From 58777807bc46afbace8bd69887ed989603f31c23 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 12 Nov 2018 20:10:46 -0800 Subject: [PATCH 01/75] Initial commit Message receiving works, sending sort of works --- MessagesBridge.xcodeproj/project.pbxproj | 420 +++++++++++ MessagesBridge/AppDelegate.h | 15 + MessagesBridge/AppDelegate.m | 33 + .../AppIcon.appiconset/Contents.json | 58 ++ MessagesBridge/Assets.xcassets/Contents.json | 6 + MessagesBridge/Base.lproj/MainMenu.xib | 692 ++++++++++++++++++ MessagesBridge/Bridge/MBIMBridge.h | 19 + MessagesBridge/Bridge/MBIMBridge.m | 123 ++++ .../Config Files/DebugDefaults.xcconfig | 88 +++ .../Config Files/OSXDebugDefaults.xcconfig | 5 + .../Config Files/OSXReleaseDefaults.xcconfig | 5 + .../Config Files/ReleaseDefaults.xcconfig | 36 + MessagesBridge/Info.plist | 32 + MessagesBridge/MessagesBridge.entitlements | 47 ++ .../SOAPlugInControllerProtocol.h | 16 + MessagesBridge/README.md | 8 + MessagesBridge/main.m | 13 + 17 files changed, 1616 insertions(+) create mode 100644 MessagesBridge.xcodeproj/project.pbxproj create mode 100644 MessagesBridge/AppDelegate.h create mode 100644 MessagesBridge/AppDelegate.m create mode 100644 MessagesBridge/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 MessagesBridge/Assets.xcassets/Contents.json create mode 100644 MessagesBridge/Base.lproj/MainMenu.xib create mode 100644 MessagesBridge/Bridge/MBIMBridge.h create mode 100644 MessagesBridge/Bridge/MBIMBridge.m create mode 100644 MessagesBridge/Config Files/DebugDefaults.xcconfig create mode 100644 MessagesBridge/Config Files/OSXDebugDefaults.xcconfig create mode 100644 MessagesBridge/Config Files/OSXReleaseDefaults.xcconfig create mode 100644 MessagesBridge/Config Files/ReleaseDefaults.xcconfig create mode 100644 MessagesBridge/Info.plist create mode 100644 MessagesBridge/MessagesBridge.entitlements create mode 100644 MessagesBridge/Pilfered Headers/SOAPlugInControllerProtocol.h create mode 100644 MessagesBridge/README.md create mode 100644 MessagesBridge/main.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj new file mode 100644 index 0000000..fe974af --- /dev/null +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -0,0 +1,420 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 1A0C444C219A38E100F2AC00 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C444B219A38E100F2AC00 /* AppDelegate.m */; }; + 1A0C444E219A38E200F2AC00 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A0C444D219A38E200F2AC00 /* Assets.xcassets */; }; + 1A0C4451219A38E200F2AC00 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1A0C444F219A38E200F2AC00 /* MainMenu.xib */; }; + 1A0C4454219A38E200F2AC00 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C4453219A38E200F2AC00 /* main.m */; }; + 1A0C4460219A45B400F2AC00 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C445F219A45B400F2AC00 /* Foundation.framework */; }; + 1A0C4462219A45BA00F2AC00 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4461219A45B900F2AC00 /* AppKit.framework */; }; + 1A0C4465219A45C700F2AC00 /* MessagesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4463219A45C700F2AC00 /* MessagesKit.framework */; }; + 1A0C4466219A45C700F2AC00 /* MessagesHelperKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4464219A45C700F2AC00 /* MessagesHelperKit.framework */; }; + 1A0C4468219A45D500F2AC00 /* IMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4467219A45D500F2AC00 /* IMCore.framework */; }; + 1A0C446B219A4BC300F2AC00 /* MBIMBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1A0C4447219A38E100F2AC00 /* MessagesBridge.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MessagesBridge.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1A0C444A219A38E100F2AC00 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 1A0C444B219A38E100F2AC00 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 1A0C444D219A38E200F2AC00 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 1A0C4450219A38E200F2AC00 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 1A0C4452219A38E200F2AC00 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1A0C4453219A38E200F2AC00 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 1A0C4455219A38E200F2AC00 /* MessagesBridge.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MessagesBridge.entitlements; sourceTree = ""; }; + 1A0C445D219A458400F2AC00 /* SOAPlugInControllerProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOAPlugInControllerProtocol.h; sourceTree = ""; }; + 1A0C445F219A45B400F2AC00 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 1A0C4461219A45B900F2AC00 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; + 1A0C4463219A45C700F2AC00 /* MessagesKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessagesKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/MessagesKit.framework; sourceTree = DEVELOPER_DIR; }; + 1A0C4464219A45C700F2AC00 /* MessagesHelperKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessagesHelperKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/MessagesHelperKit.framework; sourceTree = DEVELOPER_DIR; }; + 1A0C4467219A45D500F2AC00 /* IMCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IMCore.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/IMCore.framework; sourceTree = DEVELOPER_DIR; }; + 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridge.h; sourceTree = ""; }; + 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridge.m; sourceTree = ""; }; + 1A33B43A219A5ACD0034485A /* OSXReleaseDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OSXReleaseDefaults.xcconfig; sourceTree = ""; }; + 1A33B43B219A5ACD0034485A /* DebugDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DebugDefaults.xcconfig; sourceTree = ""; }; + 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OSXDebugDefaults.xcconfig; sourceTree = ""; }; + 1A33B43D219A5ACD0034485A /* ReleaseDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseDefaults.xcconfig; sourceTree = ""; }; + 1A33B43E219A5BD80034485A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1A0C4444219A38E100F2AC00 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A0C4468219A45D500F2AC00 /* IMCore.framework in Frameworks */, + 1A0C4465219A45C700F2AC00 /* MessagesKit.framework in Frameworks */, + 1A0C4466219A45C700F2AC00 /* MessagesHelperKit.framework in Frameworks */, + 1A0C4462219A45BA00F2AC00 /* AppKit.framework in Frameworks */, + 1A0C4460219A45B400F2AC00 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1A0C443E219A38E100F2AC00 = { + isa = PBXGroup; + children = ( + 1A0C4449219A38E100F2AC00 /* MessagesBridge */, + 1A0C4448219A38E100F2AC00 /* Products */, + 1A0C445E219A45B400F2AC00 /* Frameworks */, + ); + sourceTree = ""; + }; + 1A0C4448219A38E100F2AC00 /* Products */ = { + isa = PBXGroup; + children = ( + 1A0C4447219A38E100F2AC00 /* MessagesBridge.app */, + ); + name = Products; + sourceTree = ""; + }; + 1A0C4449219A38E100F2AC00 /* MessagesBridge */ = { + isa = PBXGroup; + children = ( + 1A0C445C219A457C00F2AC00 /* Pilfered Headers */, + 1A0C444A219A38E100F2AC00 /* AppDelegate.h */, + 1A0C444B219A38E100F2AC00 /* AppDelegate.m */, + 1A0C446D219A4BCD00F2AC00 /* Bridge */, + 1A0C444D219A38E200F2AC00 /* Assets.xcassets */, + 1A0C444F219A38E200F2AC00 /* MainMenu.xib */, + 1A0C4452219A38E200F2AC00 /* Info.plist */, + 1A0C4453219A38E200F2AC00 /* main.m */, + 1A0C4455219A38E200F2AC00 /* MessagesBridge.entitlements */, + 1A33B43E219A5BD80034485A /* README.md */, + 1A33B439219A5ACD0034485A /* Config Files */, + ); + path = MessagesBridge; + sourceTree = ""; + }; + 1A0C445C219A457C00F2AC00 /* Pilfered Headers */ = { + isa = PBXGroup; + children = ( + 1A0C445D219A458400F2AC00 /* SOAPlugInControllerProtocol.h */, + ); + path = "Pilfered Headers"; + sourceTree = ""; + }; + 1A0C445E219A45B400F2AC00 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1A0C4467219A45D500F2AC00 /* IMCore.framework */, + 1A0C4464219A45C700F2AC00 /* MessagesHelperKit.framework */, + 1A0C4463219A45C700F2AC00 /* MessagesKit.framework */, + 1A0C4461219A45B900F2AC00 /* AppKit.framework */, + 1A0C445F219A45B400F2AC00 /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 1A0C446D219A4BCD00F2AC00 /* Bridge */ = { + isa = PBXGroup; + children = ( + 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */, + 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */, + ); + path = Bridge; + sourceTree = ""; + }; + 1A33B439219A5ACD0034485A /* Config Files */ = { + isa = PBXGroup; + children = ( + 1A33B43A219A5ACD0034485A /* OSXReleaseDefaults.xcconfig */, + 1A33B43B219A5ACD0034485A /* DebugDefaults.xcconfig */, + 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */, + 1A33B43D219A5ACD0034485A /* ReleaseDefaults.xcconfig */, + ); + path = "Config Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1A0C4446219A38E100F2AC00 /* MessagesBridge */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1A0C4458219A38E200F2AC00 /* Build configuration list for PBXNativeTarget "MessagesBridge" */; + buildPhases = ( + 1A0C4443219A38E100F2AC00 /* Sources */, + 1A0C4444219A38E100F2AC00 /* Frameworks */, + 1A0C4445219A38E100F2AC00 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MessagesBridge; + productName = MessagesBridge; + productReference = 1A0C4447219A38E100F2AC00 /* MessagesBridge.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 1A0C443F219A38E100F2AC00 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1100; + ORGANIZATIONNAME = "James Magahern"; + TargetAttributes = { + 1A0C4446219A38E100F2AC00 = { + CreatedOnToolsVersion = 11.0; + }; + }; + }; + buildConfigurationList = 1A0C4442219A38E100F2AC00 /* Build configuration list for PBXProject "MessagesBridge" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 1A0C443E219A38E100F2AC00; + productRefGroup = 1A0C4448219A38E100F2AC00 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1A0C4446219A38E100F2AC00 /* MessagesBridge */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1A0C4445219A38E100F2AC00 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A0C444E219A38E200F2AC00 /* Assets.xcassets in Resources */, + 1A0C4451219A38E200F2AC00 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1A0C4443219A38E100F2AC00 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1A0C4454219A38E200F2AC00 /* main.m in Sources */, + 1A0C444C219A38E100F2AC00 /* AppDelegate.m in Sources */, + 1A0C446B219A4BC300F2AC00 /* MBIMBridge.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 1A0C444F219A38E200F2AC00 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 1A0C4450219A38E200F2AC00 /* Base */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1A0C4456219A38E200F2AC00 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SYSTEM_FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", + ); + }; + name = Debug; + }; + 1A0C4457219A38E200F2AC00 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SYSTEM_FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", + ); + }; + name = Release; + }; + 1A0C4459219A38E200F2AC00 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = MessagesBridge/MessagesBridge.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; + INFOPLIST_FILE = MessagesBridge/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.buzzert.MessagesBridge; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx.internal; + SYSTEM_FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); + }; + name = Debug; + }; + 1A0C445A219A38E200F2AC00 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = MessagesBridge/MessagesBridge.entitlements; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; + INFOPLIST_FILE = MessagesBridge/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.buzzert.MessagesBridge; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = macosx.internal; + SYSTEM_FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", + ); + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1A0C4442219A38E100F2AC00 /* Build configuration list for PBXProject "MessagesBridge" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1A0C4456219A38E200F2AC00 /* Debug */, + 1A0C4457219A38E200F2AC00 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1A0C4458219A38E200F2AC00 /* Build configuration list for PBXNativeTarget "MessagesBridge" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1A0C4459219A38E200F2AC00 /* Debug */, + 1A0C445A219A38E200F2AC00 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 1A0C443F219A38E100F2AC00 /* Project object */; +} diff --git a/MessagesBridge/AppDelegate.h b/MessagesBridge/AppDelegate.h new file mode 100644 index 0000000..86ea015 --- /dev/null +++ b/MessagesBridge/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// MessagesBridge +// +// Created by James Magahern on 11/12/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +@interface AppDelegate : NSObject + + +@end + diff --git a/MessagesBridge/AppDelegate.m b/MessagesBridge/AppDelegate.m new file mode 100644 index 0000000..471e24d --- /dev/null +++ b/MessagesBridge/AppDelegate.m @@ -0,0 +1,33 @@ +// +// AppDelegate.m +// MessagesBridge +// +// Created by James Magahern on 11/12/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "AppDelegate.h" +#import "MBIMBridge.h" + +@interface AppDelegate () +@property (weak) IBOutlet NSWindow *window; +@property (nonatomic, strong) MBIMBridge *bridge; +@end + +@implementation AppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + self.bridge = [[MBIMBridge alloc] init]; + [self.bridge connect]; +} + + + + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + // Insert code here to tear down your application +} + + +@end diff --git a/MessagesBridge/Assets.xcassets/AppIcon.appiconset/Contents.json b/MessagesBridge/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2db2b1c --- /dev/null +++ b/MessagesBridge/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MessagesBridge/Assets.xcassets/Contents.json b/MessagesBridge/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/MessagesBridge/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MessagesBridge/Base.lproj/MainMenu.xib b/MessagesBridge/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..c60269e --- /dev/null +++ b/MessagesBridge/Base.lproj/MainMenu.xib @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MessagesBridge/Bridge/MBIMBridge.h b/MessagesBridge/Bridge/MBIMBridge.h new file mode 100644 index 0000000..d0fd1a3 --- /dev/null +++ b/MessagesBridge/Bridge/MBIMBridge.h @@ -0,0 +1,19 @@ +// +// MBIMBridge.h +// MessagesBridge +// +// Created by James Magahern on 11/12/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMBridge : NSObject +- (void)connect; +- (void)disconnect; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MessagesBridge/Bridge/MBIMBridge.m b/MessagesBridge/Bridge/MBIMBridge.m new file mode 100644 index 0000000..15d7cd8 --- /dev/null +++ b/MessagesBridge/Bridge/MBIMBridge.m @@ -0,0 +1,123 @@ +// +// MBIMBridge.m +// MessagesBridge +// +// Created by James Magahern on 11/12/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMBridge.h" + +#import +#import + +#import +#import + +static NSString *const MBIMBridgeToken = @"net.buzzert.MBIMBridge"; + +@implementation MBIMBridge + +- (instancetype)init +{ + self = [super init]; + if (self) { + [self registerForNotifications]; + + [sDaemonController setDelegate:self]; + [sDaemonListener addHandler:self]; + } + + return self; +} + +#pragma mark - +#pragma mark Connection + +- (void)connect +{ + if (![sDaemonController hasListenerForID: MBIMBridgeToken]) { + if (![sDaemonController addListenerID:MBIMBridgeToken capabilities:(kFZListenerCapFileTransfers | kFZListenerCapManageStatus | kFZListenerCapChats | kFZListenerCapMessageHistory | kFZListenerCapIDQueries | kFZListenerCapSendMessages)]) { + NSLog(@"Failed to connect to imagent"); + } + } +} + +- (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] 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!"); + + // Automated reply + IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; + IMHandle *handle = [[iMessageAccount arrayOfAllIMHandles] firstObject]; + + /* this caused a crazy loop for some reason!! */ + + /* + NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:@"This is a test automated reply. Please ignore."]; + IMMessage *reply = [IMMessage fromMeIMHandle:handle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; + + IMChat *chat = [notification object]; + [chat sendMessage:reply]; + */ +} + +- (void)_chatRegistryDidLoad:(NSNotification *)notification +{ + NSLog(@"Loaded chat registry. %lu existing chats", (unsigned long)[sChatRegistry numberOfExistingChats]); +} + +#pragma mark - +#pragma mark Daemon lifecycle + +- (void)daemonControllerWillConnect +{ + NSLog(@"About to connect to daemon"); +} + +- (void)daemonControllerDidConnect +{ + NSLog(@"Did connect to daemon"); + + IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; + if (iMessageAccount) { + NSLog(@"iMessage account connected: %@", iMessageAccount); + } else { + NSLog(@"Was not able to connect to iMessage account"); + } +} + +- (void)daemonControllerDidDisconnect +{ + NSLog(@"Did disconnect from daemon"); +} + +- (void)daemonConnectionLost +{ + NSLog(@"Connection lost to daemon"); +} + +@end diff --git a/MessagesBridge/Config Files/DebugDefaults.xcconfig b/MessagesBridge/Config Files/DebugDefaults.xcconfig new file mode 100644 index 0000000..a0dda08 --- /dev/null +++ b/MessagesBridge/Config Files/DebugDefaults.xcconfig @@ -0,0 +1,88 @@ +// +// Many defines in this file are based on the selected SDK; it does not set an SDK. +// NOTE: This is inherited by ALL projects and all types, be careful in here +// + +// ####################### HEADER SEARCH PATHS ######################## + +HEADER_SEARCH_PATHS = $(SDK_DIR)/usr/local/include $(SDK_DIR)/usr/include + +// ##################### FRAMEWORK SEARCH PATHS ####################### + +ALWAYS_SEARCH_USER_PATHS = NO +FRAMEWORK_SEARCH_PATHS[sdk=macosx*] = $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks $(SDK_DIR)/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks +FRAMEWORK_SEARCH_PATHS[sdk=embedded*] = $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks +FRAMEWORK_SEARCH_PATHS[sdk=embeddedsimulator*] = $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks + +// ###################### LIBRARY SEARCH PATHS ######################## + +LIBRARY_SEARCH_PATHS[sdk=embedded*] = $(SDK_DIR)/usr/local/lib $(SDK_DIR)/usr/lib +LIBRARY_SEARCH_PATHS[sdk=embeddedsimulator*] = $(SDK_DIR)/usr/local/lib $(SDK_DIR)/usr/lib + +// ############################# FLAGS ################################ + +OTHER_CFLAGS = -Wshadow -DIM_DEBUG -D_FORTIFY_SOURCE=2 -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations +OTHER_CFLAGS[sdk=embedded*] = -Wshadow -DIM_DEBUG -D_FORTIFY_SOURCE=2 -DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations +OTHER_CFLAGS[sdk=embeddedsimulator*] = -Wshadow -DIM_DEBUG -D_FORTIFY_SOURCE=2 -DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations + +WARNING_CFLAGS = -Wno-error=deprecated-declarations + +// ######################### ARCHITECTURES ########################### + +ARCHS[sdk=macosx*] = $(ARCHS_STANDARD_64_BIT) + +VALID_ARCHS[sdk=macosx*] = x86_64 +VALID_ARCHS[sdk=embeddedsimulator*] = i386 x86_64 + +// ######################### CONFIGURATION ########################### + +CODE_SIGN_IDENTITY = - + +DYLIB_CURRENT_VERSION = 800 +DYLIB_COMPATIBILITY_VERSION = 1 + +CLANG_WARN_CONSTANT_CONVERSION = YES; +CLANG_WARN_ENUM_CONVERSION = YES; +CLANG_WARN_INT_CONVERSION = YES; +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + +GCC_WARN_UNINITIALIZED_AUTOS = YES; +GCC_WARN_UNUSED_VARIABLE = YES; + +ONLY_ACTIVE_ARCH = YES + +TARGETED_DEVICE_FAMILY = 1,2 +TARGETED_DEVICE_FAMILY[sdk=watch*] = 4 + +// ######################## INSTALLATION ############################# + +SKIP_INSTALL = NO + +// ########################### CLANG ################################# + +CLANG_MODULES_AUTOLINK = NO +RUN_CLANG_STATIC_ANALYZER = YES + +// ######################### COMPILER ################################ + +GCC_VERSION = com.apple.compilers.llvm.clang.1_0; +GCC_WARN_ABOUT_RETURN_TYPE = YES + +// ######################### LANGUAGE MISC ########################### + +GCC_C_LANGUAGE_STANDARD = c99 + +// ########################## DEBUGGING ############################## + +GCC_OPTIMIZATION_LEVEL = 0 + +// ############################ MISC ################################# + +VERSIONING_SYSTEM = apple-generic + +// ############################ USER OVERRIDE ################################# + +// Override global settings in a git ignored UserDebug.xcconfig file at the repo root. +// I seem to have to restart Xcode if I add/remove this file. +#include? "UserDebug.xcconfig" + diff --git a/MessagesBridge/Config Files/OSXDebugDefaults.xcconfig b/MessagesBridge/Config Files/OSXDebugDefaults.xcconfig new file mode 100644 index 0000000..5630ba2 --- /dev/null +++ b/MessagesBridge/Config Files/OSXDebugDefaults.xcconfig @@ -0,0 +1,5 @@ +// +// To be used by OSX targets +// + +SDKROOT = macosx.internal \ No newline at end of file diff --git a/MessagesBridge/Config Files/OSXReleaseDefaults.xcconfig b/MessagesBridge/Config Files/OSXReleaseDefaults.xcconfig new file mode 100644 index 0000000..695d65e --- /dev/null +++ b/MessagesBridge/Config Files/OSXReleaseDefaults.xcconfig @@ -0,0 +1,5 @@ +#include "OSXDebugDefaults.xcconfig" + +// +// To be used by OSX targets +// diff --git a/MessagesBridge/Config Files/ReleaseDefaults.xcconfig b/MessagesBridge/Config Files/ReleaseDefaults.xcconfig new file mode 100644 index 0000000..be6e3e4 --- /dev/null +++ b/MessagesBridge/Config Files/ReleaseDefaults.xcconfig @@ -0,0 +1,36 @@ +#include "DebugDefaults.xcconfig" + +// #################### INSTALLATION FLAGS ##################### + +SKIP_INSTALL = NO + +// ####################### DEBUG FLAGS ######################### + +STRIP_INSTALLED_PRODUCT = YES +STRIP_STYLE = non-global; + +COPY_PHASE_STRIP = YES + +GCC_OPTIMIZATION_LEVEL = s +GCC_GENERATE_DEBUGGING_SYMBOLS = YES +GCC_SYMBOLS_PRIVATE_EXTERN = YES + +ONLY_ACTIVE_ARCH = NO + +DEBUG_INFORMATION_FORMAT = dwarf-with-dsym + +// ######################### C FLAGS ########################### + +OTHER_CFLAGS = -Wshadow -D_FORTIFY_SOURCE=2 -D__IMCORE_INTERNAL__ +OTHER_CFLAGS[sdk=embedded*] = -Wshadow -D_FORTIFY_SOURCE=2 -DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations +OTHER_CFLAGS[sdk=embeddedsimulator*] = -Wshadow -D_FORTIFY_SOURCE=2 -DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations + +// ########################## CLANG ############################ + +RUN_CLANG_STATIC_ANALYZER = NO + +// ####################### Order File ########################## + +ORDER_FILE = Order Files/$(PROJECT_NAME).order + +GCC_PREPROCESSOR_DEFINITIONS = NDEBUG diff --git a/MessagesBridge/Info.plist b/MessagesBridge/Info.plist new file mode 100644 index 0000000..0d13e4a --- /dev/null +++ b/MessagesBridge/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2018 James Magahern. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/MessagesBridge/MessagesBridge.entitlements b/MessagesBridge/MessagesBridge.entitlements new file mode 100644 index 0000000..d61bb27 --- /dev/null +++ b/MessagesBridge/MessagesBridge.entitlements @@ -0,0 +1,47 @@ + + + + + com.apple.private.corespotlight.search.internal + + com.apple.private.corespotlight.internal + + com.apple.CommCenter.fine-grained + + spi + + com.apple.accounts.inactive.fullaccess + + com.apple.imagent + + com.apple.private.accounts.allaccounts + + com.apple.private.aps-connection-initiate + + com.apple.ess + com.apple.madrid + + com.apple.private.communicationsfilter + + com.apple.private.ids.idquery-cache + + com.apple.private.ids.remoteurlconnection + + com.apple.private.imcore.imdpersistence.database-access + + com.apple.private.tcc.allow + + kTCCServiceAddressBook + + keychain-access-groups + + appleaccount + InternetAccounts + IMCore + ichat + apple + + com.apple.logd.admin + + + diff --git a/MessagesBridge/Pilfered Headers/SOAPlugInControllerProtocol.h b/MessagesBridge/Pilfered Headers/SOAPlugInControllerProtocol.h new file mode 100644 index 0000000..90d4982 --- /dev/null +++ b/MessagesBridge/Pilfered Headers/SOAPlugInControllerProtocol.h @@ -0,0 +1,16 @@ +// +// MessagesHelperProtocol.h +// MessagesHelpers +// +// Created by Jeremy Payne on 7/10/12. +// Copyright (c) 2012 Apple. All rights reserved. +// + +#import + +@protocol SOAPlugInControllerProtocol + +- (oneway void)connectPlugIn:(NSString *)plugInName withConnectionHandler:(void (^)(NSXPCListenerEndpoint *))replyHandler; +- (void)reconnect; + +@end diff --git a/MessagesBridge/README.md b/MessagesBridge/README.md new file mode 100644 index 0000000..8ea8fd8 --- /dev/null +++ b/MessagesBridge/README.md @@ -0,0 +1,8 @@ +# Entitlements + +You might to enable this default to use private entitlements +``` +sudo defaults write /Library/Preferences/com.apple.security.coderequirements Entitlements -string always +``` + +Maybe a better thing to do is to DYLD_PRELOAD `imagent` and swizzle `IMDAuditTokenTaskHasEntitlement` to always return YES. diff --git a/MessagesBridge/main.m b/MessagesBridge/main.m new file mode 100644 index 0000000..7ff9331 --- /dev/null +++ b/MessagesBridge/main.m @@ -0,0 +1,13 @@ +// +// main.m +// MessagesBridge +// +// Created by James Magahern on 11/12/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +int main(int argc, const char * argv[]) { + return NSApplicationMain(argc, argv); +} From 2d0fd5b290d32cbbdcace5cef61d140720fdeb97 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 12 Nov 2018 22:11:36 -0800 Subject: [PATCH 02/75] Moved stuff around and you can see convos, messages, and send messages! --- .gitmodules | 3 + .../DebugDefaults.xcconfig | 0 .../OSXDebugDefaults.xcconfig | 0 .../OSXReleaseDefaults.xcconfig | 0 .../ReleaseDefaults.xcconfig | 0 GCDWebServer | 1 + MessagesBridge.xcodeproj/project.pbxproj | 320 +++++--- .../xcschemes/kordophoned.xcscheme | 91 +++ MessagesBridge/AppDelegate.h | 15 - MessagesBridge/AppDelegate.m | 33 - .../AppIcon.appiconset/Contents.json | 58 -- MessagesBridge/Assets.xcassets/Contents.json | 6 - MessagesBridge/Base.lproj/MainMenu.xib | 692 ------------------ MessagesBridge/Bridge/MBIMBridge.m | 123 ---- MessagesBridge/Info.plist | 32 - MessagesBridge/main.m | 13 - .../SOAPlugInControllerProtocol.h | 0 MessagesBridge/README.md => README.md | 0 .../Bridge/MBIMBridge.h | 4 + kordophone/Bridge/MBIMBridge.m | 271 +++++++ .../kordophone.entitlements | 0 kordophone/main.m | 24 + 22 files changed, 604 insertions(+), 1082 deletions(-) create mode 100644 .gitmodules rename {MessagesBridge/Config Files => Config Files}/DebugDefaults.xcconfig (100%) rename {MessagesBridge/Config Files => Config Files}/OSXDebugDefaults.xcconfig (100%) rename {MessagesBridge/Config Files => Config Files}/OSXReleaseDefaults.xcconfig (100%) rename {MessagesBridge/Config Files => Config Files}/ReleaseDefaults.xcconfig (100%) create mode 160000 GCDWebServer create mode 100644 MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme delete mode 100644 MessagesBridge/AppDelegate.h delete mode 100644 MessagesBridge/AppDelegate.m delete mode 100644 MessagesBridge/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 MessagesBridge/Assets.xcassets/Contents.json delete mode 100644 MessagesBridge/Base.lproj/MainMenu.xib delete mode 100644 MessagesBridge/Bridge/MBIMBridge.m delete mode 100644 MessagesBridge/Info.plist delete mode 100644 MessagesBridge/main.m rename {MessagesBridge/Pilfered Headers => Pilfered Headers}/SOAPlugInControllerProtocol.h (100%) rename MessagesBridge/README.md => README.md (100%) rename {MessagesBridge => kordophone}/Bridge/MBIMBridge.h (81%) create mode 100644 kordophone/Bridge/MBIMBridge.m rename MessagesBridge/MessagesBridge.entitlements => kordophone/kordophone.entitlements (100%) create mode 100644 kordophone/main.m diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2d85876 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "GCDWebServer"] + path = GCDWebServer + url = https://github.com/swisspol/GCDWebServer.git diff --git a/MessagesBridge/Config Files/DebugDefaults.xcconfig b/Config Files/DebugDefaults.xcconfig similarity index 100% rename from MessagesBridge/Config Files/DebugDefaults.xcconfig rename to Config Files/DebugDefaults.xcconfig diff --git a/MessagesBridge/Config Files/OSXDebugDefaults.xcconfig b/Config Files/OSXDebugDefaults.xcconfig similarity index 100% rename from MessagesBridge/Config Files/OSXDebugDefaults.xcconfig rename to Config Files/OSXDebugDefaults.xcconfig diff --git a/MessagesBridge/Config Files/OSXReleaseDefaults.xcconfig b/Config Files/OSXReleaseDefaults.xcconfig similarity index 100% rename from MessagesBridge/Config Files/OSXReleaseDefaults.xcconfig rename to Config Files/OSXReleaseDefaults.xcconfig diff --git a/MessagesBridge/Config Files/ReleaseDefaults.xcconfig b/Config Files/ReleaseDefaults.xcconfig similarity index 100% rename from MessagesBridge/Config Files/ReleaseDefaults.xcconfig rename to Config Files/ReleaseDefaults.xcconfig diff --git a/GCDWebServer b/GCDWebServer new file mode 160000 index 0000000..7df4653 --- /dev/null +++ b/GCDWebServer @@ -0,0 +1 @@ +Subproject commit 7df465336eb3e975fdc498e2ac8a845f3ae56a34 diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index fe974af..dc9c6ee 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -7,27 +7,88 @@ objects = { /* Begin PBXBuildFile section */ - 1A0C444C219A38E100F2AC00 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C444B219A38E100F2AC00 /* AppDelegate.m */; }; - 1A0C444E219A38E200F2AC00 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A0C444D219A38E200F2AC00 /* Assets.xcassets */; }; - 1A0C4451219A38E200F2AC00 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1A0C444F219A38E200F2AC00 /* MainMenu.xib */; }; - 1A0C4454219A38E200F2AC00 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C4453219A38E200F2AC00 /* main.m */; }; - 1A0C4460219A45B400F2AC00 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C445F219A45B400F2AC00 /* Foundation.framework */; }; - 1A0C4462219A45BA00F2AC00 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4461219A45B900F2AC00 /* AppKit.framework */; }; - 1A0C4465219A45C700F2AC00 /* MessagesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4463219A45C700F2AC00 /* MessagesKit.framework */; }; - 1A0C4466219A45C700F2AC00 /* MessagesHelperKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4464219A45C700F2AC00 /* MessagesHelperKit.framework */; }; - 1A0C4468219A45D500F2AC00 /* IMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4467219A45D500F2AC00 /* IMCore.framework */; }; - 1A0C446B219A4BC300F2AC00 /* MBIMBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C446A219A4BC300F2AC00 /* MBIMBridge.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 */; }; + CDF6233D219A8AF700690038 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C445F219A45B400F2AC00 /* Foundation.framework */; }; + CDF6233E219A8AFC00690038 /* IMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4467219A45D500F2AC00 /* IMCore.framework */; }; + CDF6233F219A8B0100690038 /* GCDWebServers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDF62324219A869000690038 /* GCDWebServers.framework */; }; + CDF62343219A9BE200690038 /* ContactsFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDF62342219A9BE200690038 /* ContactsFoundation.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + CDF6231D219A869000690038 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8DD76FB20486AB0100D96B5E; + remoteInfo = "GCDWebServer (Mac)"; + }; + CDF6231F219A869000690038 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = E2DDD1F61BE69EE4002CE867; + remoteInfo = "GCDWebServer (iOS)"; + }; + CDF62321219A869000690038 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = E2DDD1C71BE698A8002CE867; + remoteInfo = "GCDWebServer (tvOS)"; + }; + CDF62323219A869000690038 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = CEE28CD11AE004D800F4023C; + remoteInfo = "GCDWebServers (Mac)"; + }; + CDF62325219A869000690038 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = CEE28CEF1AE0051F00F4023C; + remoteInfo = "GCDWebServers (iOS)"; + }; + CDF62327219A869000690038 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = E2DDD18B1BE69404002CE867; + remoteInfo = "GCDWebServers (tvOS)"; + }; + CDF62329219A869000690038 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = E24039251BA09207000B7089; + remoteInfo = "Tests (Mac)"; + }; + CDF6233B219A8A6600690038 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = CEE28CD01AE004D800F4023C; + remoteInfo = "GCDWebServers (Mac)"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + CDF62330219A895D00690038 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ - 1A0C4447219A38E100F2AC00 /* MessagesBridge.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MessagesBridge.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A0C444A219A38E100F2AC00 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 1A0C444B219A38E100F2AC00 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 1A0C444D219A38E200F2AC00 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 1A0C4450219A38E200F2AC00 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 1A0C4452219A38E200F2AC00 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1A0C4453219A38E200F2AC00 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 1A0C4455219A38E200F2AC00 /* MessagesBridge.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MessagesBridge.entitlements; sourceTree = ""; }; + 1A0C4455219A38E200F2AC00 /* kordophone.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = kordophone.entitlements; sourceTree = ""; }; 1A0C445D219A458400F2AC00 /* SOAPlugInControllerProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOAPlugInControllerProtocol.h; sourceTree = ""; }; 1A0C445F219A45B400F2AC00 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 1A0C4461219A45B900F2AC00 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; @@ -41,18 +102,22 @@ 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OSXDebugDefaults.xcconfig; sourceTree = ""; }; 1A33B43D219A5ACD0034485A /* ReleaseDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseDefaults.xcconfig; sourceTree = ""; }; 1A33B43E219A5BD80034485A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + CDF62312219A869000690038 /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = GCDWebServer/GCDWebServer.xcodeproj; 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; }; + CDF62342219A9BE200690038 /* ContactsFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ContactsFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/ContactsFoundation.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 1A0C4444219A38E100F2AC00 /* Frameworks */ = { + CDF6232F219A895D00690038 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1A0C4468219A45D500F2AC00 /* IMCore.framework in Frameworks */, - 1A0C4465219A45C700F2AC00 /* MessagesKit.framework in Frameworks */, - 1A0C4466219A45C700F2AC00 /* MessagesHelperKit.framework in Frameworks */, - 1A0C4462219A45BA00F2AC00 /* AppKit.framework in Frameworks */, - 1A0C4460219A45B400F2AC00 /* Foundation.framework in Frameworks */, + CDF62343219A9BE200690038 /* ContactsFoundation.framework in Frameworks */, + CDF6233F219A8B0100690038 /* GCDWebServers.framework in Frameworks */, + CDF6233E219A8AFC00690038 /* IMCore.framework in Frameworks */, + CDF6233D219A8AF700690038 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -62,7 +127,11 @@ 1A0C443E219A38E100F2AC00 = { isa = PBXGroup; children = ( - 1A0C4449219A38E100F2AC00 /* MessagesBridge */, + 1A33B43E219A5BD80034485A /* README.md */, + CDF62312219A869000690038 /* GCDWebServer.xcodeproj */, + CDF62333219A895D00690038 /* kordophone */, + 1A33B439219A5ACD0034485A /* Config Files */, + 1A0C445C219A457C00F2AC00 /* Pilfered Headers */, 1A0C4448219A38E100F2AC00 /* Products */, 1A0C445E219A45B400F2AC00 /* Frameworks */, ); @@ -71,29 +140,11 @@ 1A0C4448219A38E100F2AC00 /* Products */ = { isa = PBXGroup; children = ( - 1A0C4447219A38E100F2AC00 /* MessagesBridge.app */, + CDF62332219A895D00690038 /* kordophoned */, ); name = Products; sourceTree = ""; }; - 1A0C4449219A38E100F2AC00 /* MessagesBridge */ = { - isa = PBXGroup; - children = ( - 1A0C445C219A457C00F2AC00 /* Pilfered Headers */, - 1A0C444A219A38E100F2AC00 /* AppDelegate.h */, - 1A0C444B219A38E100F2AC00 /* AppDelegate.m */, - 1A0C446D219A4BCD00F2AC00 /* Bridge */, - 1A0C444D219A38E200F2AC00 /* Assets.xcassets */, - 1A0C444F219A38E200F2AC00 /* MainMenu.xib */, - 1A0C4452219A38E200F2AC00 /* Info.plist */, - 1A0C4453219A38E200F2AC00 /* main.m */, - 1A0C4455219A38E200F2AC00 /* MessagesBridge.entitlements */, - 1A33B43E219A5BD80034485A /* README.md */, - 1A33B439219A5ACD0034485A /* Config Files */, - ); - path = MessagesBridge; - sourceTree = ""; - }; 1A0C445C219A457C00F2AC00 /* Pilfered Headers */ = { isa = PBXGroup; children = ( @@ -105,6 +156,8 @@ 1A0C445E219A45B400F2AC00 /* Frameworks */ = { isa = PBXGroup; children = ( + CDF62342219A9BE200690038 /* ContactsFoundation.framework */, + CDF62340219A9AAA00690038 /* EmailFoundation.framework */, 1A0C4467219A45D500F2AC00 /* IMCore.framework */, 1A0C4464219A45C700F2AC00 /* MessagesHelperKit.framework */, 1A0C4463219A45C700F2AC00 /* MessagesKit.framework */, @@ -134,25 +187,50 @@ path = "Config Files"; sourceTree = ""; }; + CDF62313219A869000690038 /* Products */ = { + isa = PBXGroup; + children = ( + CDF6231E219A869000690038 /* GCDWebServer */, + CDF62320219A869000690038 /* GCDWebServer.app */, + CDF62322219A869000690038 /* GCDWebServer.app */, + CDF62324219A869000690038 /* GCDWebServers.framework */, + CDF62326219A869000690038 /* GCDWebServers.framework */, + CDF62328219A869000690038 /* GCDWebServers.framework */, + CDF6232A219A869000690038 /* Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + CDF62333219A895D00690038 /* kordophone */ = { + isa = PBXGroup; + children = ( + 1A0C446D219A4BCD00F2AC00 /* Bridge */, + 1A0C4455219A38E200F2AC00 /* kordophone.entitlements */, + CDF62334219A895D00690038 /* main.m */, + ); + path = kordophone; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 1A0C4446219A38E100F2AC00 /* MessagesBridge */ = { + CDF62331219A895D00690038 /* kordophoned */ = { isa = PBXNativeTarget; - buildConfigurationList = 1A0C4458219A38E200F2AC00 /* Build configuration list for PBXNativeTarget "MessagesBridge" */; + buildConfigurationList = CDF62336219A895D00690038 /* Build configuration list for PBXNativeTarget "kordophoned" */; buildPhases = ( - 1A0C4443219A38E100F2AC00 /* Sources */, - 1A0C4444219A38E100F2AC00 /* Frameworks */, - 1A0C4445219A38E100F2AC00 /* Resources */, + CDF6232E219A895D00690038 /* Sources */, + CDF6232F219A895D00690038 /* Frameworks */, + CDF62330219A895D00690038 /* CopyFiles */, ); buildRules = ( ); dependencies = ( + CDF6233C219A8A6600690038 /* PBXTargetDependency */, ); - name = MessagesBridge; - productName = MessagesBridge; - productReference = 1A0C4447219A38E100F2AC00 /* MessagesBridge.app */; - productType = "com.apple.product-type.application"; + name = kordophoned; + productName = kordophone; + productReference = CDF62332219A895D00690038 /* kordophoned */; + productType = "com.apple.product-type.tool"; }; /* End PBXNativeTarget section */ @@ -163,7 +241,7 @@ LastUpgradeCheck = 1100; ORGANIZATIONNAME = "James Magahern"; TargetAttributes = { - 1A0C4446219A38E100F2AC00 = { + CDF62331219A895D00690038 = { CreatedOnToolsVersion = 11.0; }; }; @@ -179,48 +257,91 @@ mainGroup = 1A0C443E219A38E100F2AC00; productRefGroup = 1A0C4448219A38E100F2AC00 /* Products */; projectDirPath = ""; + projectReferences = ( + { + ProductGroup = CDF62313219A869000690038 /* Products */; + ProjectRef = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; + }, + ); projectRoot = ""; targets = ( - 1A0C4446219A38E100F2AC00 /* MessagesBridge */, + CDF62331219A895D00690038 /* kordophoned */, ); }; /* End PBXProject section */ -/* Begin PBXResourcesBuildPhase section */ - 1A0C4445219A38E100F2AC00 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A0C444E219A38E200F2AC00 /* Assets.xcassets in Resources */, - 1A0C4451219A38E200F2AC00 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; +/* Begin PBXReferenceProxy section */ + CDF6231E219A869000690038 /* GCDWebServer */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.executable"; + path = GCDWebServer; + remoteRef = CDF6231D219A869000690038 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXResourcesBuildPhase section */ + CDF62320219A869000690038 /* GCDWebServer.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = GCDWebServer.app; + remoteRef = CDF6231F219A869000690038 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + CDF62322219A869000690038 /* GCDWebServer.app */ = { + isa = PBXReferenceProxy; + fileType = wrapper.application; + path = GCDWebServer.app; + remoteRef = CDF62321219A869000690038 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + CDF62324219A869000690038 /* GCDWebServers.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = GCDWebServers.framework; + remoteRef = CDF62323219A869000690038 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + CDF62326219A869000690038 /* GCDWebServers.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = GCDWebServers.framework; + remoteRef = CDF62325219A869000690038 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + CDF62328219A869000690038 /* GCDWebServers.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = GCDWebServers.framework; + remoteRef = CDF62327219A869000690038 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + CDF6232A219A869000690038 /* Tests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = Tests.xctest; + remoteRef = CDF62329219A869000690038 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ /* Begin PBXSourcesBuildPhase section */ - 1A0C4443219A38E100F2AC00 /* Sources */ = { + CDF6232E219A895D00690038 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1A0C4454219A38E200F2AC00 /* main.m in Sources */, - 1A0C444C219A38E100F2AC00 /* AppDelegate.m in Sources */, - 1A0C446B219A4BC300F2AC00 /* MBIMBridge.m in Sources */, + CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, + CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, + CDF62335219A895D00690038 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXVariantGroup section */ - 1A0C444F219A38E200F2AC00 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 1A0C4450219A38E200F2AC00 /* Base */, - ); - name = MainMenu.xib; - sourceTree = ""; +/* Begin PBXTargetDependency section */ + CDF6233C219A8A6600690038 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "GCDWebServers (Mac)"; + targetProxy = CDF6233B219A8A6600690038 /* PBXContainerItemProxy */; }; -/* End PBXVariantGroup section */ +/* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 1A0C4456219A38E200F2AC00 /* Debug */ = { @@ -342,24 +463,13 @@ }; name = Release; }; - 1A0C4459219A38E200F2AC00 /* Debug */ = { + CDF62337219A895D00690038 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = MessagesBridge/MessagesBridge.entitlements; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = MessagesBridge/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = net.buzzert.MessagesBridge; + CLANG_ENABLE_MODULES = NO; + CODE_SIGN_ENTITLEMENTS = kordophone/kordophone.entitlements; + CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx.internal; SYSTEM_FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -368,23 +478,13 @@ }; name = Debug; }; - 1A0C445A219A38E200F2AC00 /* Release */ = { + CDF62338219A895D00690038 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = MessagesBridge/MessagesBridge.entitlements; - CODE_SIGN_IDENTITY = "-"; - CODE_SIGN_STYLE = Manual; - COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = ""; - INFOPLIST_FILE = MessagesBridge/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = net.buzzert.MessagesBridge; + CLANG_ENABLE_MODULES = NO; + CODE_SIGN_ENTITLEMENTS = kordophone/kordophone.entitlements; + CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = macosx.internal; SYSTEM_FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -405,11 +505,11 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 1A0C4458219A38E200F2AC00 /* Build configuration list for PBXNativeTarget "MessagesBridge" */ = { + CDF62336219A895D00690038 /* Build configuration list for PBXNativeTarget "kordophoned" */ = { isa = XCConfigurationList; buildConfigurations = ( - 1A0C4459219A38E200F2AC00 /* Debug */, - 1A0C445A219A38E200F2AC00 /* Release */, + CDF62337219A895D00690038 /* Debug */, + CDF62338219A895D00690038 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme new file mode 100644 index 0000000..c103900 --- /dev/null +++ b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MessagesBridge/AppDelegate.h b/MessagesBridge/AppDelegate.h deleted file mode 100644 index 86ea015..0000000 --- a/MessagesBridge/AppDelegate.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// AppDelegate.h -// MessagesBridge -// -// Created by James Magahern on 11/12/18. -// Copyright © 2018 James Magahern. All rights reserved. -// - -#import - -@interface AppDelegate : NSObject - - -@end - diff --git a/MessagesBridge/AppDelegate.m b/MessagesBridge/AppDelegate.m deleted file mode 100644 index 471e24d..0000000 --- a/MessagesBridge/AppDelegate.m +++ /dev/null @@ -1,33 +0,0 @@ -// -// AppDelegate.m -// MessagesBridge -// -// Created by James Magahern on 11/12/18. -// Copyright © 2018 James Magahern. All rights reserved. -// - -#import "AppDelegate.h" -#import "MBIMBridge.h" - -@interface AppDelegate () -@property (weak) IBOutlet NSWindow *window; -@property (nonatomic, strong) MBIMBridge *bridge; -@end - -@implementation AppDelegate - -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification -{ - self.bridge = [[MBIMBridge alloc] init]; - [self.bridge connect]; -} - - - - -- (void)applicationWillTerminate:(NSNotification *)aNotification { - // Insert code here to tear down your application -} - - -@end diff --git a/MessagesBridge/Assets.xcassets/AppIcon.appiconset/Contents.json b/MessagesBridge/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2db2b1c..0000000 --- a/MessagesBridge/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "images" : [ - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "16x16", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "32x32", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "128x128", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "256x256", - "scale" : "2x" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "1x" - }, - { - "idiom" : "mac", - "size" : "512x512", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/MessagesBridge/Assets.xcassets/Contents.json b/MessagesBridge/Assets.xcassets/Contents.json deleted file mode 100644 index da4a164..0000000 --- a/MessagesBridge/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/MessagesBridge/Base.lproj/MainMenu.xib b/MessagesBridge/Base.lproj/MainMenu.xib deleted file mode 100644 index c60269e..0000000 --- a/MessagesBridge/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MessagesBridge/Bridge/MBIMBridge.m b/MessagesBridge/Bridge/MBIMBridge.m deleted file mode 100644 index 15d7cd8..0000000 --- a/MessagesBridge/Bridge/MBIMBridge.m +++ /dev/null @@ -1,123 +0,0 @@ -// -// MBIMBridge.m -// MessagesBridge -// -// Created by James Magahern on 11/12/18. -// Copyright © 2018 James Magahern. All rights reserved. -// - -#import "MBIMBridge.h" - -#import -#import - -#import -#import - -static NSString *const MBIMBridgeToken = @"net.buzzert.MBIMBridge"; - -@implementation MBIMBridge - -- (instancetype)init -{ - self = [super init]; - if (self) { - [self registerForNotifications]; - - [sDaemonController setDelegate:self]; - [sDaemonListener addHandler:self]; - } - - return self; -} - -#pragma mark - -#pragma mark Connection - -- (void)connect -{ - if (![sDaemonController hasListenerForID: MBIMBridgeToken]) { - if (![sDaemonController addListenerID:MBIMBridgeToken capabilities:(kFZListenerCapFileTransfers | kFZListenerCapManageStatus | kFZListenerCapChats | kFZListenerCapMessageHistory | kFZListenerCapIDQueries | kFZListenerCapSendMessages)]) { - NSLog(@"Failed to connect to imagent"); - } - } -} - -- (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] 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!"); - - // Automated reply - IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; - IMHandle *handle = [[iMessageAccount arrayOfAllIMHandles] firstObject]; - - /* this caused a crazy loop for some reason!! */ - - /* - NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:@"This is a test automated reply. Please ignore."]; - IMMessage *reply = [IMMessage fromMeIMHandle:handle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; - - IMChat *chat = [notification object]; - [chat sendMessage:reply]; - */ -} - -- (void)_chatRegistryDidLoad:(NSNotification *)notification -{ - NSLog(@"Loaded chat registry. %lu existing chats", (unsigned long)[sChatRegistry numberOfExistingChats]); -} - -#pragma mark - -#pragma mark Daemon lifecycle - -- (void)daemonControllerWillConnect -{ - NSLog(@"About to connect to daemon"); -} - -- (void)daemonControllerDidConnect -{ - NSLog(@"Did connect to daemon"); - - IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; - if (iMessageAccount) { - NSLog(@"iMessage account connected: %@", iMessageAccount); - } else { - NSLog(@"Was not able to connect to iMessage account"); - } -} - -- (void)daemonControllerDidDisconnect -{ - NSLog(@"Did disconnect from daemon"); -} - -- (void)daemonConnectionLost -{ - NSLog(@"Connection lost to daemon"); -} - -@end diff --git a/MessagesBridge/Info.plist b/MessagesBridge/Info.plist deleted file mode 100644 index 0d13e4a..0000000 --- a/MessagesBridge/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - Copyright © 2018 James Magahern. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/MessagesBridge/main.m b/MessagesBridge/main.m deleted file mode 100644 index 7ff9331..0000000 --- a/MessagesBridge/main.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// main.m -// MessagesBridge -// -// Created by James Magahern on 11/12/18. -// Copyright © 2018 James Magahern. All rights reserved. -// - -#import - -int main(int argc, const char * argv[]) { - return NSApplicationMain(argc, argv); -} diff --git a/MessagesBridge/Pilfered Headers/SOAPlugInControllerProtocol.h b/Pilfered Headers/SOAPlugInControllerProtocol.h similarity index 100% rename from MessagesBridge/Pilfered Headers/SOAPlugInControllerProtocol.h rename to Pilfered Headers/SOAPlugInControllerProtocol.h diff --git a/MessagesBridge/README.md b/README.md similarity index 100% rename from MessagesBridge/README.md rename to README.md diff --git a/MessagesBridge/Bridge/MBIMBridge.h b/kordophone/Bridge/MBIMBridge.h similarity index 81% rename from MessagesBridge/Bridge/MBIMBridge.h rename to kordophone/Bridge/MBIMBridge.h index d0fd1a3..679a960 100644 --- a/MessagesBridge/Bridge/MBIMBridge.h +++ b/kordophone/Bridge/MBIMBridge.h @@ -11,6 +11,10 @@ NS_ASSUME_NONNULL_BEGIN @interface MBIMBridge : NSObject ++ (instancetype)sharedInstance; + +- (instancetype)init NS_UNAVAILABLE; + - (void)connect; - (void)disconnect; diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m new file mode 100644 index 0000000..75d5d28 --- /dev/null +++ b/kordophone/Bridge/MBIMBridge.m @@ -0,0 +1,271 @@ +// +// MBIMBridge.m +// MessagesBridge +// +// Created by James Magahern on 11/12/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMBridge.h" + +#import + +#import +#import + +#import +#import + +static NSString *const MBIMBridgeToken = @"net.buzzert.MBIMBridge"; + +static NSString *const kAPIEndpointConversationList = @"conversations"; +static NSString *const kAPIEndpointConversationContents = @"messages"; +static NSString *const kAPIEndpointSendMessage = @"sendMessage"; + +@interface MBIMBridge (/* INTERNAL */) +@property (nonatomic, strong) GCDWebServer *webServer; + +- (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]; + } + + return self; +} + +#pragma mark - +#pragma mark Connection + +- (void)connect +{ + if (![sDaemonController hasListenerForID: MBIMBridgeToken]) { + if (![sDaemonController addListenerID:MBIMBridgeToken capabilities:(kFZListenerCapFileTransfers | kFZListenerCapManageStatus | kFZListenerCapChats | kFZListenerCapMessageHistory | kFZListenerCapIDQueries | kFZListenerCapSendMessages)]) { + NSLog(@"Failed to connect to imagent"); + } + } +} + +- (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!"); + + // Sending a message + /* + IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; + IMHandle *handle = [[iMessageAccount arrayOfAllIMHandles] firstObject]; + + NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:@"This is a test automated reply. Please ignore."]; + IMMessage *reply = [IMMessage fromMeIMHandle:handle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; + + IMChat *chat = [notification object]; + [chat sendMessage:reply]; + */ +} + +- (void)_chatRegistryDidLoad:(NSNotification *)notification +{ + NSLog(@"Loaded chat registry. %lu existing chats", (unsigned long)[sChatRegistry numberOfExistingChats]); +} + +- (void)_chatItemsDidChange:(NSNotification *)notification +{ + NSLog(@"chat items changed: %@", notification); +} + +- (BOOL)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID +{ + IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; + IMHandle *handle = [[iMessageAccount arrayOfAllIMHandles] firstObject]; + + NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:messageBody]; + IMMessage *reply = [IMMessage fromMeIMHandle:handle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; + + IMChat *chat = [sChatRegistry existingChatWithGUID:chatGUID]; + if (!chat) { + NSLog(@"Chat does not exist: %@", chatGUID); + return NO; + } + + [chat sendMessage:reply]; + + return YES; +} + +#pragma mark - +#pragma mark Web Server initialization + +- (void)startWebServer +{ + [GCDWebServer setLogLevel:3]; + + __auto_type __weak weakSelf = self; + self.webServer = [[GCDWebServer alloc] init]; + [self.webServer addDefaultHandlerForMethod:@"GET" + requestClass:[GCDWebServerRequest class] + processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerRequest * _Nonnull request) { return [weakSelf _handleWebServerRequest:request]; }]; + + [self.webServer addDefaultHandlerForMethod:@"POST" + requestClass:[GCDWebServerURLEncodedFormRequest class] + processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerRequest * _Nonnull request) { return [weakSelf _handleWebServerPOST:(GCDWebServerURLEncodedFormRequest *)request]; }]; + + [self.webServer startWithPort:8080 bonjourName:nil]; +} + +- (GCDWebServerResponse *)_handleWebServerPOST:(__kindof GCDWebServerURLEncodedFormRequest * _Nonnull)request +{ + NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:[request URL] resolvingAgainstBaseURL:NO]; + NSString *endpoint = [[urlComponents path] lastPathComponent]; + + if ([endpoint isEqualToString:kAPIEndpointSendMessage]) { + NSDictionary *args = [request arguments]; + + NSString *guid = [args objectForKey:@"guid"]; + NSString *messageBody = [args objectForKey:@"body"]; + BOOL result = [self _sendMessage:messageBody toChatWithGUID:guid]; + if (result) { + return [GCDWebServerDataResponse responseWithStatusCode:200]; + } else { + return [GCDWebServerDataResponse responseWithStatusCode:500]; + } + } + + return [GCDWebServerDataResponse responseWithStatusCode:404]; +} + +- (GCDWebServerResponse *)_handleWebServerRequest:(__kindof GCDWebServerRequest * _Nonnull)request +{ + NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:[request URL] resolvingAgainstBaseURL:NO]; + NSString *endpoint = [[urlComponents path] lastPathComponent]; + + if ([endpoint isEqualToString:kAPIEndpointConversationList]) { + NSArray *chats = [sChatRegistry allExistingChats]; + + NSMutableArray *conversations = [NSMutableArray array]; + for (IMChat *chat in chats) { + NSMutableDictionary *chatDict = [NSMutableDictionary dictionary]; + chatDict[@"guid"] = [chat guid]; + chatDict[@"displayName"] = [chat displayName]; + chatDict[@"date"] = GCDWebServerFormatRFC822([chat lastFinishedMessageDate]); + + [conversations addObject:chatDict]; + } + + return [GCDWebServerDataResponse responseWithJSONObject:conversations]; + } + + if ([endpoint isEqualToString:kAPIEndpointConversationContents]) { + 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"); + return [GCDWebServerDataResponse responseWithStatusCode:500]; + } + + IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; + if (!chat) { + NSLog(@"Chat with guid: %@ not found", guid); + return [GCDWebServerDataResponse responseWithStatusCode:500]; + } + + // Load messages + [chat loadMessagesBeforeDate:[NSDate date] limit:50 loadImmediately:YES]; + + NSMutableArray *messages = [NSMutableArray array]; + for (IMMessageItem *imMessage in [[chat chatItems] messages]) { + NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; + messageDict[@"text"] = [[imMessage body] string]; + messageDict[@"date"] = GCDWebServerFormatRFC822([imMessage time]); + messageDict[@"sender"] = [imMessage sender]; + [messages addObject:messageDict]; + } + + return [GCDWebServerDataResponse responseWithJSONObject:messages]; + } + + + return [GCDWebServerDataResponse responseWithStatusCode:404]; +} + +#pragma mark - +#pragma mark Daemon lifecycle + +- (void)daemonControllerWillConnect +{ + NSLog(@"About to connect to daemon"); +} + +- (void)daemonControllerDidConnect +{ + NSLog(@"Did connect to daemon"); + + IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; + if (iMessageAccount) { + NSLog(@"iMessage account connected: %@", iMessageAccount); + } else { + NSLog(@"Was not able to connect to iMessage account"); + } +} + +- (void)daemonControllerDidDisconnect +{ + NSLog(@"Did disconnect from daemon"); +} + +- (void)daemonConnectionLost +{ + NSLog(@"Connection lost to daemon"); +} + +@end diff --git a/MessagesBridge/MessagesBridge.entitlements b/kordophone/kordophone.entitlements similarity index 100% rename from MessagesBridge/MessagesBridge.entitlements rename to kordophone/kordophone.entitlements diff --git a/kordophone/main.m b/kordophone/main.m new file mode 100644 index 0000000..fde00de --- /dev/null +++ b/kordophone/main.m @@ -0,0 +1,24 @@ +// +// main.m +// kordophone +// +// Created by James Magahern on 11/12/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +#import "MBIMBridge.h" + +int main(int argc, const char * argv[]) { + @autoreleasepool { + MBIMBridge *bridge = [MBIMBridge sharedInstance]; + [bridge connect]; + + BOOL running = YES; + while (running) { + [[NSRunLoop currentRunLoop] run]; + } + } + return 0; +} From 7a3dee70735ea566dfa7cdc915948cc55b949a2c Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 12 Nov 2018 22:15:50 -0800 Subject: [PATCH 03/75] Bit of cleanup --- kordophone/Bridge/MBIMBridge.m | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index 75d5d28..54621a3 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -16,7 +16,7 @@ #import #import -static NSString *const MBIMBridgeToken = @"net.buzzert.MBIMBridge"; +static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; static NSString *const kAPIEndpointConversationList = @"conversations"; static NSString *const kAPIEndpointConversationContents = @"messages"; @@ -93,19 +93,9 @@ static NSString *const kAPIEndpointSendMessage = @"sendMessage"; - (void)_messageReceived:(NSNotification *)notification { - NSLog(@"Received!"); + NSLog(@"Received message from chat with GUID: %@", [[notification object] guid]); - // Sending a message - /* - IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; - IMHandle *handle = [[iMessageAccount arrayOfAllIMHandles] firstObject]; - - NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:@"This is a test automated reply. Please ignore."]; - IMMessage *reply = [IMMessage fromMeIMHandle:handle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; - - IMChat *chat = [notification object]; - [chat sendMessage:reply]; - */ + // TODO: Notify observers or something } - (void)_chatRegistryDidLoad:(NSNotification *)notification @@ -243,29 +233,30 @@ static NSString *const kAPIEndpointSendMessage = @"sendMessage"; - (void)daemonControllerWillConnect { - NSLog(@"About to connect to daemon"); + NSLog(@"Connecting to imagent..."); } - (void)daemonControllerDidConnect { - NSLog(@"Did connect to daemon"); + 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(@"Was not able to connect to iMessage account"); + NSLog(@"imagent returned no accounts (not entitled?)"); } } - (void)daemonControllerDidDisconnect { - NSLog(@"Did disconnect from daemon"); + NSLog(@"Disconnected from imagent"); } - (void)daemonConnectionLost { - NSLog(@"Connection lost to daemon"); + NSLog(@"Connection lost to imagent"); } @end From ce7e6e7dd88081dc74e53811ab0e37e69935208e Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 13 Nov 2018 12:29:15 -0800 Subject: [PATCH 04/75] Organize everything into operations --- MessagesBridge.xcodeproj/project.pbxproj | 32 +++++ kordophone/Bridge/MBIMBridge.m | 124 +++--------------- .../Bridge/Operations/MBIMBridgeOperation.h | 25 ++++ .../Bridge/Operations/MBIMBridgeOperation.m | 58 ++++++++ .../MBIMConversationListOperation.h | 17 +++ .../MBIMConversationListOperation.m | 40 ++++++ .../Operations/MBIMMessagesListOperation.h | 17 +++ .../Operations/MBIMMessagesListOperation.m | 67 ++++++++++ .../Operations/MBIMSendMessageOperation.h | 17 +++ .../Operations/MBIMSendMessageOperation.m | 63 +++++++++ 10 files changed, 354 insertions(+), 106 deletions(-) create mode 100644 kordophone/Bridge/Operations/MBIMBridgeOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMBridgeOperation.m create mode 100644 kordophone/Bridge/Operations/MBIMConversationListOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMConversationListOperation.m create mode 100644 kordophone/Bridge/Operations/MBIMMessagesListOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMMessagesListOperation.m create mode 100644 kordophone/Bridge/Operations/MBIMSendMessageOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMSendMessageOperation.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index dc9c6ee..5012574 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; + CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */; }; + CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */; }; + CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602061219B68950024D9C5 /* MBIMSendMessageOperation.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 */; }; @@ -102,6 +106,14 @@ 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OSXDebugDefaults.xcconfig; sourceTree = ""; }; 1A33B43D219A5ACD0034485A /* ReleaseDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseDefaults.xcconfig; sourceTree = ""; }; 1A33B43E219A5BD80034485A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridgeOperation.h; sourceTree = ""; }; + CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridgeOperation.m; sourceTree = ""; }; + CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMMessagesListOperation.h; sourceTree = ""; }; + CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMMessagesListOperation.m; sourceTree = ""; }; + CD60205D219B674B0024D9C5 /* MBIMConversationListOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMConversationListOperation.h; sourceTree = ""; }; + CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMConversationListOperation.m; sourceTree = ""; }; + CD602060219B68950024D9C5 /* MBIMSendMessageOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMSendMessageOperation.h; sourceTree = ""; }; + CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMSendMessageOperation.m; sourceTree = ""; }; CDF62312219A869000690038 /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = GCDWebServer/GCDWebServer.xcodeproj; 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 = ""; }; @@ -170,6 +182,7 @@ 1A0C446D219A4BCD00F2AC00 /* Bridge */ = { isa = PBXGroup; children = ( + CD60204C219B5D710024D9C5 /* Operations */, 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */, 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */, ); @@ -187,6 +200,21 @@ path = "Config Files"; sourceTree = ""; }; + CD60204C219B5D710024D9C5 /* Operations */ = { + isa = PBXGroup; + children = ( + CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */, + CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */, + CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */, + CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */, + CD60205D219B674B0024D9C5 /* MBIMConversationListOperation.h */, + CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */, + CD602060219B68950024D9C5 /* MBIMSendMessageOperation.h */, + CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */, + ); + path = Operations; + sourceTree = ""; + }; CDF62313219A869000690038 /* Products */ = { isa = PBXGroup; children = ( @@ -330,6 +358,10 @@ CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, CDF62335219A895D00690038 /* main.m in Sources */, + CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */, + CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, + CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */, + CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index 54621a3..5559595 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -7,6 +7,7 @@ // #import "MBIMBridge.h" +#import "MBIMBridgeOperation.h" #import @@ -18,12 +19,9 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; -static NSString *const kAPIEndpointConversationList = @"conversations"; -static NSString *const kAPIEndpointConversationContents = @"messages"; -static NSString *const kAPIEndpointSendMessage = @"sendMessage"; - @interface MBIMBridge (/* INTERNAL */) @property (nonatomic, strong) GCDWebServer *webServer; +@property (nonatomic, strong) NSOperationQueue *operationQueue; - (instancetype)_init; @end @@ -50,6 +48,8 @@ static NSString *const kAPIEndpointSendMessage = @"sendMessage"; [sDaemonController setDelegate:self]; [sDaemonListener addHandler:self]; + + _operationQueue = [[NSOperationQueue alloc] init]; } return self; @@ -108,28 +108,21 @@ static NSString *const kAPIEndpointSendMessage = @"sendMessage"; NSLog(@"chat items changed: %@", notification); } -- (BOOL)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID -{ - IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; - IMHandle *handle = [[iMessageAccount arrayOfAllIMHandles] firstObject]; - - NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:messageBody]; - IMMessage *reply = [IMMessage fromMeIMHandle:handle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; - - IMChat *chat = [sChatRegistry existingChatWithGUID:chatGUID]; - if (!chat) { - NSLog(@"Chat does not exist: %@", chatGUID); - return NO; - } - - [chat sendMessage:reply]; - - return YES; -} - #pragma mark - #pragma mark Web Server initialization +- (void)_handleAsyncServerRequest:(GCDWebServerRequest *)request completion:(GCDWebServerCompletionBlock)completion +{ + NSString *endpointName = [[request URL] lastPathComponent]; + Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName]; + if (operationClass != nil) { + MBIMBridgeOperation *operation = [[operationClass alloc] initWithRequest:request completion:completion]; + [[self operationQueue] addOperation:operation]; + } else { + completion([GCDWebServerDataResponse responseWithStatusCode:404]); + } +} + - (void)startWebServer { [GCDWebServer setLogLevel:3]; @@ -138,96 +131,15 @@ static NSString *const kAPIEndpointSendMessage = @"sendMessage"; self.webServer = [[GCDWebServer alloc] init]; [self.webServer addDefaultHandlerForMethod:@"GET" requestClass:[GCDWebServerRequest class] - processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerRequest * _Nonnull request) { return [weakSelf _handleWebServerRequest:request]; }]; + asyncProcessBlock:^(__kindof GCDWebServerRequest * _Nonnull request, GCDWebServerCompletionBlock _Nonnull completionBlock) { [weakSelf _handleAsyncServerRequest:request completion:completionBlock]; }]; [self.webServer addDefaultHandlerForMethod:@"POST" requestClass:[GCDWebServerURLEncodedFormRequest class] - processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerRequest * _Nonnull request) { return [weakSelf _handleWebServerPOST:(GCDWebServerURLEncodedFormRequest *)request]; }]; + asyncProcessBlock:^(__kindof GCDWebServerRequest * _Nonnull request, GCDWebServerCompletionBlock _Nonnull completionBlock) { [weakSelf _handleAsyncServerRequest:request completion:completionBlock]; }]; [self.webServer startWithPort:8080 bonjourName:nil]; } -- (GCDWebServerResponse *)_handleWebServerPOST:(__kindof GCDWebServerURLEncodedFormRequest * _Nonnull)request -{ - NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:[request URL] resolvingAgainstBaseURL:NO]; - NSString *endpoint = [[urlComponents path] lastPathComponent]; - - if ([endpoint isEqualToString:kAPIEndpointSendMessage]) { - NSDictionary *args = [request arguments]; - - NSString *guid = [args objectForKey:@"guid"]; - NSString *messageBody = [args objectForKey:@"body"]; - BOOL result = [self _sendMessage:messageBody toChatWithGUID:guid]; - if (result) { - return [GCDWebServerDataResponse responseWithStatusCode:200]; - } else { - return [GCDWebServerDataResponse responseWithStatusCode:500]; - } - } - - return [GCDWebServerDataResponse responseWithStatusCode:404]; -} - -- (GCDWebServerResponse *)_handleWebServerRequest:(__kindof GCDWebServerRequest * _Nonnull)request -{ - NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:[request URL] resolvingAgainstBaseURL:NO]; - NSString *endpoint = [[urlComponents path] lastPathComponent]; - - if ([endpoint isEqualToString:kAPIEndpointConversationList]) { - NSArray *chats = [sChatRegistry allExistingChats]; - - NSMutableArray *conversations = [NSMutableArray array]; - for (IMChat *chat in chats) { - NSMutableDictionary *chatDict = [NSMutableDictionary dictionary]; - chatDict[@"guid"] = [chat guid]; - chatDict[@"displayName"] = [chat displayName]; - chatDict[@"date"] = GCDWebServerFormatRFC822([chat lastFinishedMessageDate]); - - [conversations addObject:chatDict]; - } - - return [GCDWebServerDataResponse responseWithJSONObject:conversations]; - } - - if ([endpoint isEqualToString:kAPIEndpointConversationContents]) { - 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"); - return [GCDWebServerDataResponse responseWithStatusCode:500]; - } - - IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; - if (!chat) { - NSLog(@"Chat with guid: %@ not found", guid); - return [GCDWebServerDataResponse responseWithStatusCode:500]; - } - - // Load messages - [chat loadMessagesBeforeDate:[NSDate date] limit:50 loadImmediately:YES]; - - NSMutableArray *messages = [NSMutableArray array]; - for (IMMessageItem *imMessage in [[chat chatItems] messages]) { - NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; - messageDict[@"text"] = [[imMessage body] string]; - messageDict[@"date"] = GCDWebServerFormatRFC822([imMessage time]); - messageDict[@"sender"] = [imMessage sender]; - [messages addObject:messageDict]; - } - - return [GCDWebServerDataResponse responseWithJSONObject:messages]; - } - - - return [GCDWebServerDataResponse responseWithStatusCode:404]; -} - #pragma mark - #pragma mark Daemon lifecycle diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.h b/kordophone/Bridge/Operations/MBIMBridgeOperation.h new file mode 100644 index 0000000..8b3894d --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.h @@ -0,0 +1,25 @@ +// +// MBIMBridgeOperation.h +// kordophoned +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMBridgeOperation : NSOperation +@property (class, nonatomic, readonly) NSString *endpointName; + +@property (nonatomic, readonly) GCDWebServerRequest *request; +@property (nonatomic, readonly) GCDWebServerCompletionBlock serverCompletionBlock; + ++ (nullable Class)operationClassForEndpointName:(NSString *)endpointName; +- (instancetype)initWithRequest:(GCDWebServerRequest *)request completion:(GCDWebServerCompletionBlock)completionBlock; + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.m b/kordophone/Bridge/Operations/MBIMBridgeOperation.m new file mode 100644 index 0000000..883489e --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.m @@ -0,0 +1,58 @@ +// +// MBIMBridgeOperation.m +// kordophoned +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +@interface MBIMBridgeOperation (/*INTERNAL*/) +@property (nonatomic, copy) GCDWebServerCompletionBlock serverCompletionBlock; +@property (nonatomic, strong) GCDWebServerRequest *request; +@end + +@implementation MBIMBridgeOperation + ++ (NSString *)endpointName +{ + // To be inplemented by subclasses + return @"__unimplemented__"; +} + ++ (NSMutableDictionary *)_operationClassMapping +{ + static dispatch_once_t onceToken; + static NSMutableDictionary *operationClassMapping = nil; + dispatch_once(&onceToken, ^{ + operationClassMapping = [[NSMutableDictionary alloc] init]; + }); + + return operationClassMapping; +} + ++ (void)load +{ + if ([self class] != [MBIMBridgeOperation class]) { + [[self _operationClassMapping] setObject:[self class] forKey:[self endpointName]]; + } +} + ++ (nullable Class)operationClassForEndpointName:(NSString *)endpointName +{ + return [[self _operationClassMapping] objectForKey:endpointName]; +} + +- (instancetype)initWithRequest:(GCDWebServerRequest *)request completion:(GCDWebServerCompletionBlock)completionBlock +{ + self = [super init]; + if (self) { + self.request = request; + self.serverCompletionBlock = completionBlock; + } + + return self; +} + +@end diff --git a/kordophone/Bridge/Operations/MBIMConversationListOperation.h b/kordophone/Bridge/Operations/MBIMConversationListOperation.h new file mode 100644 index 0000000..0e43311 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMConversationListOperation.h @@ -0,0 +1,17 @@ +// +// MBIMConversationListOperation.h +// kordophoned +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMConversationListOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMConversationListOperation.m b/kordophone/Bridge/Operations/MBIMConversationListOperation.m new file mode 100644 index 0000000..1962153 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMConversationListOperation.m @@ -0,0 +1,40 @@ +// +// MBIMConversationListOperation.m +// kordophoned +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMConversationListOperation.h" + +#import + +@implementation MBIMConversationListOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"conversations"; +} + +- (void)main +{ + NSArray *chats = [sChatRegistry allExistingChats]; + + NSMutableArray *conversations = [NSMutableArray array]; + for (IMChat *chat in chats) { + NSMutableDictionary *chatDict = [NSMutableDictionary dictionary]; + chatDict[@"guid"] = [chat guid]; + chatDict[@"displayName"] = [chat displayName]; + chatDict[@"date"] = GCDWebServerFormatRFC822([chat lastFinishedMessageDate]); + + [conversations addObject:chatDict]; + } + + GCDWebServerResponse *response = [GCDWebServerDataResponse responseWithJSONObject:conversations]; + self.serverCompletionBlock(response); +} + +@end diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.h b/kordophone/Bridge/Operations/MBIMMessagesListOperation.h new file mode 100644 index 0000000..cc0215d --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.h @@ -0,0 +1,17 @@ +// +// MBIMMessagesListOperation.h +// kordophoned +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMMessagesListOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m new file mode 100644 index 0000000..d9be1b1 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -0,0 +1,67 @@ +// +// MBIMMessagesListOperation.m +// kordophoned +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMMessagesListOperation.h" + +#import + +@implementation MBIMMessagesListOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"messages"; +} + +- (void)main +{ + GCDWebServerResponse *response = nil; + do { + NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:[self.request URL] 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 = [GCDWebServerDataResponse responseWithStatusCode:500]; + break; + } + + IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; + if (!chat) { + NSLog(@"Chat with guid: %@ not found", guid); + response = [GCDWebServerDataResponse responseWithStatusCode:500]; + break; + } + + // Load messages + [chat loadMessagesBeforeDate:[NSDate date] limit:50 loadImmediately:YES]; + + NSMutableArray *messages = [NSMutableArray array]; + for (IMMessageItem *imMessage in [[chat chatItems] messages]) { + NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; + messageDict[@"text"] = [[imMessage body] string]; + messageDict[@"date"] = GCDWebServerFormatRFC822([imMessage time]); + messageDict[@"sender"] = [imMessage sender]; + [messages addObject:messageDict]; + } + + response = [GCDWebServerDataResponse responseWithJSONObject:messages]; + } while (0); + + self.serverCompletionBlock(response); +} + +@end diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.h b/kordophone/Bridge/Operations/MBIMSendMessageOperation.h new file mode 100644 index 0000000..8762af2 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.h @@ -0,0 +1,17 @@ +// +// MBIMSendMessageOperation.h +// kordophoned +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMSendMessageOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m new file mode 100644 index 0000000..907c6c9 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -0,0 +1,63 @@ +// +// MBIMSendMessageOperation.m +// kordophoned +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMSendMessageOperation.h" + +#import +#import + +@implementation MBIMSendMessageOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"sendMessage"; +} + +- (BOOL)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID +{ + IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; + IMHandle *handle = [[iMessageAccount arrayOfAllIMHandles] firstObject]; + + NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:messageBody]; + IMMessage *reply = [IMMessage fromMeIMHandle:handle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; + + IMChat *chat = [sChatRegistry existingChatWithGUID:chatGUID]; + if (!chat) { + NSLog(@"Chat does not exist: %@", chatGUID); + return NO; + } + + [chat sendMessage:reply]; + + return YES; +} + +- (void)main +{ + assert([self.request isKindOfClass:[GCDWebServerURLEncodedFormRequest class]]); + + GCDWebServerURLEncodedFormRequest *formRequest = (GCDWebServerURLEncodedFormRequest *)self.request; + NSDictionary *args = [formRequest arguments]; + + NSString *guid = [args objectForKey:@"guid"]; + NSString *messageBody = [args objectForKey:@"body"]; + BOOL result = [self _sendMessage:messageBody toChatWithGUID:guid]; + + GCDWebServerResponse *response = nil; + if (result) { + response = [GCDWebServerDataResponse responseWithStatusCode:200]; + } else { + response = [GCDWebServerDataResponse responseWithStatusCode:500]; + } + + self.serverCompletionBlock(response); +} + +@end From f462ee68ca8cb14936493dd266edad5277433d4f Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 13 Nov 2018 22:39:03 -0800 Subject: [PATCH 05/75] Try to not use private entitlements --- .gitmodules | 3 + MessagesBridge.xcodeproj/project.pbxproj | 135 +++++++++++++++++- .../xcschemes/kordophoned.xcscheme | 6 + README.md | 9 ++ agentHook/agentHook.m | 19 +++ agentHook/hookAgent.sh | 19 +++ kordophone/Bridge/MBIMBridge.h | 5 + kordophone/Bridge/MBIMBridge.m | 20 +++ kordophone/Hooking/hooking.h | 12 ++ kordophone/Hooking/hooking.m | 75 ++++++++++ kordophone/kordophone.entitlements | 47 ------ kordophone/main.m | 10 ++ 12 files changed, 309 insertions(+), 51 deletions(-) create mode 100644 agentHook/agentHook.m create mode 100755 agentHook/hookAgent.sh create mode 100644 kordophone/Hooking/hooking.h create mode 100644 kordophone/Hooking/hooking.m delete mode 100644 kordophone/kordophone.entitlements diff --git a/.gitmodules b/.gitmodules index 2d85876..cd77084 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "GCDWebServer"] path = GCDWebServer url = https://github.com/swisspol/GCDWebServer.git +[submodule "logos"] + path = logos + url = git@github.com:theos/logos.git diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 5012574..bddcc17 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */; }; CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */; }; 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 */; }; 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 */; }; @@ -21,6 +23,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + CD83E16A219BE9AB00F4CCEA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1A0C443F219A38E100F2AC00 /* Project object */; + proxyType = 1; + remoteGlobalIDString = CD83E160219BE91500F4CCEA; + remoteInfo = agentHook; + }; CDF6231D219A869000690038 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; @@ -92,7 +101,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 1A0C4455219A38E200F2AC00 /* kordophone.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = kordophone.entitlements; sourceTree = ""; }; 1A0C445D219A458400F2AC00 /* SOAPlugInControllerProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOAPlugInControllerProtocol.h; sourceTree = ""; }; 1A0C445F219A45B400F2AC00 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 1A0C4461219A45B900F2AC00 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; @@ -114,6 +122,11 @@ CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMConversationListOperation.m; sourceTree = ""; }; CD602060219B68950024D9C5 /* MBIMSendMessageOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMSendMessageOperation.h; sourceTree = ""; }; CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMSendMessageOperation.m; sourceTree = ""; }; + CD83E154219BDBA200F4CCEA /* hooking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hooking.h; sourceTree = ""; }; + CD83E155219BE10A00F4CCEA /* hooking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = hooking.m; sourceTree = ""; }; + 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 = ""; }; CDF62312219A869000690038 /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = GCDWebServer/GCDWebServer.xcodeproj; 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 = ""; }; @@ -122,6 +135,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + CD83E15F219BE91500F4CCEA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CDF6232F219A895D00690038 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -144,6 +164,7 @@ CDF62333219A895D00690038 /* kordophone */, 1A33B439219A5ACD0034485A /* Config Files */, 1A0C445C219A457C00F2AC00 /* Pilfered Headers */, + CD83E162219BE91600F4CCEA /* agentHook */, 1A0C4448219A38E100F2AC00 /* Products */, 1A0C445E219A45B400F2AC00 /* Frameworks */, ); @@ -153,6 +174,7 @@ isa = PBXGroup; children = ( CDF62332219A895D00690038 /* kordophoned */, + CD83E161219BE91500F4CCEA /* libagentHook.dylib */, ); name = Products; sourceTree = ""; @@ -215,6 +237,24 @@ path = Operations; sourceTree = ""; }; + CD83E150219BDB4F00F4CCEA /* Hooking */ = { + isa = PBXGroup; + children = ( + CD83E154219BDBA200F4CCEA /* hooking.h */, + CD83E155219BE10A00F4CCEA /* hooking.m */, + ); + path = Hooking; + sourceTree = ""; + }; + CD83E162219BE91600F4CCEA /* agentHook */ = { + isa = PBXGroup; + children = ( + CD83E1B5219BF78E00F4CCEA /* hookAgent.sh */, + CD83E165219BE91600F4CCEA /* agentHook.m */, + ); + path = agentHook; + sourceTree = ""; + }; CDF62313219A869000690038 /* Products */ = { isa = PBXGroup; children = ( @@ -232,8 +272,8 @@ CDF62333219A895D00690038 /* kordophone */ = { isa = PBXGroup; children = ( + CD83E150219BDB4F00F4CCEA /* Hooking */, 1A0C446D219A4BCD00F2AC00 /* Bridge */, - 1A0C4455219A38E200F2AC00 /* kordophone.entitlements */, CDF62334219A895D00690038 /* main.m */, ); path = kordophone; @@ -241,7 +281,34 @@ }; /* End PBXGroup section */ +/* Begin PBXHeadersBuildPhase section */ + CD83E15D219BE91500F4CCEA /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + /* Begin PBXNativeTarget section */ + CD83E160219BE91500F4CCEA /* agentHook */ = { + isa = PBXNativeTarget; + buildConfigurationList = CD83E167219BE91600F4CCEA /* Build configuration list for PBXNativeTarget "agentHook" */; + buildPhases = ( + CD83E15D219BE91500F4CCEA /* Headers */, + CD83E15E219BE91500F4CCEA /* Sources */, + CD83E15F219BE91500F4CCEA /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = agentHook; + productName = agentHook; + productReference = CD83E161219BE91500F4CCEA /* libagentHook.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; CDF62331219A895D00690038 /* kordophoned */ = { isa = PBXNativeTarget; buildConfigurationList = CDF62336219A895D00690038 /* Build configuration list for PBXNativeTarget "kordophoned" */; @@ -253,6 +320,7 @@ buildRules = ( ); dependencies = ( + CD83E16B219BE9AB00F4CCEA /* PBXTargetDependency */, CDF6233C219A8A6600690038 /* PBXTargetDependency */, ); name = kordophoned; @@ -269,6 +337,9 @@ LastUpgradeCheck = 1100; ORGANIZATIONNAME = "James Magahern"; TargetAttributes = { + CD83E160219BE91500F4CCEA = { + CreatedOnToolsVersion = 11.0; + }; CDF62331219A895D00690038 = { CreatedOnToolsVersion = 11.0; }; @@ -294,6 +365,7 @@ projectRoot = ""; targets = ( CDF62331219A895D00690038 /* kordophoned */, + CD83E160219BE91500F4CCEA /* agentHook */, ); }; /* End PBXProject section */ @@ -351,11 +423,20 @@ /* End PBXReferenceProxy section */ /* Begin PBXSourcesBuildPhase section */ + CD83E15E219BE91500F4CCEA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CD83E166219BE91600F4CCEA /* agentHook.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CDF6232E219A895D00690038 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, + CD83E156219BE10A00F4CCEA /* hooking.m in Sources */, CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, CDF62335219A895D00690038 /* main.m in Sources */, CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */, @@ -368,6 +449,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + CD83E16B219BE9AB00F4CCEA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = CD83E160219BE91500F4CCEA /* agentHook */; + targetProxy = CD83E16A219BE9AB00F4CCEA /* PBXContainerItemProxy */; + }; CDF6233C219A8A6600690038 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = "GCDWebServers (Mac)"; @@ -495,11 +581,44 @@ }; name = Release; }; + CD83E168219BE91600F4CCEA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + EXECUTABLE_PREFIX = lib; + OTHER_LDFLAGS = ( + "-undefined", + dynamic_lookup, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + CD83E169219BE91600F4CCEA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + EXECUTABLE_PREFIX = lib; + OTHER_LDFLAGS = ( + "-undefined", + dynamic_lookup, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; CDF62337219A895D00690038 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = NO; - CODE_SIGN_ENTITLEMENTS = kordophone/kordophone.entitlements; CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx.internal; @@ -514,7 +633,6 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = NO; - CODE_SIGN_ENTITLEMENTS = kordophone/kordophone.entitlements; CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx.internal; @@ -537,6 +655,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + CD83E167219BE91600F4CCEA /* Build configuration list for PBXNativeTarget "agentHook" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD83E168219BE91600F4CCEA /* Debug */, + CD83E169219BE91600F4CCEA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; CDF62336219A895D00690038 /* Build configuration list for PBXNativeTarget "kordophoned" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme index c103900..d87e6eb 100644 --- a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme +++ b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme @@ -61,6 +61,12 @@ ReferencedContainer = "container:MessagesBridge.xcodeproj"> + + + + diff --git a/README.md b/README.md index 8ea8fd8..e657bef 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,12 @@ sudo defaults write /Library/Preferences/com.apple.security.coderequirements Ent ``` Maybe a better thing to do is to DYLD_PRELOAD `imagent` and swizzle `IMDAuditTokenTaskHasEntitlement` to always return YES. + + +## Building/linking +If you get dyld errors running from the command line, use `install_name_tool` to update the @rpath (where @rpath points to where linked Frameworks like GCDWebServer is). + `install_name_tool -add_rpath . ./kordophoned` + + +## Running +You need to hook imagent first to bypass entitlements check. Look at `hookAgent.sh` diff --git a/agentHook/agentHook.m b/agentHook/agentHook.m new file mode 100644 index 0000000..354fa51 --- /dev/null +++ b/agentHook/agentHook.m @@ -0,0 +1,19 @@ +#import +#import + +#include + +#define DYLD_INTERPOSE(_replacment,_replacee) \ +__attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \ +__attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee }; + + +BOOL IMDAuditTokenTaskHasEntitlement(audit_token_t *auditToken, NSString *entitlement); + +BOOL replacement__IMDAuditTokenTaskHasEntitlement(audit_token_t *auditToken, NSString *entitlement) +{ + // Bypass all entitlement checks + return YES; +} + +DYLD_INTERPOSE(replacement__IMDAuditTokenTaskHasEntitlement, IMDAuditTokenTaskHasEntitlement); diff --git a/agentHook/hookAgent.sh b/agentHook/hookAgent.sh new file mode 100755 index 0000000..5631265 --- /dev/null +++ b/agentHook/hookAgent.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# This script is necessary to circumvent the entitlements check in imagent. +# Might want to wrap this script up in a startup script or something so we make sure this +# happens every time. + +if [[ $# -lt 1 ]]; then + echo "Usage: hookAgent.sh libagentHook.dylib" + exit 0 +fi + +LIB_PATH=$(python -c "import os; print(os.path.realpath('$1'))") +echo "Library path: $LIB_PATH" + +echo "Telling imagent to launch with inserted libraries for uid $EUID" +sudo launchctl debug gui/$EUID/com.apple.imagent --environment DYLD_INSERT_LIBRARIES=$LIB_PATH +launchctl kill SIGKILL gui/501/com.apple.imagent + + diff --git a/kordophone/Bridge/MBIMBridge.h b/kordophone/Bridge/MBIMBridge.h index 679a960..ce00681 100644 --- a/kordophone/Bridge/MBIMBridge.h +++ b/kordophone/Bridge/MBIMBridge.h @@ -8,9 +8,14 @@ #import +// See note in hooking.m about why this was a bad idea +#define HOOK_IMAGENT 0 + NS_ASSUME_NONNULL_BEGIN @interface MBIMBridge : NSObject +@property (nonatomic, assign) const char *dylibPath; + + (instancetype)sharedInstance; - (instancetype)init NS_UNAVAILABLE; diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index 5559595..348143c 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -8,6 +8,7 @@ #import "MBIMBridge.h" #import "MBIMBridgeOperation.h" +#import "hooking.h" #import @@ -55,14 +56,32 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; 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]; } } } @@ -158,6 +177,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; NSLog(@"iMessage account connected: %@", iMessageAccount); } else { NSLog(@"imagent returned no accounts (not entitled?)"); + [self _terminate]; } } diff --git a/kordophone/Hooking/hooking.h b/kordophone/Hooking/hooking.h new file mode 100644 index 0000000..933fa89 --- /dev/null +++ b/kordophone/Hooking/hooking.h @@ -0,0 +1,12 @@ +// +// hooking.h +// MessagesBridge +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +// Returns success and a populated errorString on error. +BOOL HookIMAgent(const char *hookDylibPath, char **errorString); diff --git a/kordophone/Hooking/hooking.m b/kordophone/Hooking/hooking.m new file mode 100644 index 0000000..3b98af6 --- /dev/null +++ b/kordophone/Hooking/hooking.m @@ -0,0 +1,75 @@ +// +// hooking.c +// kordophoned +// +// Created by James Magahern on 11/13/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#include "hooking.h" +#include +#include +#include + +BOOL HookIMAgent(const char *relativeDylibPath, char **errorString) +{ + NSLog(@"Hooking imagent"); + + const char *hookDylibPath = realpath(relativeDylibPath, NULL); + + // See if file is there. + int succ = access(hookDylibPath, R_OK); + if (succ != 0) { + *errorString = "Unable to access hook dylib. Does file exist?"; + return NO; + } + + // Make sure we can load the dylib (filters out codesigning issues) + void *handle = dlopen(hookDylibPath, RTLD_NOW); + if (!handle) { + *errorString = dlerror(); + return NO; + } + + /********* + *********** + PROBABLY DON'T DO THIS + + If other processes start and load agentHook, then they will crash because dyld tries to + interpose a function that doesn't exist. + + A better way (maybe put this in a script or something): + ( But launchctl debug needs to run as root :( ) + + $ launchctl debug gui/501/com.apple.imagent --environment DYLD_INSERT_LIBRARIES=(path to libagentHook.dylib) + + $ launchctl kill SIGKILL gui/501/com.apple.imagent + + // then let it restart... + + **/ + + // Set launchd DYLD_INSERT_LIBRARIES environment variable + const char *systemCommandFormatString = "/bin/launchctl setenv DYLD_INSERT_LIBRARIES %s"; + size_t bufferSize = strlen(systemCommandFormatString) + strlen(hookDylibPath) + 2; + char *systemCommand = (char *)malloc(sizeof(char) * bufferSize); + + sprintf(systemCommand, "/bin/launchctl setenv DYLD_INSERT_LIBRARIES %s", hookDylibPath); + int setEnvSucc = system(systemCommand); + if (setEnvSucc != 0) { + *errorString = "Unable to set launchd environment variable."; + return NO; + } + + NSLog(@"Successfully setup environment variables"); + + // Kill imagent so the new one has the loaded bundle + NSLog(@"Killing imagent..."); + int killAgentSuccess = system("killall imagent"); + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + system("/bin/launchctl unsetenv DYLD_INSERT_LIBRARIES"); + }); + + return (killAgentSuccess == 0); +} diff --git a/kordophone/kordophone.entitlements b/kordophone/kordophone.entitlements deleted file mode 100644 index d61bb27..0000000 --- a/kordophone/kordophone.entitlements +++ /dev/null @@ -1,47 +0,0 @@ - - - - - com.apple.private.corespotlight.search.internal - - com.apple.private.corespotlight.internal - - com.apple.CommCenter.fine-grained - - spi - - com.apple.accounts.inactive.fullaccess - - com.apple.imagent - - com.apple.private.accounts.allaccounts - - com.apple.private.aps-connection-initiate - - com.apple.ess - com.apple.madrid - - com.apple.private.communicationsfilter - - com.apple.private.ids.idquery-cache - - com.apple.private.ids.remoteurlconnection - - com.apple.private.imcore.imdpersistence.database-access - - com.apple.private.tcc.allow - - kTCCServiceAddressBook - - keychain-access-groups - - appleaccount - InternetAccounts - IMCore - ichat - apple - - com.apple.logd.admin - - - diff --git a/kordophone/main.m b/kordophone/main.m index fde00de..8e90311 100644 --- a/kordophone/main.m +++ b/kordophone/main.m @@ -13,6 +13,16 @@ int main(int argc, const char * argv[]) { @autoreleasepool { MBIMBridge *bridge = [MBIMBridge sharedInstance]; + +#if HOOK_IMAGENT + if (argc < 2) { + fprintf(stderr, "Usage: kordophoned agentHook.dylib\n"); + return 1; + } + + bridge.dylibPath = argv[1]; +#endif + [bridge connect]; BOOL running = YES; From e08e9d738c35aae5193cc8a81c98673cecc558cd Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 14 Nov 2018 23:12:41 -0800 Subject: [PATCH 06/75] Message preview and participant list --- .../Operations/MBIMConversationListOperation.m | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/kordophone/Bridge/Operations/MBIMConversationListOperation.m b/kordophone/Bridge/Operations/MBIMConversationListOperation.m index 1962153..84ad63c 100644 --- a/kordophone/Bridge/Operations/MBIMConversationListOperation.m +++ b/kordophone/Bridge/Operations/MBIMConversationListOperation.m @@ -30,6 +30,21 @@ chatDict[@"displayName"] = [chat displayName]; chatDict[@"date"] = GCDWebServerFormatRFC822([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; + [conversations addObject:chatDict]; } From b92860b0114fd331ddf2bbb0fb19d2544f1cc0d7 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 15 Nov 2018 14:50:40 -0800 Subject: [PATCH 07/75] Some basic crypto laid down and tests --- MessagesBridge.xcodeproj/project.pbxproj | 120 +++++++++++++++++++++++ Tests/CryptoTests.m | 48 +++++++++ Tests/Info.plist | 22 +++++ kordophone/Crypto/NSData+AES.h | 17 ++++ kordophone/Crypto/NSData+AES.m | 58 +++++++++++ 5 files changed, 265 insertions(+) create mode 100644 Tests/CryptoTests.m create mode 100644 Tests/Info.plist create mode 100644 kordophone/Crypto/NSData+AES.h create mode 100644 kordophone/Crypto/NSData+AES.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index bddcc17..4147485 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + CD14F185219E2A6800E7DD22 /* NSData+AES.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F184219E2A6800E7DD22 /* NSData+AES.m */; }; + CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; + CD14F194219E2F9C00E7DD22 /* NSData+AES.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F184219E2A6800E7DD22 /* NSData+AES.m */; }; CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */; }; CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */; }; @@ -114,6 +117,11 @@ 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OSXDebugDefaults.xcconfig; sourceTree = ""; }; 1A33B43D219A5ACD0034485A /* ReleaseDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseDefaults.xcconfig; sourceTree = ""; }; 1A33B43E219A5BD80034485A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; + CD14F183219E2A6800E7DD22 /* NSData+AES.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+AES.h"; sourceTree = ""; }; + CD14F184219E2A6800E7DD22 /* NSData+AES.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+AES.m"; sourceTree = ""; }; + CD14F18B219E2DB400E7DD22 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + CD14F18D219E2DB400E7DD22 /* CryptoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoTests.m; sourceTree = ""; }; + CD14F18F219E2DB400E7DD22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridgeOperation.h; sourceTree = ""; }; CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridgeOperation.m; sourceTree = ""; }; CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMMessagesListOperation.h; sourceTree = ""; }; @@ -135,6 +143,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + CD14F188219E2DB400E7DD22 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD83E15F219BE91500F4CCEA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -165,6 +180,7 @@ 1A33B439219A5ACD0034485A /* Config Files */, 1A0C445C219A457C00F2AC00 /* Pilfered Headers */, CD83E162219BE91600F4CCEA /* agentHook */, + CD14F18C219E2DB400E7DD22 /* Tests */, 1A0C4448219A38E100F2AC00 /* Products */, 1A0C445E219A45B400F2AC00 /* Frameworks */, ); @@ -175,6 +191,7 @@ children = ( CDF62332219A895D00690038 /* kordophoned */, CD83E161219BE91500F4CCEA /* libagentHook.dylib */, + CD14F18B219E2DB400E7DD22 /* Tests.xctest */, ); name = Products; sourceTree = ""; @@ -222,6 +239,24 @@ path = "Config Files"; sourceTree = ""; }; + CD14F182219E2A4C00E7DD22 /* Crypto */ = { + isa = PBXGroup; + children = ( + CD14F183219E2A6800E7DD22 /* NSData+AES.h */, + CD14F184219E2A6800E7DD22 /* NSData+AES.m */, + ); + path = Crypto; + sourceTree = ""; + }; + CD14F18C219E2DB400E7DD22 /* Tests */ = { + isa = PBXGroup; + children = ( + CD14F18D219E2DB400E7DD22 /* CryptoTests.m */, + CD14F18F219E2DB400E7DD22 /* Info.plist */, + ); + path = Tests; + sourceTree = ""; + }; CD60204C219B5D710024D9C5 /* Operations */ = { isa = PBXGroup; children = ( @@ -272,6 +307,7 @@ CDF62333219A895D00690038 /* kordophone */ = { isa = PBXGroup; children = ( + CD14F182219E2A4C00E7DD22 /* Crypto */, CD83E150219BDB4F00F4CCEA /* Hooking */, 1A0C446D219A4BCD00F2AC00 /* Bridge */, CDF62334219A895D00690038 /* main.m */, @@ -292,6 +328,23 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + CD14F18A219E2DB400E7DD22 /* Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = CD14F190219E2DB400E7DD22 /* Build configuration list for PBXNativeTarget "Tests" */; + buildPhases = ( + CD14F187219E2DB400E7DD22 /* Sources */, + CD14F188219E2DB400E7DD22 /* Frameworks */, + CD14F189219E2DB400E7DD22 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Tests; + productName = Tests; + productReference = CD14F18B219E2DB400E7DD22 /* Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; CD83E160219BE91500F4CCEA /* agentHook */ = { isa = PBXNativeTarget; buildConfigurationList = CD83E167219BE91600F4CCEA /* Build configuration list for PBXNativeTarget "agentHook" */; @@ -337,6 +390,9 @@ LastUpgradeCheck = 1100; ORGANIZATIONNAME = "James Magahern"; TargetAttributes = { + CD14F18A219E2DB400E7DD22 = { + CreatedOnToolsVersion = 11.0; + }; CD83E160219BE91500F4CCEA = { CreatedOnToolsVersion = 11.0; }; @@ -366,6 +422,7 @@ targets = ( CDF62331219A895D00690038 /* kordophoned */, CD83E160219BE91500F4CCEA /* agentHook */, + CD14F18A219E2DB400E7DD22 /* Tests */, ); }; /* End PBXProject section */ @@ -422,7 +479,26 @@ }; /* End PBXReferenceProxy section */ +/* Begin PBXResourcesBuildPhase section */ + CD14F189219E2DB400E7DD22 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ + CD14F187219E2DB400E7DD22 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CD14F194219E2F9C00E7DD22 /* NSData+AES.m in Sources */, + CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD83E15E219BE91500F4CCEA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -440,6 +516,7 @@ CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, CDF62335219A895D00690038 /* main.m in Sources */, CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */, + CD14F185219E2A6800E7DD22 /* NSData+AES.m in Sources */, CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */, CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, @@ -581,6 +658,40 @@ }; name = Release; }; + CD14F191219E2DB400E7DD22 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.buzzert.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + CD14F192219E2DB400E7DD22 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Tests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.buzzert.Tests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; CD83E168219BE91600F4CCEA /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -655,6 +766,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + CD14F190219E2DB400E7DD22 /* Build configuration list for PBXNativeTarget "Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD14F191219E2DB400E7DD22 /* Debug */, + CD14F192219E2DB400E7DD22 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; CD83E167219BE91600F4CCEA /* Build configuration list for PBXNativeTarget "agentHook" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Tests/CryptoTests.m b/Tests/CryptoTests.m new file mode 100644 index 0000000..eca7828 --- /dev/null +++ b/Tests/CryptoTests.m @@ -0,0 +1,48 @@ +// +// Tests.m +// Tests +// +// Created by James Magahern on 11/15/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +#import "NSData+AES.h" + +// base64 encoded +static NSString *const kTestKey = @"QMeDmiHj8eCFVfrQWQfDpw=="; + +@interface Tests : XCTestCase +@property (nonatomic, strong) NSString *commonPayload; +@property (nonatomic, strong) NSData *commonIVData; +@property (nonatomic, strong) NSData *symmetricKeyData; +@end + +@implementation Tests + +- (void)setUp { + self.commonPayload = @"Hey this is a test"; + + NSString *IVDataString = [[NSUUID UUID] UUIDString]; + self.commonIVData = [IVDataString dataUsingEncoding:NSUTF8StringEncoding]; + + self.symmetricKeyData = [[NSData alloc] initWithBase64EncodedString:kTestKey options:0]; + XCTAssert(self.commonIVData && self.symmetricKeyData); +} + +- (void)testEncryptionAndDecryption +{ + NSData *inputData = [self.commonPayload dataUsingEncoding:NSUTF8StringEncoding]; + + NSError *error = nil; + NSData *encryptedData = [inputData encryptedDataWithKey:self.symmetricKeyData iv:self.commonIVData error:&error]; + XCTAssert(!error); + + NSData *decryptedData = [encryptedData decryptedDataWithKey:self.symmetricKeyData iv:self.commonIVData error:&error]; + XCTAssert(!error); + + XCTAssert([decryptedData isEqualToData:inputData]); +} + +@end diff --git a/Tests/Info.plist b/Tests/Info.plist new file mode 100644 index 0000000..6c40a6c --- /dev/null +++ b/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/kordophone/Crypto/NSData+AES.h b/kordophone/Crypto/NSData+AES.h new file mode 100644 index 0000000..7530ba7 --- /dev/null +++ b/kordophone/Crypto/NSData+AES.h @@ -0,0 +1,17 @@ +// +// NSData+AES.h +// MessagesBridge +// +// Created by James Magahern on 11/15/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import +#import + +@interface NSData (AES) + +- (NSData *)encryptedDataWithKey:(NSData *)key iv:(NSData *)iv error:(NSError **)error; +- (NSData *)decryptedDataWithKey:(NSData *)key iv:(NSData *)iv error:(NSError **)error; + +@end diff --git a/kordophone/Crypto/NSData+AES.m b/kordophone/Crypto/NSData+AES.m new file mode 100644 index 0000000..d69614c --- /dev/null +++ b/kordophone/Crypto/NSData+AES.m @@ -0,0 +1,58 @@ +// +// NSData+AES.m +// MessagesBridge +// +// Created by James Magahern on 11/15/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "NSData+AES.h" + +@implementation NSData (AES) + ++ (NSData *)AES128Operation:(CCOperation)operation + withInputData:(NSData *)inputData + key:(NSData *)key + iv:(NSData *)iv + error:(NSError **)error +{ + size_t dataMoved = 0; + NSMutableData *outputData = [NSMutableData dataWithLength:(inputData.length + kCCBlockSizeAES128)]; + CCCryptorStatus status = CCCrypt( + operation, + kCCAlgorithmAES, + kCCOptionPKCS7Padding, + key.bytes, + key.length, + iv.bytes, + inputData.bytes, + inputData.length, + outputData.mutableBytes, + outputData.length, + &dataMoved + ); + + if (status == kCCSuccess) { + outputData.length = dataMoved; + } else { + *error = [NSError errorWithDomain:@"CommonCryptoError" + code:status + userInfo:nil]; + + outputData = nil; + } + + return outputData; +} + +- (NSData *)encryptedDataWithKey:(NSData *)key iv:(NSData *)iv error:(NSError *__autoreleasing *)error +{ + return [[self class] AES128Operation:kCCEncrypt withInputData:self key:key iv:iv error:error]; +} + +- (NSData *)decryptedDataWithKey:(NSData *)key iv:(NSData *)iv error:(NSError *__autoreleasing *)error +{ + return [[self class] AES128Operation:kCCDecrypt withInputData:self key:key iv:iv error:error]; +} + +@end From 6c9996dfa17228cf23222c4994805aff898e29d1 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 15 Nov 2018 15:08:39 -0800 Subject: [PATCH 08/75] Encrypted server response --- MessagesBridge.xcodeproj/project.pbxproj | 6 ++++ .../Crypto/GCDWebServerDataResponse+Crypto.h | 20 +++++++++++ .../Crypto/GCDWebServerDataResponse+Crypto.m | 36 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 kordophone/Crypto/GCDWebServerDataResponse+Crypto.h create mode 100644 kordophone/Crypto/GCDWebServerDataResponse+Crypto.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 4147485..a86c464 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ CD14F185219E2A6800E7DD22 /* NSData+AES.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F184219E2A6800E7DD22 /* NSData+AES.m */; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; CD14F194219E2F9C00E7DD22 /* NSData+AES.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F184219E2A6800E7DD22 /* NSData+AES.m */; }; + CD14F19E219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F19D219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m */; }; CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */; }; CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */; }; @@ -122,6 +123,8 @@ CD14F18B219E2DB400E7DD22 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CD14F18D219E2DB400E7DD22 /* CryptoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoTests.m; sourceTree = ""; }; CD14F18F219E2DB400E7DD22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CD14F19C219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GCDWebServerDataResponse+Crypto.h"; sourceTree = ""; }; + CD14F19D219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "GCDWebServerDataResponse+Crypto.m"; sourceTree = ""; }; CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridgeOperation.h; sourceTree = ""; }; CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridgeOperation.m; sourceTree = ""; }; CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMMessagesListOperation.h; sourceTree = ""; }; @@ -244,6 +247,8 @@ children = ( CD14F183219E2A6800E7DD22 /* NSData+AES.h */, CD14F184219E2A6800E7DD22 /* NSData+AES.m */, + CD14F19C219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.h */, + CD14F19D219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m */, ); path = Crypto; sourceTree = ""; @@ -517,6 +522,7 @@ CDF62335219A895D00690038 /* main.m in Sources */, CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */, CD14F185219E2A6800E7DD22 /* NSData+AES.m in Sources */, + CD14F19E219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m in Sources */, CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */, CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, diff --git a/kordophone/Crypto/GCDWebServerDataResponse+Crypto.h b/kordophone/Crypto/GCDWebServerDataResponse+Crypto.h new file mode 100644 index 0000000..6b9ab04 --- /dev/null +++ b/kordophone/Crypto/GCDWebServerDataResponse+Crypto.h @@ -0,0 +1,20 @@ +// +// GCDWebServerDataResponse+Crypto.h +// kordophoned +// +// Created by James Magahern on 11/15/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GCDWebServerDataResponse (Crypto) + ++ (nullable instancetype)encryptedResponseWithJSONObject:(id)object; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m b/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m new file mode 100644 index 0000000..99a76dd --- /dev/null +++ b/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m @@ -0,0 +1,36 @@ +// +// GCDWebServerDataResponse+Crypto.m +// kordophoned +// +// Created by James Magahern on 11/15/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "GCDWebServerDataResponse+Crypto.h" + +#import "NSData+AES.h" + +// TEMP!! +static NSString *const kSymmetricKey = @"axPy0nljtG/TOVJSVwVXag=="; + +@implementation GCDWebServerDataResponse (Crypto) + ++ (nullable instancetype)encryptedResponseWithJSONObject:(id)object +{ + NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL]; + if (data == nil) { + return nil; + } + + NSError *error = nil; + NSData *ivData = [[[NSUUID UUID] UUIDString] dataUsingEncoding:NSUTF8StringEncoding]; + NSData *keyData = [[NSData alloc] initWithBase64EncodedString:kSymmetricKey options:0]; + NSData *encryptedData = [data encryptedDataWithKey:keyData iv:ivData error:&error]; + if (error) { + NSLog(@"Error encrypting response: %@", error); + } + + return [[self alloc] initWithData:encryptedData contentType:@"application/octet-stream"]; +} + +@end From 5ced6151c2f00b4e9f57d542690c95b0cfbbf19a Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 15 Nov 2018 16:30:25 -0800 Subject: [PATCH 09/75] Some additional headers needed to decrypt the payload --- kordophone/Crypto/GCDWebServerDataResponse+Crypto.m | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m b/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m index 99a76dd..793b83a 100644 --- a/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m +++ b/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m @@ -30,7 +30,15 @@ static NSString *const kSymmetricKey = @"axPy0nljtG/TOVJSVwVXag=="; NSLog(@"Error encrypting response: %@", error); } - return [[self alloc] initWithData:encryptedData contentType:@"application/octet-stream"]; + NSString *ivDataString = [ivData base64EncodedStringWithOptions:0]; + + GCDWebServerDataResponse *response = [[self alloc] initWithData:encryptedData contentType:@"application/octet-stream"]; + [response setValue:ivDataString forAdditionalHeader:@"X-KordophoneCrypto-IV"]; + + // TODO: is this the right way?? + [response setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[data length]] forAdditionalHeader:@"X-Decrypted-Content-Length"]; + + return response; } @end From baffa7b03572926b9c3cfcaeaa58cdb5c880fae6 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 16 Nov 2018 01:30:38 -0800 Subject: [PATCH 10/75] Switches from GCDWebServer to CocoaHTTPServer so we can have HTTPS eventually --- .gitmodules | 3 + CocoaHTTPServer | 1 + MessagesBridge.xcodeproj/project.pbxproj | 620 +++++++++++++----- kordophone/Bridge/MBIMBridge.h | 3 +- kordophone/Bridge/MBIMBridge.m | 36 +- kordophone/Bridge/MBIMHTTPConnection.h | 13 + kordophone/Bridge/MBIMHTTPConnection.m | 70 ++ .../Bridge/Operations/MBIMBridgeOperation.h | 13 +- .../Bridge/Operations/MBIMBridgeOperation.m | 8 +- .../MBIMConversationListOperation.m | 5 +- .../Operations/MBIMMessagesListOperation.m | 13 +- .../Operations/MBIMSendMessageOperation.m | 21 +- .../Operations/Utilities/MBIMHTTPUtilities.h | 11 + .../Operations/Utilities/MBIMHTTPUtilities.m | 33 + .../Utilities/MBIMJSONDataResponse.h | 16 + .../Utilities/MBIMJSONDataResponse.m | 32 + .../Crypto/GCDWebServerDataResponse+Crypto.h | 20 - .../Crypto/GCDWebServerDataResponse+Crypto.m | 44 -- kordophone/Crypto/NSData+AES.h | 17 - kordophone/Crypto/NSData+AES.m | 58 -- 20 files changed, 692 insertions(+), 345 deletions(-) create mode 160000 CocoaHTTPServer create mode 100644 kordophone/Bridge/MBIMHTTPConnection.h create mode 100644 kordophone/Bridge/MBIMHTTPConnection.m create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m delete mode 100644 kordophone/Crypto/GCDWebServerDataResponse+Crypto.h delete mode 100644 kordophone/Crypto/GCDWebServerDataResponse+Crypto.m delete mode 100644 kordophone/Crypto/NSData+AES.h delete mode 100644 kordophone/Crypto/NSData+AES.m diff --git a/.gitmodules b/.gitmodules index cd77084..e374d4f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "logos"] path = logos url = git@github.com:theos/logos.git +[submodule "CocoaHTTPServer"] + path = CocoaHTTPServer + url = https://github.com/robbiehanson/CocoaHTTPServer.git diff --git a/CocoaHTTPServer b/CocoaHTTPServer new file mode 160000 index 0000000..52b2a64 --- /dev/null +++ b/CocoaHTTPServer @@ -0,0 +1 @@ +Subproject commit 52b2a64e9cbdb5f09cc915814a5fb68a45dd3707 diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index a86c464..d3e0f25 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -7,10 +7,70 @@ objects = { /* Begin PBXBuildFile section */ - CD14F185219E2A6800E7DD22 /* NSData+AES.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F184219E2A6800E7DD22 /* NSData+AES.m */; }; + 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */; }; + 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */; }; + 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */; }; + 1ACFCF26219EB2AC00E2C237 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCDFB219EB2AB00E2C237 /* Info.plist */; }; + 1ACFCF27219EB2AC00E2C237 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */; }; + 1ACFCF29219EB2AC00E2C237 /* README.markdown in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCDFE219EB2AB00E2C237 /* README.markdown */; }; + 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE01219EB2AB00E2C237 /* HTTPLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE02219EB2AB00E2C237 /* HTTPMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2D219EB2AC00E2C237 /* WebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE03219EB2AB00E2C237 /* WebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2E219EB2AC00E2C237 /* HTTPAuthenticationRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE04219EB2AB00E2C237 /* HTTPAuthenticationRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2F219EB2AC00E2C237 /* HTTPAsyncFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE06219EB2AB00E2C237 /* HTTPAsyncFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF30219EB2AC00E2C237 /* HTTPErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE07219EB2AB00E2C237 /* HTTPErrorResponse.m */; }; + 1ACFCF31219EB2AC00E2C237 /* HTTPDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE08219EB2AB00E2C237 /* HTTPDataResponse.m */; }; + 1ACFCF32219EB2AC00E2C237 /* HTTPRedirectResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE09219EB2AB00E2C237 /* HTTPRedirectResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF33219EB2AC00E2C237 /* HTTPDynamicFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0A219EB2AB00E2C237 /* HTTPDynamicFileResponse.m */; }; + 1ACFCF34219EB2AC00E2C237 /* HTTPFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0B219EB2AB00E2C237 /* HTTPFileResponse.m */; }; + 1ACFCF35219EB2AC00E2C237 /* HTTPAsyncFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0C219EB2AB00E2C237 /* HTTPAsyncFileResponse.m */; }; + 1ACFCF36219EB2AC00E2C237 /* HTTPRedirectResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0D219EB2AB00E2C237 /* HTTPRedirectResponse.m */; }; + 1ACFCF37219EB2AC00E2C237 /* HTTPDataResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE0E219EB2AB00E2C237 /* HTTPDataResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF38219EB2AC00E2C237 /* HTTPErrorResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE0F219EB2AB00E2C237 /* HTTPErrorResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF39219EB2AC00E2C237 /* HTTPFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE10219EB2AB00E2C237 /* HTTPFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF3A219EB2AC00E2C237 /* HTTPDynamicFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE11219EB2AB00E2C237 /* HTTPDynamicFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF3B219EB2AC00E2C237 /* HTTPServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE12219EB2AB00E2C237 /* HTTPServer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF3C219EB2AC00E2C237 /* HTTPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE13219EB2AB00E2C237 /* HTTPMessage.m */; }; + 1ACFCF3D219EB2AC00E2C237 /* HTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE14219EB2AB00E2C237 /* HTTPConnection.m */; }; + 1ACFCF3E219EB2AC00E2C237 /* WebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE15219EB2AB00E2C237 /* WebSocket.m */; }; + 1ACFCF3F219EB2AC00E2C237 /* HTTPResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE16219EB2AB00E2C237 /* HTTPResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF40219EB2AC00E2C237 /* MultipartFormDataParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE18219EB2AB00E2C237 /* MultipartFormDataParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF41219EB2AC00E2C237 /* MultipartMessageHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE19219EB2AB00E2C237 /* MultipartMessageHeader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF42219EB2AC00E2C237 /* MultipartMessageHeaderField.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1A219EB2AB00E2C237 /* MultipartMessageHeaderField.m */; }; + 1ACFCF43219EB2AC00E2C237 /* MultipartFormDataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1B219EB2AB00E2C237 /* MultipartFormDataParser.m */; }; + 1ACFCF44219EB2AC00E2C237 /* MultipartMessageHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1C219EB2AB00E2C237 /* MultipartMessageHeader.m */; }; + 1ACFCF45219EB2AC00E2C237 /* MultipartMessageHeaderField.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE1D219EB2AB00E2C237 /* MultipartMessageHeaderField.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF46219EB2AC00E2C237 /* HTTPAuthenticationRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1E219EB2AB00E2C237 /* HTTPAuthenticationRequest.m */; }; + 1ACFCF47219EB2AC00E2C237 /* DDNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE20219EB2AB00E2C237 /* DDNumber.m */; }; + 1ACFCF48219EB2AC00E2C237 /* DDData.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE21219EB2AB00E2C237 /* DDData.m */; }; + 1ACFCF49219EB2AC00E2C237 /* DDRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE22219EB2AB00E2C237 /* DDRange.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF4A219EB2AC00E2C237 /* DDNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE23219EB2AB00E2C237 /* DDNumber.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF4B219EB2AC00E2C237 /* DDRange.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE24219EB2AB00E2C237 /* DDRange.m */; }; + 1ACFCF4C219EB2AC00E2C237 /* DDData.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE25219EB2AB00E2C237 /* DDData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF4D219EB2AC00E2C237 /* HTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE26219EB2AB00E2C237 /* HTTPServer.m */; }; + 1ACFCFCA219EB2AC00E2C237 /* DDTTYLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF09219EB2AC00E2C237 /* DDTTYLogger.m */; }; + 1ACFCFCB219EB2AC00E2C237 /* DDLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0A219EB2AC00E2C237 /* DDLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFCC219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0B219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFCD219EB2AC00E2C237 /* DDASLLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF0C219EB2AC00E2C237 /* DDASLLogger.m */; }; + 1ACFCFCE219EB2AC00E2C237 /* DDFileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0D219EB2AC00E2C237 /* DDFileLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFCF219EB2AC00E2C237 /* ContextFilterLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0F219EB2AC00E2C237 /* ContextFilterLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFD0219EB2AC00E2C237 /* DispatchQueueLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF10219EB2AC00E2C237 /* DispatchQueueLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFD1219EB2AC00E2C237 /* ContextFilterLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF11219EB2AC00E2C237 /* ContextFilterLogFormatter.m */; }; + 1ACFCFD2219EB2AC00E2C237 /* DispatchQueueLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF12219EB2AC00E2C237 /* DispatchQueueLogFormatter.m */; }; + 1ACFCFD3219EB2AC00E2C237 /* README.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCF13219EB2AC00E2C237 /* README.txt */; }; + 1ACFCFD4219EB2AC00E2C237 /* DDLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF14219EB2AC00E2C237 /* DDLog.m */; }; + 1ACFCFD5219EB2AC00E2C237 /* About.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCF15219EB2AC00E2C237 /* About.txt */; }; + 1ACFCFD6219EB2AC00E2C237 /* DDTTYLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF16219EB2AC00E2C237 /* DDTTYLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFD7219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF17219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m */; }; + 1ACFCFD8219EB2AC00E2C237 /* DDFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF18219EB2AC00E2C237 /* DDFileLogger.m */; }; + 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF19219EB2AC00E2C237 /* DDASLLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFDA219EB2AC00E2C237 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */; }; + 1ACFCFDB219EB2AC00E2C237 /* About.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1C219EB2AC00E2C237 /* About.txt */; }; + 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */; }; + 1ACFCFE1219EB37000E2C237 /* CocoaHTTPServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCFE0219EB37000E2C237 /* CocoaHTTPServer.h */; settings = {ATTRIBUTES = (Public, ); }; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; - CD14F194219E2F9C00E7DD22 /* NSData+AES.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F184219E2A6800E7DD22 /* NSData+AES.m */; }; - CD14F19E219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F19D219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m */; }; CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */; }; CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */; }; @@ -22,11 +82,17 @@ CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */; }; CDF6233D219A8AF700690038 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C445F219A45B400F2AC00 /* Foundation.framework */; }; CDF6233E219A8AFC00690038 /* IMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4467219A45D500F2AC00 /* IMCore.framework */; }; - CDF6233F219A8B0100690038 /* GCDWebServers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDF62324219A869000690038 /* GCDWebServers.framework */; }; CDF62343219A9BE200690038 /* ContactsFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDF62342219A9BE200690038 /* ContactsFoundation.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 1ACFCFDD219EB30E00E2C237 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1A0C443F219A38E100F2AC00 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1ACFCDE1219EB28A00E2C237; + remoteInfo = CocoaHTTPServer; + }; CD83E16A219BE9AB00F4CCEA /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1A0C443F219A38E100F2AC00 /* Project object */; @@ -34,62 +100,6 @@ remoteGlobalIDString = CD83E160219BE91500F4CCEA; remoteInfo = agentHook; }; - CDF6231D219A869000690038 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 8DD76FB20486AB0100D96B5E; - remoteInfo = "GCDWebServer (Mac)"; - }; - CDF6231F219A869000690038 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = E2DDD1F61BE69EE4002CE867; - remoteInfo = "GCDWebServer (iOS)"; - }; - CDF62321219A869000690038 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = E2DDD1C71BE698A8002CE867; - remoteInfo = "GCDWebServer (tvOS)"; - }; - CDF62323219A869000690038 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = CEE28CD11AE004D800F4023C; - remoteInfo = "GCDWebServers (Mac)"; - }; - CDF62325219A869000690038 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = CEE28CEF1AE0051F00F4023C; - remoteInfo = "GCDWebServers (iOS)"; - }; - CDF62327219A869000690038 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = E2DDD18B1BE69404002CE867; - remoteInfo = "GCDWebServers (tvOS)"; - }; - CDF62329219A869000690038 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = E24039251BA09207000B7089; - remoteInfo = "Tests (Mac)"; - }; - CDF6233B219A8A6600690038 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = CEE28CD01AE004D800F4023C; - remoteInfo = "GCDWebServers (Mac)"; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -118,13 +128,76 @@ 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OSXDebugDefaults.xcconfig; sourceTree = ""; }; 1A33B43D219A5ACD0034485A /* ReleaseDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseDefaults.xcconfig; sourceTree = ""; }; 1A33B43E219A5BD80034485A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - CD14F183219E2A6800E7DD22 /* NSData+AES.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+AES.h"; sourceTree = ""; }; - CD14F184219E2A6800E7DD22 /* NSData+AES.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+AES.m"; sourceTree = ""; }; + 1AA43E8D219EBB2D00EDF1A7 /* MBIMJSONDataResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMJSONDataResponse.h; sourceTree = ""; }; + 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMJSONDataResponse.m; sourceTree = ""; }; + 1AA43E93219EC38E00EDF1A7 /* MBIMHTTPUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMHTTPUtilities.h; sourceTree = ""; }; + 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMHTTPUtilities.m; sourceTree = ""; }; + 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CocoaHTTPServer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1ACFCDE5219EB28A00E2C237 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1ACFCDFB219EB2AB00E2C237 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; + 1ACFCDFE219EB2AB00E2C237 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = ""; }; + 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPConnection.h; sourceTree = ""; }; + 1ACFCE01219EB2AB00E2C237 /* HTTPLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPLogging.h; sourceTree = ""; }; + 1ACFCE02219EB2AB00E2C237 /* HTTPMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPMessage.h; sourceTree = ""; }; + 1ACFCE03219EB2AB00E2C237 /* WebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocket.h; sourceTree = ""; }; + 1ACFCE04219EB2AB00E2C237 /* HTTPAuthenticationRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPAuthenticationRequest.h; sourceTree = ""; }; + 1ACFCE06219EB2AB00E2C237 /* HTTPAsyncFileResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPAsyncFileResponse.h; sourceTree = ""; }; + 1ACFCE07219EB2AB00E2C237 /* HTTPErrorResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPErrorResponse.m; sourceTree = ""; }; + 1ACFCE08219EB2AB00E2C237 /* HTTPDataResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPDataResponse.m; sourceTree = ""; }; + 1ACFCE09219EB2AB00E2C237 /* HTTPRedirectResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPRedirectResponse.h; sourceTree = ""; }; + 1ACFCE0A219EB2AB00E2C237 /* HTTPDynamicFileResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPDynamicFileResponse.m; sourceTree = ""; }; + 1ACFCE0B219EB2AB00E2C237 /* HTTPFileResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPFileResponse.m; sourceTree = ""; }; + 1ACFCE0C219EB2AB00E2C237 /* HTTPAsyncFileResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPAsyncFileResponse.m; sourceTree = ""; }; + 1ACFCE0D219EB2AB00E2C237 /* HTTPRedirectResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPRedirectResponse.m; sourceTree = ""; }; + 1ACFCE0E219EB2AB00E2C237 /* HTTPDataResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPDataResponse.h; sourceTree = ""; }; + 1ACFCE0F219EB2AB00E2C237 /* HTTPErrorResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPErrorResponse.h; sourceTree = ""; }; + 1ACFCE10219EB2AB00E2C237 /* HTTPFileResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPFileResponse.h; sourceTree = ""; }; + 1ACFCE11219EB2AB00E2C237 /* HTTPDynamicFileResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPDynamicFileResponse.h; sourceTree = ""; }; + 1ACFCE12219EB2AB00E2C237 /* HTTPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPServer.h; sourceTree = ""; }; + 1ACFCE13219EB2AB00E2C237 /* HTTPMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPMessage.m; sourceTree = ""; }; + 1ACFCE14219EB2AB00E2C237 /* HTTPConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPConnection.m; sourceTree = ""; }; + 1ACFCE15219EB2AB00E2C237 /* WebSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebSocket.m; sourceTree = ""; }; + 1ACFCE16219EB2AB00E2C237 /* HTTPResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPResponse.h; sourceTree = ""; }; + 1ACFCE18219EB2AB00E2C237 /* MultipartFormDataParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultipartFormDataParser.h; sourceTree = ""; }; + 1ACFCE19219EB2AB00E2C237 /* MultipartMessageHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultipartMessageHeader.h; sourceTree = ""; }; + 1ACFCE1A219EB2AB00E2C237 /* MultipartMessageHeaderField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MultipartMessageHeaderField.m; sourceTree = ""; }; + 1ACFCE1B219EB2AB00E2C237 /* MultipartFormDataParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MultipartFormDataParser.m; sourceTree = ""; }; + 1ACFCE1C219EB2AB00E2C237 /* MultipartMessageHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MultipartMessageHeader.m; sourceTree = ""; }; + 1ACFCE1D219EB2AB00E2C237 /* MultipartMessageHeaderField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultipartMessageHeaderField.h; sourceTree = ""; }; + 1ACFCE1E219EB2AB00E2C237 /* HTTPAuthenticationRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPAuthenticationRequest.m; sourceTree = ""; }; + 1ACFCE20219EB2AB00E2C237 /* DDNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDNumber.m; sourceTree = ""; }; + 1ACFCE21219EB2AB00E2C237 /* DDData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDData.m; sourceTree = ""; }; + 1ACFCE22219EB2AB00E2C237 /* DDRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDRange.h; sourceTree = ""; }; + 1ACFCE23219EB2AB00E2C237 /* DDNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDNumber.h; sourceTree = ""; }; + 1ACFCE24219EB2AB00E2C237 /* DDRange.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDRange.m; sourceTree = ""; }; + 1ACFCE25219EB2AB00E2C237 /* DDData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDData.h; sourceTree = ""; }; + 1ACFCE26219EB2AB00E2C237 /* HTTPServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPServer.m; sourceTree = ""; }; + 1ACFCF09219EB2AC00E2C237 /* DDTTYLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDTTYLogger.m; sourceTree = ""; }; + 1ACFCF0A219EB2AC00E2C237 /* DDLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDLog.h; sourceTree = ""; }; + 1ACFCF0B219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDAbstractDatabaseLogger.h; sourceTree = ""; }; + 1ACFCF0C219EB2AC00E2C237 /* DDASLLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDASLLogger.m; sourceTree = ""; }; + 1ACFCF0D219EB2AC00E2C237 /* DDFileLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDFileLogger.h; sourceTree = ""; }; + 1ACFCF0F219EB2AC00E2C237 /* ContextFilterLogFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContextFilterLogFormatter.h; sourceTree = ""; }; + 1ACFCF10219EB2AC00E2C237 /* DispatchQueueLogFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DispatchQueueLogFormatter.h; sourceTree = ""; }; + 1ACFCF11219EB2AC00E2C237 /* ContextFilterLogFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContextFilterLogFormatter.m; sourceTree = ""; }; + 1ACFCF12219EB2AC00E2C237 /* DispatchQueueLogFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DispatchQueueLogFormatter.m; sourceTree = ""; }; + 1ACFCF13219EB2AC00E2C237 /* README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.txt; sourceTree = ""; }; + 1ACFCF14219EB2AC00E2C237 /* DDLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDLog.m; sourceTree = ""; }; + 1ACFCF15219EB2AC00E2C237 /* About.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = About.txt; sourceTree = ""; }; + 1ACFCF16219EB2AC00E2C237 /* DDTTYLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDTTYLogger.h; sourceTree = ""; }; + 1ACFCF17219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDAbstractDatabaseLogger.m; sourceTree = ""; }; + 1ACFCF18219EB2AC00E2C237 /* DDFileLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDFileLogger.m; sourceTree = ""; }; + 1ACFCF19219EB2AC00E2C237 /* DDASLLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDASLLogger.h; sourceTree = ""; }; + 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncSocket.m; sourceTree = ""; }; + 1ACFCF1C219EB2AC00E2C237 /* About.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = About.txt; sourceTree = ""; }; + 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocket.h; sourceTree = ""; }; + 1ACFCFE0219EB37000E2C237 /* CocoaHTTPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CocoaHTTPServer.h; sourceTree = ""; }; + 1ACFCFE2219EB45300E2C237 /* MBIMHTTPConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMHTTPConnection.h; sourceTree = ""; }; + 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMHTTPConnection.m; sourceTree = ""; }; CD14F18B219E2DB400E7DD22 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CD14F18D219E2DB400E7DD22 /* CryptoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoTests.m; sourceTree = ""; }; CD14F18F219E2DB400E7DD22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - CD14F19C219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "GCDWebServerDataResponse+Crypto.h"; sourceTree = ""; }; - CD14F19D219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "GCDWebServerDataResponse+Crypto.m"; sourceTree = ""; }; CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridgeOperation.h; sourceTree = ""; }; CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridgeOperation.m; sourceTree = ""; }; CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMMessagesListOperation.h; sourceTree = ""; }; @@ -138,7 +211,6 @@ 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 = ""; }; - CDF62312219A869000690038 /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = GCDWebServer/GCDWebServer.xcodeproj; 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; }; @@ -146,6 +218,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 1ACFCDDE219EB28A00E2C237 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD14F188219E2DB400E7DD22 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -164,8 +243,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */, CDF62343219A9BE200690038 /* ContactsFoundation.framework in Frameworks */, - CDF6233F219A8B0100690038 /* GCDWebServers.framework in Frameworks */, CDF6233E219A8AFC00690038 /* IMCore.framework in Frameworks */, CDF6233D219A8AF700690038 /* Foundation.framework in Frameworks */, ); @@ -178,12 +257,12 @@ isa = PBXGroup; children = ( 1A33B43E219A5BD80034485A /* README.md */, - CDF62312219A869000690038 /* GCDWebServer.xcodeproj */, CDF62333219A895D00690038 /* kordophone */, 1A33B439219A5ACD0034485A /* Config Files */, 1A0C445C219A457C00F2AC00 /* Pilfered Headers */, CD83E162219BE91600F4CCEA /* agentHook */, CD14F18C219E2DB400E7DD22 /* Tests */, + 1ACFCDE3219EB28A00E2C237 /* CocoaHTTPServer */, 1A0C4448219A38E100F2AC00 /* Products */, 1A0C445E219A45B400F2AC00 /* Frameworks */, ); @@ -195,6 +274,7 @@ CDF62332219A895D00690038 /* kordophoned */, CD83E161219BE91500F4CCEA /* libagentHook.dylib */, CD14F18B219E2DB400E7DD22 /* Tests.xctest */, + 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */, ); name = Products; sourceTree = ""; @@ -227,6 +307,8 @@ CD60204C219B5D710024D9C5 /* Operations */, 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */, 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */, + 1ACFCFE2219EB45300E2C237 /* MBIMHTTPConnection.h */, + 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */, ); path = Bridge; sourceTree = ""; @@ -242,15 +324,146 @@ path = "Config Files"; sourceTree = ""; }; - CD14F182219E2A4C00E7DD22 /* Crypto */ = { + 1AA43E90219EBB3400EDF1A7 /* Utilities */ = { isa = PBXGroup; children = ( - CD14F183219E2A6800E7DD22 /* NSData+AES.h */, - CD14F184219E2A6800E7DD22 /* NSData+AES.m */, - CD14F19C219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.h */, - CD14F19D219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m */, + 1AA43E8D219EBB2D00EDF1A7 /* MBIMJSONDataResponse.h */, + 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */, + 1AA43E93219EC38E00EDF1A7 /* MBIMHTTPUtilities.h */, + 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */, ); - path = Crypto; + path = Utilities; + sourceTree = ""; + }; + 1ACFCDE3219EB28A00E2C237 /* CocoaHTTPServer */ = { + isa = PBXGroup; + children = ( + 1ACFCFE0219EB37000E2C237 /* CocoaHTTPServer.h */, + 1ACFCDFF219EB2AB00E2C237 /* Core */, + 1ACFCDFB219EB2AB00E2C237 /* Info.plist */, + 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */, + 1ACFCDFE219EB2AB00E2C237 /* README.markdown */, + 1ACFCF07219EB2AC00E2C237 /* Vendor */, + 1ACFCDE5219EB28A00E2C237 /* Info.plist */, + ); + path = CocoaHTTPServer; + sourceTree = ""; + }; + 1ACFCDFF219EB2AB00E2C237 /* Core */ = { + isa = PBXGroup; + children = ( + 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */, + 1ACFCE01219EB2AB00E2C237 /* HTTPLogging.h */, + 1ACFCE02219EB2AB00E2C237 /* HTTPMessage.h */, + 1ACFCE03219EB2AB00E2C237 /* WebSocket.h */, + 1ACFCE04219EB2AB00E2C237 /* HTTPAuthenticationRequest.h */, + 1ACFCE05219EB2AB00E2C237 /* Responses */, + 1ACFCE12219EB2AB00E2C237 /* HTTPServer.h */, + 1ACFCE13219EB2AB00E2C237 /* HTTPMessage.m */, + 1ACFCE14219EB2AB00E2C237 /* HTTPConnection.m */, + 1ACFCE15219EB2AB00E2C237 /* WebSocket.m */, + 1ACFCE16219EB2AB00E2C237 /* HTTPResponse.h */, + 1ACFCE17219EB2AB00E2C237 /* Mime */, + 1ACFCE1E219EB2AB00E2C237 /* HTTPAuthenticationRequest.m */, + 1ACFCE1F219EB2AB00E2C237 /* Categories */, + 1ACFCE26219EB2AB00E2C237 /* HTTPServer.m */, + ); + path = Core; + sourceTree = ""; + }; + 1ACFCE05219EB2AB00E2C237 /* Responses */ = { + isa = PBXGroup; + children = ( + 1ACFCE06219EB2AB00E2C237 /* HTTPAsyncFileResponse.h */, + 1ACFCE07219EB2AB00E2C237 /* HTTPErrorResponse.m */, + 1ACFCE08219EB2AB00E2C237 /* HTTPDataResponse.m */, + 1ACFCE09219EB2AB00E2C237 /* HTTPRedirectResponse.h */, + 1ACFCE0A219EB2AB00E2C237 /* HTTPDynamicFileResponse.m */, + 1ACFCE0B219EB2AB00E2C237 /* HTTPFileResponse.m */, + 1ACFCE0C219EB2AB00E2C237 /* HTTPAsyncFileResponse.m */, + 1ACFCE0D219EB2AB00E2C237 /* HTTPRedirectResponse.m */, + 1ACFCE0E219EB2AB00E2C237 /* HTTPDataResponse.h */, + 1ACFCE0F219EB2AB00E2C237 /* HTTPErrorResponse.h */, + 1ACFCE10219EB2AB00E2C237 /* HTTPFileResponse.h */, + 1ACFCE11219EB2AB00E2C237 /* HTTPDynamicFileResponse.h */, + ); + path = Responses; + sourceTree = ""; + }; + 1ACFCE17219EB2AB00E2C237 /* Mime */ = { + isa = PBXGroup; + children = ( + 1ACFCE18219EB2AB00E2C237 /* MultipartFormDataParser.h */, + 1ACFCE19219EB2AB00E2C237 /* MultipartMessageHeader.h */, + 1ACFCE1A219EB2AB00E2C237 /* MultipartMessageHeaderField.m */, + 1ACFCE1B219EB2AB00E2C237 /* MultipartFormDataParser.m */, + 1ACFCE1C219EB2AB00E2C237 /* MultipartMessageHeader.m */, + 1ACFCE1D219EB2AB00E2C237 /* MultipartMessageHeaderField.h */, + ); + path = Mime; + sourceTree = ""; + }; + 1ACFCE1F219EB2AB00E2C237 /* Categories */ = { + isa = PBXGroup; + children = ( + 1ACFCE20219EB2AB00E2C237 /* DDNumber.m */, + 1ACFCE21219EB2AB00E2C237 /* DDData.m */, + 1ACFCE22219EB2AB00E2C237 /* DDRange.h */, + 1ACFCE23219EB2AB00E2C237 /* DDNumber.h */, + 1ACFCE24219EB2AB00E2C237 /* DDRange.m */, + 1ACFCE25219EB2AB00E2C237 /* DDData.h */, + ); + path = Categories; + sourceTree = ""; + }; + 1ACFCF07219EB2AC00E2C237 /* Vendor */ = { + isa = PBXGroup; + children = ( + 1ACFCF08219EB2AC00E2C237 /* CocoaLumberjack */, + 1ACFCF1A219EB2AC00E2C237 /* CocoaAsyncSocket */, + ); + path = Vendor; + sourceTree = ""; + }; + 1ACFCF08219EB2AC00E2C237 /* CocoaLumberjack */ = { + isa = PBXGroup; + children = ( + 1ACFCF09219EB2AC00E2C237 /* DDTTYLogger.m */, + 1ACFCF0A219EB2AC00E2C237 /* DDLog.h */, + 1ACFCF0B219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h */, + 1ACFCF0C219EB2AC00E2C237 /* DDASLLogger.m */, + 1ACFCF0D219EB2AC00E2C237 /* DDFileLogger.h */, + 1ACFCF0E219EB2AC00E2C237 /* Extensions */, + 1ACFCF14219EB2AC00E2C237 /* DDLog.m */, + 1ACFCF15219EB2AC00E2C237 /* About.txt */, + 1ACFCF16219EB2AC00E2C237 /* DDTTYLogger.h */, + 1ACFCF17219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m */, + 1ACFCF18219EB2AC00E2C237 /* DDFileLogger.m */, + 1ACFCF19219EB2AC00E2C237 /* DDASLLogger.h */, + ); + path = CocoaLumberjack; + sourceTree = ""; + }; + 1ACFCF0E219EB2AC00E2C237 /* Extensions */ = { + isa = PBXGroup; + children = ( + 1ACFCF0F219EB2AC00E2C237 /* ContextFilterLogFormatter.h */, + 1ACFCF10219EB2AC00E2C237 /* DispatchQueueLogFormatter.h */, + 1ACFCF11219EB2AC00E2C237 /* ContextFilterLogFormatter.m */, + 1ACFCF12219EB2AC00E2C237 /* DispatchQueueLogFormatter.m */, + 1ACFCF13219EB2AC00E2C237 /* README.txt */, + ); + path = Extensions; + sourceTree = ""; + }; + 1ACFCF1A219EB2AC00E2C237 /* CocoaAsyncSocket */ = { + isa = PBXGroup; + children = ( + 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */, + 1ACFCF1C219EB2AC00E2C237 /* About.txt */, + 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */, + ); + path = CocoaAsyncSocket; sourceTree = ""; }; CD14F18C219E2DB400E7DD22 /* Tests */ = { @@ -265,6 +478,7 @@ CD60204C219B5D710024D9C5 /* Operations */ = { isa = PBXGroup; children = ( + 1AA43E90219EBB3400EDF1A7 /* Utilities */, CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */, CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */, CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */, @@ -295,24 +509,9 @@ path = agentHook; sourceTree = ""; }; - CDF62313219A869000690038 /* Products */ = { - isa = PBXGroup; - children = ( - CDF6231E219A869000690038 /* GCDWebServer */, - CDF62320219A869000690038 /* GCDWebServer.app */, - CDF62322219A869000690038 /* GCDWebServer.app */, - CDF62324219A869000690038 /* GCDWebServers.framework */, - CDF62326219A869000690038 /* GCDWebServers.framework */, - CDF62328219A869000690038 /* GCDWebServers.framework */, - CDF6232A219A869000690038 /* Tests.xctest */, - ); - name = Products; - sourceTree = ""; - }; CDF62333219A895D00690038 /* kordophone */ = { isa = PBXGroup; children = ( - CD14F182219E2A4C00E7DD22 /* Crypto */, CD83E150219BDB4F00F4CCEA /* Hooking */, 1A0C446D219A4BCD00F2AC00 /* Bridge */, CDF62334219A895D00690038 /* main.m */, @@ -323,6 +522,41 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 1ACFCDDF219EB28A00E2C237 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 1ACFCFCB219EB2AC00E2C237 /* DDLog.h in Headers */, + 1ACFCF40219EB2AC00E2C237 /* MultipartFormDataParser.h in Headers */, + 1ACFCF2F219EB2AC00E2C237 /* HTTPAsyncFileResponse.h in Headers */, + 1ACFCF37219EB2AC00E2C237 /* HTTPDataResponse.h in Headers */, + 1ACFCF45219EB2AC00E2C237 /* MultipartMessageHeaderField.h in Headers */, + 1ACFCF3A219EB2AC00E2C237 /* HTTPDynamicFileResponse.h in Headers */, + 1ACFCFCC219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h in Headers */, + 1ACFCFD6219EB2AC00E2C237 /* DDTTYLogger.h in Headers */, + 1ACFCF4C219EB2AC00E2C237 /* DDData.h in Headers */, + 1ACFCF2D219EB2AC00E2C237 /* WebSocket.h in Headers */, + 1ACFCF49219EB2AC00E2C237 /* DDRange.h in Headers */, + 1ACFCF32219EB2AC00E2C237 /* HTTPRedirectResponse.h in Headers */, + 1ACFCF2E219EB2AC00E2C237 /* HTTPAuthenticationRequest.h in Headers */, + 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */, + 1ACFCF4A219EB2AC00E2C237 /* DDNumber.h in Headers */, + 1ACFCFE1219EB37000E2C237 /* CocoaHTTPServer.h in Headers */, + 1ACFCF3F219EB2AC00E2C237 /* HTTPResponse.h in Headers */, + 1ACFCF39219EB2AC00E2C237 /* HTTPFileResponse.h in Headers */, + 1ACFCFCF219EB2AC00E2C237 /* ContextFilterLogFormatter.h in Headers */, + 1ACFCF3B219EB2AC00E2C237 /* HTTPServer.h in Headers */, + 1ACFCF41219EB2AC00E2C237 /* MultipartMessageHeader.h in Headers */, + 1ACFCF38219EB2AC00E2C237 /* HTTPErrorResponse.h in Headers */, + 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */, + 1ACFCFD0219EB2AC00E2C237 /* DispatchQueueLogFormatter.h in Headers */, + 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */, + 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */, + 1ACFCFCE219EB2AC00E2C237 /* DDFileLogger.h in Headers */, + 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD83E15D219BE91500F4CCEA /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -333,6 +567,24 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 1ACFCDE1219EB28A00E2C237 /* CocoaHTTPServer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1ACFCDF0219EB28A00E2C237 /* Build configuration list for PBXNativeTarget "CocoaHTTPServer" */; + buildPhases = ( + 1ACFCDDD219EB28A00E2C237 /* Sources */, + 1ACFCDDE219EB28A00E2C237 /* Frameworks */, + 1ACFCDDF219EB28A00E2C237 /* Headers */, + 1ACFCDE0219EB28A00E2C237 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CocoaHTTPServer; + productName = CocoaHTTPServer; + productReference = 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */; + productType = "com.apple.product-type.framework"; + }; CD14F18A219E2DB400E7DD22 /* Tests */ = { isa = PBXNativeTarget; buildConfigurationList = CD14F190219E2DB400E7DD22 /* Build configuration list for PBXNativeTarget "Tests" */; @@ -378,8 +630,8 @@ buildRules = ( ); dependencies = ( + 1ACFCFDE219EB30E00E2C237 /* PBXTargetDependency */, CD83E16B219BE9AB00F4CCEA /* PBXTargetDependency */, - CDF6233C219A8A6600690038 /* PBXTargetDependency */, ); name = kordophoned; productName = kordophone; @@ -395,6 +647,9 @@ LastUpgradeCheck = 1100; ORGANIZATIONNAME = "James Magahern"; TargetAttributes = { + 1ACFCDE1219EB28A00E2C237 = { + CreatedOnToolsVersion = 9.3; + }; CD14F18A219E2DB400E7DD22 = { CreatedOnToolsVersion = 11.0; }; @@ -413,78 +668,35 @@ knownRegions = ( en, Base, + English, ); mainGroup = 1A0C443E219A38E100F2AC00; productRefGroup = 1A0C4448219A38E100F2AC00 /* Products */; projectDirPath = ""; - projectReferences = ( - { - ProductGroup = CDF62313219A869000690038 /* Products */; - ProjectRef = CDF62312219A869000690038 /* GCDWebServer.xcodeproj */; - }, - ); projectRoot = ""; targets = ( CDF62331219A895D00690038 /* kordophoned */, CD83E160219BE91500F4CCEA /* agentHook */, CD14F18A219E2DB400E7DD22 /* Tests */, + 1ACFCDE1219EB28A00E2C237 /* CocoaHTTPServer */, ); }; /* End PBXProject section */ -/* Begin PBXReferenceProxy section */ - CDF6231E219A869000690038 /* GCDWebServer */ = { - isa = PBXReferenceProxy; - fileType = "compiled.mach-o.executable"; - path = GCDWebServer; - remoteRef = CDF6231D219A869000690038 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CDF62320219A869000690038 /* GCDWebServer.app */ = { - isa = PBXReferenceProxy; - fileType = wrapper.application; - path = GCDWebServer.app; - remoteRef = CDF6231F219A869000690038 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CDF62322219A869000690038 /* GCDWebServer.app */ = { - isa = PBXReferenceProxy; - fileType = wrapper.application; - path = GCDWebServer.app; - remoteRef = CDF62321219A869000690038 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CDF62324219A869000690038 /* GCDWebServers.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = GCDWebServers.framework; - remoteRef = CDF62323219A869000690038 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CDF62326219A869000690038 /* GCDWebServers.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = GCDWebServers.framework; - remoteRef = CDF62325219A869000690038 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CDF62328219A869000690038 /* GCDWebServers.framework */ = { - isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = GCDWebServers.framework; - remoteRef = CDF62327219A869000690038 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - CDF6232A219A869000690038 /* Tests.xctest */ = { - isa = PBXReferenceProxy; - fileType = wrapper.cfbundle; - path = Tests.xctest; - remoteRef = CDF62329219A869000690038 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - /* Begin PBXResourcesBuildPhase section */ + 1ACFCDE0219EB28A00E2C237 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1ACFCFD5219EB2AC00E2C237 /* About.txt in Resources */, + 1ACFCFD3219EB2AC00E2C237 /* README.txt in Resources */, + 1ACFCF27219EB2AC00E2C237 /* LICENSE.txt in Resources */, + 1ACFCFDB219EB2AC00E2C237 /* About.txt in Resources */, + 1ACFCF26219EB2AC00E2C237 /* Info.plist in Resources */, + 1ACFCF29219EB2AC00E2C237 /* README.markdown in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD14F189219E2DB400E7DD22 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -495,11 +707,42 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 1ACFCDDD219EB28A00E2C237 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1ACFCFD1219EB2AC00E2C237 /* ContextFilterLogFormatter.m in Sources */, + 1ACFCF3E219EB2AC00E2C237 /* WebSocket.m in Sources */, + 1ACFCFD4219EB2AC00E2C237 /* DDLog.m in Sources */, + 1ACFCF30219EB2AC00E2C237 /* HTTPErrorResponse.m in Sources */, + 1ACFCFD7219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m in Sources */, + 1ACFCFD2219EB2AC00E2C237 /* DispatchQueueLogFormatter.m in Sources */, + 1ACFCF47219EB2AC00E2C237 /* DDNumber.m in Sources */, + 1ACFCF44219EB2AC00E2C237 /* MultipartMessageHeader.m in Sources */, + 1ACFCF4B219EB2AC00E2C237 /* DDRange.m in Sources */, + 1ACFCF31219EB2AC00E2C237 /* HTTPDataResponse.m in Sources */, + 1ACFCF34219EB2AC00E2C237 /* HTTPFileResponse.m in Sources */, + 1ACFCFCA219EB2AC00E2C237 /* DDTTYLogger.m in Sources */, + 1ACFCF48219EB2AC00E2C237 /* DDData.m in Sources */, + 1ACFCF33219EB2AC00E2C237 /* HTTPDynamicFileResponse.m in Sources */, + 1ACFCF4D219EB2AC00E2C237 /* HTTPServer.m in Sources */, + 1ACFCF42219EB2AC00E2C237 /* MultipartMessageHeaderField.m in Sources */, + 1ACFCF43219EB2AC00E2C237 /* MultipartFormDataParser.m in Sources */, + 1ACFCF3D219EB2AC00E2C237 /* HTTPConnection.m in Sources */, + 1ACFCFDA219EB2AC00E2C237 /* GCDAsyncSocket.m in Sources */, + 1ACFCFCD219EB2AC00E2C237 /* DDASLLogger.m in Sources */, + 1ACFCFD8219EB2AC00E2C237 /* DDFileLogger.m in Sources */, + 1ACFCF36219EB2AC00E2C237 /* HTTPRedirectResponse.m in Sources */, + 1ACFCF3C219EB2AC00E2C237 /* HTTPMessage.m in Sources */, + 1ACFCF46219EB2AC00E2C237 /* HTTPAuthenticationRequest.m in Sources */, + 1ACFCF35219EB2AC00E2C237 /* HTTPAsyncFileResponse.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD14F187219E2DB400E7DD22 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - CD14F194219E2F9C00E7DD22 /* NSData+AES.m in Sources */, CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -516,32 +759,33 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */, CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, + 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */, CD83E156219BE10A00F4CCEA /* hooking.m in Sources */, CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, CDF62335219A895D00690038 /* main.m in Sources */, CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */, - CD14F185219E2A6800E7DD22 /* NSData+AES.m in Sources */, - CD14F19E219E306C00E7DD22 /* GCDWebServerDataResponse+Crypto.m in Sources */, CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */, CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, + 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 1ACFCFDE219EB30E00E2C237 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1ACFCDE1219EB28A00E2C237 /* CocoaHTTPServer */; + targetProxy = 1ACFCFDD219EB30E00E2C237 /* PBXContainerItemProxy */; + }; CD83E16B219BE9AB00F4CCEA /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = CD83E160219BE91500F4CCEA /* agentHook */; targetProxy = CD83E16A219BE9AB00F4CCEA /* PBXContainerItemProxy */; }; - CDF6233C219A8A6600690038 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = "GCDWebServers (Mac)"; - targetProxy = CDF6233B219A8A6600690038 /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -664,6 +908,63 @@ }; name = Release; }; + 1ACFCDE7219EB28A00E2C237 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = CocoaHTTPServer/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.github.CocoaHTTPServer; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 1ACFCDE8219EB28A00E2C237 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = CocoaHTTPServer/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.github.CocoaHTTPServer; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; CD14F191219E2DB400E7DD22 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -772,6 +1073,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 1ACFCDF0219EB28A00E2C237 /* Build configuration list for PBXNativeTarget "CocoaHTTPServer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1ACFCDE7219EB28A00E2C237 /* Debug */, + 1ACFCDE8219EB28A00E2C237 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; CD14F190219E2DB400E7DD22 /* Build configuration list for PBXNativeTarget "Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/kordophone/Bridge/MBIMBridge.h b/kordophone/Bridge/MBIMBridge.h index ce00681..a6a5572 100644 --- a/kordophone/Bridge/MBIMBridge.h +++ b/kordophone/Bridge/MBIMBridge.h @@ -14,7 +14,8 @@ NS_ASSUME_NONNULL_BEGIN @interface MBIMBridge : NSObject -@property (nonatomic, assign) const char *dylibPath; +@property (nonatomic, assign) const char *dylibPath; +@property (nonatomic, readonly) NSOperationQueue *operationQueue; + (instancetype)sharedInstance; diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index 348143c..76b74fc 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -8,9 +8,10 @@ #import "MBIMBridge.h" #import "MBIMBridgeOperation.h" +#import "MBIMHTTPConnection.h" #import "hooking.h" -#import +#import #import #import @@ -21,7 +22,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; @interface MBIMBridge (/* INTERNAL */) -@property (nonatomic, strong) GCDWebServer *webServer; +@property (nonatomic, strong) HTTPServer *httpServer; @property (nonatomic, strong) NSOperationQueue *operationQueue; - (instancetype)_init; @@ -130,33 +131,16 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; #pragma mark - #pragma mark Web Server initialization -- (void)_handleAsyncServerRequest:(GCDWebServerRequest *)request completion:(GCDWebServerCompletionBlock)completion -{ - NSString *endpointName = [[request URL] lastPathComponent]; - Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName]; - if (operationClass != nil) { - MBIMBridgeOperation *operation = [[operationClass alloc] initWithRequest:request completion:completion]; - [[self operationQueue] addOperation:operation]; - } else { - completion([GCDWebServerDataResponse responseWithStatusCode:404]); - } -} - - (void)startWebServer { - [GCDWebServer setLogLevel:3]; + self.httpServer = [[HTTPServer alloc] init]; + [self.httpServer setConnectionClass:[MBIMHTTPConnection class]]; + [self.httpServer setPort:8080]; - __auto_type __weak weakSelf = self; - self.webServer = [[GCDWebServer alloc] init]; - [self.webServer addDefaultHandlerForMethod:@"GET" - requestClass:[GCDWebServerRequest class] - asyncProcessBlock:^(__kindof GCDWebServerRequest * _Nonnull request, GCDWebServerCompletionBlock _Nonnull completionBlock) { [weakSelf _handleAsyncServerRequest:request completion:completionBlock]; }]; - - [self.webServer addDefaultHandlerForMethod:@"POST" - requestClass:[GCDWebServerURLEncodedFormRequest class] - asyncProcessBlock:^(__kindof GCDWebServerRequest * _Nonnull request, GCDWebServerCompletionBlock _Nonnull completionBlock) { [weakSelf _handleAsyncServerRequest:request completion:completionBlock]; }]; - - [self.webServer startWithPort:8080 bonjourName:nil]; + NSError *error = nil; + if (![self.httpServer start:&error]) { + NSLog(@"Error starting HTTP server: %@", [error localizedDescription]); + } } #pragma mark - diff --git a/kordophone/Bridge/MBIMHTTPConnection.h b/kordophone/Bridge/MBIMHTTPConnection.h new file mode 100644 index 0000000..f6bae1b --- /dev/null +++ b/kordophone/Bridge/MBIMHTTPConnection.h @@ -0,0 +1,13 @@ +// +// MBIMHTTPConnection.h +// CocoaHTTPServer +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +@interface MBIMHTTPConnection : HTTPConnection + +@end diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m new file mode 100644 index 0000000..1d748d6 --- /dev/null +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -0,0 +1,70 @@ +// +// MBIMHTTPConnection.m +// CocoaHTTPServer +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMHTTPConnection.h" +#import "MBIMBridge.h" +#import "MBIMBridgeOperation.h" + +@implementation MBIMHTTPConnection { + NSMutableData *_bodyData; +} + +- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path +{ + if ([method isEqualToString:@"GET"] || [method isEqualToString:@"POST"]) { + return YES; + } + + return NO; +} + +- (NSObject *)httpResponseForMethod:(NSString *)method URI:(NSString *)path +{ + __block NSObject *response = nil; + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + MBIMBridgeOperationCompletionBlock completion = ^(NSObject *incomingResponse) { + response = incomingResponse; + dispatch_semaphore_signal(sema); + }; + + NSURL *url = [NSURL URLWithString:path]; + NSString *endpointName = [url lastPathComponent]; + Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName]; + if (operationClass != nil) { + MBIMBridgeOperation *operation = [[operationClass alloc] initWithRequestURL:url completion:completion]; + operation.requestBodyData = _bodyData; + + [[[MBIMBridge sharedInstance] operationQueue] addOperation:operation]; + dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC))); + } else { + response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; + } + + return response; +} + +- (BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path +{ + if ([method isEqualToString:@"POST"]) { + return YES; + } + + return NO; +} + +- (void)prepareForBodyWithSize:(UInt64)contentLength +{ + _bodyData = [[NSMutableData alloc] initWithCapacity:contentLength]; +} + +- (void)processBodyData:(NSData *)postDataChunk +{ + [_bodyData appendData:postDataChunk]; +} + +@end diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.h b/kordophone/Bridge/Operations/MBIMBridgeOperation.h index 8b3894d..895e5bf 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.h +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.h @@ -7,18 +7,23 @@ // #import -#import +#import + +#import "MBIMJSONDataResponse.h" NS_ASSUME_NONNULL_BEGIN +typedef void (^MBIMBridgeOperationCompletionBlock)(NSObject * _Nullable response); + @interface MBIMBridgeOperation : NSOperation @property (class, nonatomic, readonly) NSString *endpointName; -@property (nonatomic, readonly) GCDWebServerRequest *request; -@property (nonatomic, readonly) GCDWebServerCompletionBlock serverCompletionBlock; +@property (nonatomic, strong) NSData *requestBodyData; +@property (nonatomic, readonly) NSURL *requestURL; +@property (nonatomic, readonly) MBIMBridgeOperationCompletionBlock serverCompletionBlock; + (nullable Class)operationClassForEndpointName:(NSString *)endpointName; -- (instancetype)initWithRequest:(GCDWebServerRequest *)request completion:(GCDWebServerCompletionBlock)completionBlock; +- (instancetype)initWithRequestURL:(NSURL *)requestURL completion:(MBIMBridgeOperationCompletionBlock)completionBlock; @end diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.m b/kordophone/Bridge/Operations/MBIMBridgeOperation.m index 883489e..ebab0b1 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.m +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.m @@ -9,8 +9,8 @@ #import "MBIMBridgeOperation.h" @interface MBIMBridgeOperation (/*INTERNAL*/) -@property (nonatomic, copy) GCDWebServerCompletionBlock serverCompletionBlock; -@property (nonatomic, strong) GCDWebServerRequest *request; +@property (nonatomic, strong) NSURL *requestURL; +@property (nonatomic, copy) MBIMBridgeOperationCompletionBlock serverCompletionBlock; @end @implementation MBIMBridgeOperation @@ -44,11 +44,11 @@ return [[self _operationClassMapping] objectForKey:endpointName]; } -- (instancetype)initWithRequest:(GCDWebServerRequest *)request completion:(GCDWebServerCompletionBlock)completionBlock +- (instancetype)initWithRequestURL:(NSURL *)requestURL completion:(MBIMBridgeOperationCompletionBlock)completionBlock { self = [super init]; if (self) { - self.request = request; + self.requestURL = requestURL; self.serverCompletionBlock = completionBlock; } diff --git a/kordophone/Bridge/Operations/MBIMConversationListOperation.m b/kordophone/Bridge/Operations/MBIMConversationListOperation.m index 84ad63c..515d0ca 100644 --- a/kordophone/Bridge/Operations/MBIMConversationListOperation.m +++ b/kordophone/Bridge/Operations/MBIMConversationListOperation.m @@ -7,6 +7,7 @@ // #import "MBIMConversationListOperation.h" +#import "MBIMHTTPUtilities.h" #import @@ -28,7 +29,7 @@ NSMutableDictionary *chatDict = [NSMutableDictionary dictionary]; chatDict[@"guid"] = [chat guid]; chatDict[@"displayName"] = [chat displayName]; - chatDict[@"date"] = GCDWebServerFormatRFC822([chat lastFinishedMessageDate]); + chatDict[@"date"] = MBIMWebServerFormatRFC822([chat lastFinishedMessageDate]); IMMessage *lastMessage = [chat lastMessage]; if (lastMessage) { @@ -48,7 +49,7 @@ [conversations addObject:chatDict]; } - GCDWebServerResponse *response = [GCDWebServerDataResponse responseWithJSONObject:conversations]; + MBIMJSONDataResponse *response = [MBIMJSONDataResponse responseWithJSONObject:conversations]; self.serverCompletionBlock(response); } diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m index d9be1b1..9f34d62 100644 --- a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -7,6 +7,7 @@ // #import "MBIMMessagesListOperation.h" +#import "MBIMHTTPUtilities.h" #import @@ -21,9 +22,9 @@ - (void)main { - GCDWebServerResponse *response = nil; + NSObject *response = nil; do { - NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:[self.request URL] resolvingAgainstBaseURL:NO]; + NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:self.requestURL resolvingAgainstBaseURL:NO]; NSString *guid = nil; for (NSURLQueryItem *queryItem in [urlComponents queryItems]) { @@ -35,14 +36,14 @@ if (!guid) { NSLog(@"No query item provided"); - response = [GCDWebServerDataResponse responseWithStatusCode:500]; + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; if (!chat) { NSLog(@"Chat with guid: %@ not found", guid); - response = [GCDWebServerDataResponse responseWithStatusCode:500]; + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } @@ -53,12 +54,12 @@ for (IMMessageItem *imMessage in [[chat chatItems] messages]) { NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; messageDict[@"text"] = [[imMessage body] string]; - messageDict[@"date"] = GCDWebServerFormatRFC822([imMessage time]); + messageDict[@"date"] = MBIMWebServerFormatRFC822([imMessage time]); messageDict[@"sender"] = [imMessage sender]; [messages addObject:messageDict]; } - response = [GCDWebServerDataResponse responseWithJSONObject:messages]; + response = [MBIMJSONDataResponse responseWithJSONObject:messages]; } while (0); self.serverCompletionBlock(response); diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index 907c6c9..5b8e2e7 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -41,20 +41,25 @@ - (void)main { - assert([self.request isKindOfClass:[GCDWebServerURLEncodedFormRequest class]]); + NSObject *response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; - GCDWebServerURLEncodedFormRequest *formRequest = (GCDWebServerURLEncodedFormRequest *)self.request; - NSDictionary *args = [formRequest arguments]; + NSError *error = nil; + NSDictionary *args = [NSJSONSerialization JSONObjectWithData:self.requestBodyData options:0 error:&error]; + if (error || args.count == 0) { + self.serverCompletionBlock(response); + return; + } NSString *guid = [args objectForKey:@"guid"]; NSString *messageBody = [args objectForKey:@"body"]; - BOOL result = [self _sendMessage:messageBody toChatWithGUID:guid]; + if (!guid || !messageBody) { + self.serverCompletionBlock(response); + return; + } - GCDWebServerResponse *response = nil; + BOOL result = [self _sendMessage:messageBody toChatWithGUID:guid]; if (result) { - response = [GCDWebServerDataResponse responseWithStatusCode:200]; - } else { - response = [GCDWebServerDataResponse responseWithStatusCode:500]; + response = [[HTTPErrorResponse alloc] initWithErrorCode:200]; } self.serverCompletionBlock(response); diff --git a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h new file mode 100644 index 0000000..10f03d6 --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h @@ -0,0 +1,11 @@ +// +// MBIMHTTPUtilities.h +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +NSString* MBIMWebServerFormatRFC822(NSDate *date); diff --git a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m new file mode 100644 index 0000000..61bbd1a --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m @@ -0,0 +1,33 @@ +// +// MBIMHTTPUtilities.c +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#include "MBIMHTTPUtilities.h" + +static NSDateFormatter* _dateFormatterRFC822 = nil; +static dispatch_queue_t _dateFormatterQueue = NULL; + +__attribute__((constructor)) +static void __InitializeDateFormatter() +{ + _dateFormatterQueue = dispatch_queue_create("dateFormatter", DISPATCH_QUEUE_SERIAL); + + _dateFormatterRFC822 = [[NSDateFormatter alloc] init]; + _dateFormatterRFC822.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + _dateFormatterRFC822.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'"; + _dateFormatterRFC822.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]; +} + +NSString* MBIMWebServerFormatRFC822(NSDate *date) +{ + __block NSString *string = nil; + dispatch_sync(_dateFormatterQueue, ^{ + string = [_dateFormatterRFC822 stringFromDate:date]; + }); + + return string; +} diff --git a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h new file mode 100644 index 0000000..71f1756 --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h @@ -0,0 +1,16 @@ +// +// MBIMJSONDataResponse.h +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import +#import + +@interface MBIMJSONDataResponse : HTTPDataResponse + ++ (instancetype)responseWithJSONObject:(id)object; + +@end diff --git a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m new file mode 100644 index 0000000..ec59aae --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m @@ -0,0 +1,32 @@ +// +// MBIMJSONDataResponse.m +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMJSONDataResponse.h" + +@implementation MBIMJSONDataResponse + ++ (instancetype)responseWithJSONObject:(id)object +{ + NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL]; + if (data == nil) { + return nil; + } + + MBIMJSONDataResponse *response = [[self alloc] initWithData:data]; + + return response; +} + +- (NSDictionary *)httpHeaders +{ + return @{ + @"Content-Type" : @"application/json; charset=utf-8" + }; +} + +@end diff --git a/kordophone/Crypto/GCDWebServerDataResponse+Crypto.h b/kordophone/Crypto/GCDWebServerDataResponse+Crypto.h deleted file mode 100644 index 6b9ab04..0000000 --- a/kordophone/Crypto/GCDWebServerDataResponse+Crypto.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// GCDWebServerDataResponse+Crypto.h -// kordophoned -// -// Created by James Magahern on 11/15/18. -// Copyright © 2018 James Magahern. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface GCDWebServerDataResponse (Crypto) - -+ (nullable instancetype)encryptedResponseWithJSONObject:(id)object; - -@end - -NS_ASSUME_NONNULL_END - diff --git a/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m b/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m deleted file mode 100644 index 793b83a..0000000 --- a/kordophone/Crypto/GCDWebServerDataResponse+Crypto.m +++ /dev/null @@ -1,44 +0,0 @@ -// -// GCDWebServerDataResponse+Crypto.m -// kordophoned -// -// Created by James Magahern on 11/15/18. -// Copyright © 2018 James Magahern. All rights reserved. -// - -#import "GCDWebServerDataResponse+Crypto.h" - -#import "NSData+AES.h" - -// TEMP!! -static NSString *const kSymmetricKey = @"axPy0nljtG/TOVJSVwVXag=="; - -@implementation GCDWebServerDataResponse (Crypto) - -+ (nullable instancetype)encryptedResponseWithJSONObject:(id)object -{ - NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL]; - if (data == nil) { - return nil; - } - - NSError *error = nil; - NSData *ivData = [[[NSUUID UUID] UUIDString] dataUsingEncoding:NSUTF8StringEncoding]; - NSData *keyData = [[NSData alloc] initWithBase64EncodedString:kSymmetricKey options:0]; - NSData *encryptedData = [data encryptedDataWithKey:keyData iv:ivData error:&error]; - if (error) { - NSLog(@"Error encrypting response: %@", error); - } - - NSString *ivDataString = [ivData base64EncodedStringWithOptions:0]; - - GCDWebServerDataResponse *response = [[self alloc] initWithData:encryptedData contentType:@"application/octet-stream"]; - [response setValue:ivDataString forAdditionalHeader:@"X-KordophoneCrypto-IV"]; - - // TODO: is this the right way?? - [response setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[data length]] forAdditionalHeader:@"X-Decrypted-Content-Length"]; - - return response; -} - -@end diff --git a/kordophone/Crypto/NSData+AES.h b/kordophone/Crypto/NSData+AES.h deleted file mode 100644 index 7530ba7..0000000 --- a/kordophone/Crypto/NSData+AES.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// NSData+AES.h -// MessagesBridge -// -// Created by James Magahern on 11/15/18. -// Copyright © 2018 James Magahern. All rights reserved. -// - -#import -#import - -@interface NSData (AES) - -- (NSData *)encryptedDataWithKey:(NSData *)key iv:(NSData *)iv error:(NSError **)error; -- (NSData *)decryptedDataWithKey:(NSData *)key iv:(NSData *)iv error:(NSError **)error; - -@end diff --git a/kordophone/Crypto/NSData+AES.m b/kordophone/Crypto/NSData+AES.m deleted file mode 100644 index d69614c..0000000 --- a/kordophone/Crypto/NSData+AES.m +++ /dev/null @@ -1,58 +0,0 @@ -// -// NSData+AES.m -// MessagesBridge -// -// Created by James Magahern on 11/15/18. -// Copyright © 2018 James Magahern. All rights reserved. -// - -#import "NSData+AES.h" - -@implementation NSData (AES) - -+ (NSData *)AES128Operation:(CCOperation)operation - withInputData:(NSData *)inputData - key:(NSData *)key - iv:(NSData *)iv - error:(NSError **)error -{ - size_t dataMoved = 0; - NSMutableData *outputData = [NSMutableData dataWithLength:(inputData.length + kCCBlockSizeAES128)]; - CCCryptorStatus status = CCCrypt( - operation, - kCCAlgorithmAES, - kCCOptionPKCS7Padding, - key.bytes, - key.length, - iv.bytes, - inputData.bytes, - inputData.length, - outputData.mutableBytes, - outputData.length, - &dataMoved - ); - - if (status == kCCSuccess) { - outputData.length = dataMoved; - } else { - *error = [NSError errorWithDomain:@"CommonCryptoError" - code:status - userInfo:nil]; - - outputData = nil; - } - - return outputData; -} - -- (NSData *)encryptedDataWithKey:(NSData *)key iv:(NSData *)iv error:(NSError *__autoreleasing *)error -{ - return [[self class] AES128Operation:kCCEncrypt withInputData:self key:key iv:iv error:error]; -} - -- (NSData *)decryptedDataWithKey:(NSData *)key iv:(NSData *)iv error:(NSError *__autoreleasing *)error -{ - return [[self class] AES128Operation:kCCDecrypt withInputData:self key:key iv:iv error:error]; -} - -@end From 182e240291d2475a43c571861193369971684331 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 16 Nov 2018 01:32:09 -0800 Subject: [PATCH 11/75] Removed GCDWebServer submodule --- .gitmodules | 6 ------ GCDWebServer | 1 - 2 files changed, 7 deletions(-) delete mode 160000 GCDWebServer diff --git a/.gitmodules b/.gitmodules index e374d4f..98ed119 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,3 @@ -[submodule "GCDWebServer"] - path = GCDWebServer - url = https://github.com/swisspol/GCDWebServer.git -[submodule "logos"] - path = logos - url = git@github.com:theos/logos.git [submodule "CocoaHTTPServer"] path = CocoaHTTPServer url = https://github.com/robbiehanson/CocoaHTTPServer.git diff --git a/GCDWebServer b/GCDWebServer deleted file mode 160000 index 7df4653..0000000 --- a/GCDWebServer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7df465336eb3e975fdc498e2ac8a845f3ae56a34 From 1b12faddf8f0002a4e5c26921f53f5b25acaa69b Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 16 Nov 2018 01:40:02 -0800 Subject: [PATCH 12/75] Project cleanup around new submodule --- MessagesBridge.xcodeproj/project.pbxproj | 12 ------------ kordophone/Bridge/MBIMBridge.m | 2 +- kordophone/Bridge/MBIMHTTPConnection.h | 2 +- kordophone/Bridge/MBIMHTTPConnection.m | 1 + kordophone/Bridge/Operations/MBIMBridgeOperation.h | 5 +++-- .../Operations/Utilities/MBIMJSONDataResponse.h | 2 +- 6 files changed, 7 insertions(+), 17 deletions(-) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index d3e0f25..d0fe242 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -10,7 +10,6 @@ 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */; }; 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */; }; 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */; }; - 1ACFCF26219EB2AC00E2C237 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCDFB219EB2AB00E2C237 /* Info.plist */; }; 1ACFCF27219EB2AC00E2C237 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */; }; 1ACFCF29219EB2AC00E2C237 /* README.markdown in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCDFE219EB2AB00E2C237 /* README.markdown */; }; 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -69,7 +68,6 @@ 1ACFCFDB219EB2AC00E2C237 /* About.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1C219EB2AC00E2C237 /* About.txt */; }; 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */; }; - 1ACFCFE1219EB37000E2C237 /* CocoaHTTPServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCFE0219EB37000E2C237 /* CocoaHTTPServer.h */; settings = {ATTRIBUTES = (Public, ); }; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */; }; @@ -133,8 +131,6 @@ 1AA43E93219EC38E00EDF1A7 /* MBIMHTTPUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMHTTPUtilities.h; sourceTree = ""; }; 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMHTTPUtilities.m; sourceTree = ""; }; 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CocoaHTTPServer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 1ACFCDE5219EB28A00E2C237 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1ACFCDFB219EB2AB00E2C237 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 1ACFCDFE219EB2AB00E2C237 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = ""; }; 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPConnection.h; sourceTree = ""; }; @@ -192,7 +188,6 @@ 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncSocket.m; sourceTree = ""; }; 1ACFCF1C219EB2AC00E2C237 /* About.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = About.txt; sourceTree = ""; }; 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocket.h; sourceTree = ""; }; - 1ACFCFE0219EB37000E2C237 /* CocoaHTTPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CocoaHTTPServer.h; sourceTree = ""; }; 1ACFCFE2219EB45300E2C237 /* MBIMHTTPConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMHTTPConnection.h; sourceTree = ""; }; 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMHTTPConnection.m; sourceTree = ""; }; CD14F18B219E2DB400E7DD22 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -338,13 +333,10 @@ 1ACFCDE3219EB28A00E2C237 /* CocoaHTTPServer */ = { isa = PBXGroup; children = ( - 1ACFCFE0219EB37000E2C237 /* CocoaHTTPServer.h */, 1ACFCDFF219EB2AB00E2C237 /* Core */, - 1ACFCDFB219EB2AB00E2C237 /* Info.plist */, 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */, 1ACFCDFE219EB2AB00E2C237 /* README.markdown */, 1ACFCF07219EB2AC00E2C237 /* Vendor */, - 1ACFCDE5219EB28A00E2C237 /* Info.plist */, ); path = CocoaHTTPServer; sourceTree = ""; @@ -541,7 +533,6 @@ 1ACFCF2E219EB2AC00E2C237 /* HTTPAuthenticationRequest.h in Headers */, 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */, 1ACFCF4A219EB2AC00E2C237 /* DDNumber.h in Headers */, - 1ACFCFE1219EB37000E2C237 /* CocoaHTTPServer.h in Headers */, 1ACFCF3F219EB2AC00E2C237 /* HTTPResponse.h in Headers */, 1ACFCF39219EB2AC00E2C237 /* HTTPFileResponse.h in Headers */, 1ACFCFCF219EB2AC00E2C237 /* ContextFilterLogFormatter.h in Headers */, @@ -692,7 +683,6 @@ 1ACFCFD3219EB2AC00E2C237 /* README.txt in Resources */, 1ACFCF27219EB2AC00E2C237 /* LICENSE.txt in Resources */, 1ACFCFDB219EB2AC00E2C237 /* About.txt in Resources */, - 1ACFCF26219EB2AC00E2C237 /* Info.plist in Resources */, 1ACFCF29219EB2AC00E2C237 /* README.markdown in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -921,7 +911,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - INFOPLIST_FILE = CocoaHTTPServer/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -950,7 +939,6 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; - INFOPLIST_FILE = CocoaHTTPServer/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index 76b74fc..06c6a9a 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -11,7 +11,7 @@ #import "MBIMHTTPConnection.h" #import "hooking.h" -#import +#import #import #import diff --git a/kordophone/Bridge/MBIMHTTPConnection.h b/kordophone/Bridge/MBIMHTTPConnection.h index f6bae1b..de4f094 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.h +++ b/kordophone/Bridge/MBIMHTTPConnection.h @@ -6,7 +6,7 @@ // Copyright © 2018 James Magahern. All rights reserved. // -#import +#import @interface MBIMHTTPConnection : HTTPConnection diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index 1d748d6..0479cd8 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -7,6 +7,7 @@ // #import "MBIMHTTPConnection.h" + #import "MBIMBridge.h" #import "MBIMBridgeOperation.h" diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.h b/kordophone/Bridge/Operations/MBIMBridgeOperation.h index 895e5bf..50d94c9 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.h +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.h @@ -7,13 +7,14 @@ // #import -#import +#import +#import #import "MBIMJSONDataResponse.h" NS_ASSUME_NONNULL_BEGIN -typedef void (^MBIMBridgeOperationCompletionBlock)(NSObject * _Nullable response); +typedef void (^MBIMBridgeOperationCompletionBlock)(NSObject * _Nullable response); @interface MBIMBridgeOperation : NSOperation @property (class, nonatomic, readonly) NSString *endpointName; diff --git a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h index 71f1756..be617b3 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h +++ b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h @@ -7,7 +7,7 @@ // #import -#import +#import @interface MBIMJSONDataResponse : HTTPDataResponse From 464e9fe22c6eb903af52b3b9887f7a76dbf19ca7 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 16 Nov 2018 18:52:23 -0800 Subject: [PATCH 13/75] Remove copy files phase for CocoaWebServer framework --- MessagesBridge.xcodeproj/project.pbxproj | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index d0fe242..be3113e 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -10,8 +10,6 @@ 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */; }; 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */; }; 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */; }; - 1ACFCF27219EB2AC00E2C237 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */; }; - 1ACFCF29219EB2AC00E2C237 /* README.markdown in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCDFE219EB2AB00E2C237 /* README.markdown */; }; 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE01219EB2AB00E2C237 /* HTTPLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE02219EB2AB00E2C237 /* HTTPMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -57,15 +55,12 @@ 1ACFCFD0219EB2AC00E2C237 /* DispatchQueueLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF10219EB2AC00E2C237 /* DispatchQueueLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFD1219EB2AC00E2C237 /* ContextFilterLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF11219EB2AC00E2C237 /* ContextFilterLogFormatter.m */; }; 1ACFCFD2219EB2AC00E2C237 /* DispatchQueueLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF12219EB2AC00E2C237 /* DispatchQueueLogFormatter.m */; }; - 1ACFCFD3219EB2AC00E2C237 /* README.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCF13219EB2AC00E2C237 /* README.txt */; }; 1ACFCFD4219EB2AC00E2C237 /* DDLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF14219EB2AC00E2C237 /* DDLog.m */; }; - 1ACFCFD5219EB2AC00E2C237 /* About.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCF15219EB2AC00E2C237 /* About.txt */; }; 1ACFCFD6219EB2AC00E2C237 /* DDTTYLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF16219EB2AC00E2C237 /* DDTTYLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFD7219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF17219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m */; }; 1ACFCFD8219EB2AC00E2C237 /* DDFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF18219EB2AC00E2C237 /* DDFileLogger.m */; }; 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF19219EB2AC00E2C237 /* DDASLLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDA219EB2AC00E2C237 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */; }; - 1ACFCFDB219EB2AC00E2C237 /* About.txt in Resources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1C219EB2AC00E2C237 /* About.txt */; }; 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; @@ -679,11 +674,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1ACFCFD5219EB2AC00E2C237 /* About.txt in Resources */, - 1ACFCFD3219EB2AC00E2C237 /* README.txt in Resources */, - 1ACFCF27219EB2AC00E2C237 /* LICENSE.txt in Resources */, - 1ACFCFDB219EB2AC00E2C237 /* About.txt in Resources */, - 1ACFCF29219EB2AC00E2C237 /* README.markdown in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; From ddec4be8d603ccff143b0ed45f8925e56b90938d Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sat, 17 Nov 2018 01:07:55 -0800 Subject: [PATCH 14/75] Supports polling for updates --- MessagesBridge.xcodeproj/project.pbxproj | 36 +++++++++++ kordophone/Bridge/MBIMBridge.m | 21 ++++++- kordophone/Bridge/MBIMConcurrentHTTPServer.h | 17 ++++++ kordophone/Bridge/MBIMConcurrentHTTPServer.m | 23 +++++++ kordophone/Bridge/MBIMHTTPConnection.m | 15 +++-- kordophone/Bridge/MBIMUpdateQueue.h | 30 +++++++++ kordophone/Bridge/MBIMUpdateQueue.m | 61 +++++++++++++++++++ .../Operations/MBIMMessagesListOperation.m | 6 +- .../Operations/MBIMUpdatePollOperation.h | 17 ++++++ .../Operations/MBIMUpdatePollOperation.m | 39 ++++++++++++ kordophone/Categories/IMMessageItem+Encoded.h | 24 ++++++++ kordophone/Categories/IMMessageItem+Encoded.m | 38 ++++++++++++ 12 files changed, 316 insertions(+), 11 deletions(-) create mode 100644 kordophone/Bridge/MBIMConcurrentHTTPServer.h create mode 100644 kordophone/Bridge/MBIMConcurrentHTTPServer.m create mode 100644 kordophone/Bridge/MBIMUpdateQueue.h create mode 100644 kordophone/Bridge/MBIMUpdateQueue.m create mode 100644 kordophone/Bridge/Operations/MBIMUpdatePollOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMUpdatePollOperation.m create mode 100644 kordophone/Categories/IMMessageItem+Encoded.h create mode 100644 kordophone/Categories/IMMessageItem+Encoded.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index be3113e..45d0d86 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -64,6 +64,11 @@ 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; + CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */; }; + CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A3219FF22700E7DD22 /* IMMessageItem+Encoded.m */; }; + CD14F1A7219FF2F400E7DD22 /* IMSharedUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD14F1A6219FF2F400E7DD22 /* IMSharedUtilities.framework */; }; + CD14F1AA219FF3B800E7DD22 /* MBIMUpdateQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */; }; + CD14F1AD219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */; }; CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */; }; CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */; }; @@ -188,6 +193,15 @@ CD14F18B219E2DB400E7DD22 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CD14F18D219E2DB400E7DD22 /* CryptoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoTests.m; sourceTree = ""; }; CD14F18F219E2DB400E7DD22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CD14F19F219FE7D600E7DD22 /* MBIMUpdatePollOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMUpdatePollOperation.h; sourceTree = ""; }; + CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMUpdatePollOperation.m; sourceTree = ""; }; + CD14F1A2219FF22700E7DD22 /* IMMessageItem+Encoded.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IMMessageItem+Encoded.h"; sourceTree = ""; }; + CD14F1A3219FF22700E7DD22 /* IMMessageItem+Encoded.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "IMMessageItem+Encoded.m"; sourceTree = ""; }; + CD14F1A6219FF2F400E7DD22 /* IMSharedUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IMSharedUtilities.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/IMSharedUtilities.framework; sourceTree = DEVELOPER_DIR; }; + CD14F1A8219FF3B800E7DD22 /* MBIMUpdateQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMUpdateQueue.h; sourceTree = ""; }; + CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMUpdateQueue.m; sourceTree = ""; }; + CD14F1AB219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMConcurrentHTTPServer.h; sourceTree = ""; }; + CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMConcurrentHTTPServer.m; sourceTree = ""; }; CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridgeOperation.h; sourceTree = ""; }; CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridgeOperation.m; sourceTree = ""; }; CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMMessagesListOperation.h; sourceTree = ""; }; @@ -233,6 +247,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CD14F1A7219FF2F400E7DD22 /* IMSharedUtilities.framework in Frameworks */, 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */, CDF62343219A9BE200690038 /* ContactsFoundation.framework in Frameworks */, CDF6233E219A8AFC00690038 /* IMCore.framework in Frameworks */, @@ -280,6 +295,7 @@ 1A0C445E219A45B400F2AC00 /* Frameworks */ = { isa = PBXGroup; children = ( + CD14F1A6219FF2F400E7DD22 /* IMSharedUtilities.framework */, CDF62342219A9BE200690038 /* ContactsFoundation.framework */, CDF62340219A9AAA00690038 /* EmailFoundation.framework */, 1A0C4467219A45D500F2AC00 /* IMCore.framework */, @@ -297,6 +313,10 @@ CD60204C219B5D710024D9C5 /* Operations */, 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */, 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */, + CD14F1A8219FF3B800E7DD22 /* MBIMUpdateQueue.h */, + CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */, + CD14F1AB219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.h */, + CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */, 1ACFCFE2219EB45300E2C237 /* MBIMHTTPConnection.h */, 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */, ); @@ -462,6 +482,15 @@ path = Tests; sourceTree = ""; }; + CD14F1A5219FF22B00E7DD22 /* Categories */ = { + isa = PBXGroup; + children = ( + CD14F1A2219FF22700E7DD22 /* IMMessageItem+Encoded.h */, + CD14F1A3219FF22700E7DD22 /* IMMessageItem+Encoded.m */, + ); + path = Categories; + sourceTree = ""; + }; CD60204C219B5D710024D9C5 /* Operations */ = { isa = PBXGroup; children = ( @@ -474,6 +503,8 @@ CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */, CD602060219B68950024D9C5 /* MBIMSendMessageOperation.h */, CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */, + CD14F19F219FE7D600E7DD22 /* MBIMUpdatePollOperation.h */, + CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */, ); path = Operations; sourceTree = ""; @@ -499,6 +530,7 @@ CDF62333219A895D00690038 /* kordophone */ = { isa = PBXGroup; children = ( + CD14F1A5219FF22B00E7DD22 /* Categories */, CD83E150219BDB4F00F4CCEA /* Hooking */, 1A0C446D219A4BCD00F2AC00 /* Bridge */, CDF62334219A895D00690038 /* main.m */, @@ -739,6 +771,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CD14F1AD219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m in Sources */, 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */, CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */, @@ -746,7 +779,10 @@ CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, CDF62335219A895D00690038 /* main.m in Sources */, CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */, + CD14F1AA219FF3B800E7DD22 /* MBIMUpdateQueue.m in Sources */, + CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */, CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, + CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */, CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */, CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */, diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index 06c6a9a..cce8c65 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -8,7 +8,9 @@ #import "MBIMBridge.h" #import "MBIMBridgeOperation.h" +#import "MBIMConcurrentHTTPServer.h" #import "MBIMHTTPConnection.h" +#import "MBIMUpdateQueue.h" #import "hooking.h" #import @@ -22,7 +24,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; @interface MBIMBridge (/* INTERNAL */) -@property (nonatomic, strong) HTTPServer *httpServer; +@property (nonatomic, strong) MBIMConcurrentHTTPServer *httpServer; @property (nonatomic, strong) NSOperationQueue *operationQueue; - (instancetype)_init; @@ -52,6 +54,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; [sDaemonListener addHandler:self]; _operationQueue = [[NSOperationQueue alloc] init]; + _operationQueue.maxConcurrentOperationCount = 5; } return self; @@ -115,7 +118,19 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; { NSLog(@"Received message from chat with GUID: %@", [[notification object] guid]); - // TODO: Notify observers or something + IMChat *chat = [notification object]; + IMMessage *message = [[notification userInfo] objectForKey:IMChatValueKey]; + if (chat && message) { + if (![message isFromMe]) { + MBIMUpdateItem *updateItem = [[MBIMUpdateItem alloc] init]; + updateItem.changedChat = chat; + updateItem.message = message; + + [[MBIMUpdateQueue sharedInstance] enqueueUpdateItem:updateItem]; + } else { + // TODO: care about messages from me? + } + } } - (void)_chatRegistryDidLoad:(NSNotification *)notification @@ -133,7 +148,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; - (void)startWebServer { - self.httpServer = [[HTTPServer alloc] init]; + self.httpServer = [[MBIMConcurrentHTTPServer alloc] init]; [self.httpServer setConnectionClass:[MBIMHTTPConnection class]]; [self.httpServer setPort:8080]; diff --git a/kordophone/Bridge/MBIMConcurrentHTTPServer.h b/kordophone/Bridge/MBIMConcurrentHTTPServer.h new file mode 100644 index 0000000..e19cc43 --- /dev/null +++ b/kordophone/Bridge/MBIMConcurrentHTTPServer.h @@ -0,0 +1,17 @@ +// +// MBIMConcurrentHTTPServer.h +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMConcurrentHTTPServer : HTTPServer + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/MBIMConcurrentHTTPServer.m b/kordophone/Bridge/MBIMConcurrentHTTPServer.m new file mode 100644 index 0000000..f05b537 --- /dev/null +++ b/kordophone/Bridge/MBIMConcurrentHTTPServer.m @@ -0,0 +1,23 @@ +// +// MBIMConcurrentHTTPServer.m +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMConcurrentHTTPServer.h" + +@implementation MBIMConcurrentHTTPServer + +- (id)init +{ + self = [super init]; + if (self) { + connectionQueue = dispatch_queue_create("net.buzzert.MBIMConcurrentHTTPConnectionQueue", DISPATCH_QUEUE_CONCURRENT); + } + + return self; +} + +@end diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index 0479cd8..1aba86f 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -13,6 +13,7 @@ @implementation MBIMHTTPConnection { NSMutableData *_bodyData; + MBIMBridgeOperation *_currentOperation; } - (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path @@ -37,11 +38,11 @@ NSString *endpointName = [url lastPathComponent]; Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName]; if (operationClass != nil) { - MBIMBridgeOperation *operation = [[operationClass alloc] initWithRequestURL:url completion:completion]; - operation.requestBodyData = _bodyData; + _currentOperation = [[operationClass alloc] initWithRequestURL:url completion:completion]; + _currentOperation.requestBodyData = _bodyData; - [[[MBIMBridge sharedInstance] operationQueue] addOperation:operation]; - dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC))); + [[[MBIMBridge sharedInstance] operationQueue] addOperation:_currentOperation]; + dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60.0 * NSEC_PER_SEC))); } else { response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; } @@ -68,4 +69,10 @@ [_bodyData appendData:postDataChunk]; } +- (void)die +{ + [_currentOperation cancel]; + [super die]; +} + @end diff --git a/kordophone/Bridge/MBIMUpdateQueue.h b/kordophone/Bridge/MBIMUpdateQueue.h new file mode 100644 index 0000000..9eb15b1 --- /dev/null +++ b/kordophone/Bridge/MBIMUpdateQueue.h @@ -0,0 +1,30 @@ +// +// MBIMUpdateQueue.h +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMUpdateItem : NSObject +@property (nonatomic, strong) IMChat *changedChat; +@property (nonatomic, strong) IMMessage *message; +@end + +typedef void (^MBIMUpdateConsumer)(MBIMUpdateItem *item); + +@interface MBIMUpdateQueue : NSObject + ++ (instancetype)sharedInstance; + +- (void)addConsumer:(MBIMUpdateConsumer)consumer; +- (void)enqueueUpdateItem:(MBIMUpdateItem *)item; + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/MBIMUpdateQueue.m b/kordophone/Bridge/MBIMUpdateQueue.m new file mode 100644 index 0000000..30e4091 --- /dev/null +++ b/kordophone/Bridge/MBIMUpdateQueue.m @@ -0,0 +1,61 @@ +// +// MBIMUpdateQueue.m +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMUpdateQueue.h" + +@implementation MBIMUpdateQueue { + dispatch_queue_t _accessQueue; + NSMutableArray *_consumers; +} + ++ (instancetype)sharedInstance +{ + static MBIMUpdateQueue *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + + return sharedInstance; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + _accessQueue = dispatch_queue_create("net.buzzert.MBIMUpdateQueue", DISPATCH_QUEUE_SERIAL); + _consumers = [[NSMutableArray alloc] init]; + } + + return self; +} + +- (void)addConsumer:(MBIMUpdateConsumer)consumer +{ + __weak NSMutableArray *consumers = _consumers; + dispatch_async(_accessQueue, ^{ + [consumers addObject:consumer]; + }); +} + +- (void)enqueueUpdateItem:(MBIMUpdateItem *)item +{ + __weak NSMutableArray *consumers = _consumers; + dispatch_async(_accessQueue, ^{ + for (MBIMUpdateConsumer consumer in consumers) { + consumer(item); + } + + [consumers removeAllObjects]; + }); +} + +@end + +@implementation MBIMUpdateItem +@end diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m index 9f34d62..a50c282 100644 --- a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -8,6 +8,7 @@ #import "MBIMMessagesListOperation.h" #import "MBIMHTTPUtilities.h" +#import "IMMessageItem+Encoded.h" #import @@ -52,10 +53,7 @@ NSMutableArray *messages = [NSMutableArray array]; for (IMMessageItem *imMessage in [[chat chatItems] messages]) { - NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; - messageDict[@"text"] = [[imMessage body] string]; - messageDict[@"date"] = MBIMWebServerFormatRFC822([imMessage time]); - messageDict[@"sender"] = [imMessage sender]; + NSDictionary *messageDict = [imMessage mbim_dictionaryRepresentation]; [messages addObject:messageDict]; } diff --git a/kordophone/Bridge/Operations/MBIMUpdatePollOperation.h b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.h new file mode 100644 index 0000000..db2f740 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.h @@ -0,0 +1,17 @@ +// +// MBIMUpdatePollOperation.h +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMUpdatePollOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m new file mode 100644 index 0000000..d0db0c9 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m @@ -0,0 +1,39 @@ +// +// MBIMUpdatePollOperation.m +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMUpdatePollOperation.h" +#import "MBIMUpdateQueue.h" +#import "IMMessageItem+Encoded.h" + +@implementation MBIMUpdatePollOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"pollUpdates"; +} + +- (void)main +{ + MBIMUpdateConsumer consumer = ^(MBIMUpdateItem *nextUpdateItem) { + NSDictionary *updateDict = @{ + @"guid" : [[nextUpdateItem changedChat] guid], + @"message" : [[nextUpdateItem message] mbim_dictionaryRepresentation] + }; + + MBIMJSONDataResponse *response = [MBIMJSONDataResponse responseWithJSONObject:updateDict]; + self.serverCompletionBlock(response); + }; + + [[MBIMUpdateQueue sharedInstance] addConsumer:consumer]; +} + +// TODO: cancel needs to remove the consumer from the update queue + +@end diff --git a/kordophone/Categories/IMMessageItem+Encoded.h b/kordophone/Categories/IMMessageItem+Encoded.h new file mode 100644 index 0000000..222d704 --- /dev/null +++ b/kordophone/Categories/IMMessageItem+Encoded.h @@ -0,0 +1,24 @@ +// +// IMMessageItem+Encoded.h +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface IMMessage (Encoded) +- (NSDictionary *)mbim_dictionaryRepresentation; + +@end + +@interface IMMessageItem (Encoded) +- (NSDictionary *)mbim_dictionaryRepresentation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Categories/IMMessageItem+Encoded.m b/kordophone/Categories/IMMessageItem+Encoded.m new file mode 100644 index 0000000..7305780 --- /dev/null +++ b/kordophone/Categories/IMMessageItem+Encoded.m @@ -0,0 +1,38 @@ +// +// IMMessageItem+Encoded.m +// kordophoned +// +// Created by James Magahern on 11/16/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "IMMessageItem+Encoded.h" +#import "MBIMHTTPUtilities.h" + +@implementation IMMessage (Encoded) + +- (NSDictionary *)mbim_dictionaryRepresentation +{ + NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; + messageDict[@"text"] = [[self text] string]; + messageDict[@"date"] = MBIMWebServerFormatRFC822([self time]); + messageDict[@"sender"] = [[self sender] displayID]; + + return messageDict; +} + +@end + +@implementation IMMessageItem (Encoded) + +- (NSDictionary *)mbim_dictionaryRepresentation +{ + NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; + messageDict[@"text"] = [[self body] string]; + messageDict[@"date"] = MBIMWebServerFormatRFC822([self time]); + messageDict[@"sender"] = [self sender]; + + return messageDict; +} + +@end From 4f5cd058c55fed926dcc03db2fc4442c88832682 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 20 Nov 2018 19:57:35 -0700 Subject: [PATCH 15/75] Updates to sending and message sequences --- MessagesBridge.xcodeproj/project.pbxproj | 12 ++++ kordophone/Bridge/MBIMBridge.m | 23 ++++--- kordophone/Bridge/MBIMHTTPConnection.m | 11 +++- kordophone/Bridge/MBIMUpdateQueue.h | 6 +- kordophone/Bridge/MBIMUpdateQueue.m | 35 +++++++++++ .../Bridge/Operations/MBIMBridgeOperation.h | 2 + .../Bridge/Operations/MBIMBridgeOperation.m | 6 ++ .../MBIMConversationListOperation.m | 22 +------ .../Bridge/Operations/MBIMMarkOperation.h | 17 ++++++ .../Bridge/Operations/MBIMMarkOperation.m | 60 +++++++++++++++++++ .../Operations/MBIMSendMessageOperation.m | 8 ++- .../Operations/MBIMUpdatePollOperation.m | 29 +++++---- .../Operations/Utilities/MBIMHTTPUtilities.h | 1 + .../Operations/Utilities/MBIMHTTPUtilities.m | 16 +++++ kordophone/Categories/IMChat+Encoded.h | 17 ++++++ kordophone/Categories/IMChat+Encoded.m | 40 +++++++++++++ kordophone/Categories/IMMessageItem+Encoded.m | 4 +- 17 files changed, 264 insertions(+), 45 deletions(-) create mode 100644 kordophone/Bridge/Operations/MBIMMarkOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMMarkOperation.m create mode 100644 kordophone/Categories/IMChat+Encoded.h create mode 100644 kordophone/Categories/IMChat+Encoded.m 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; From 3186f1948aa3bc7e2a5096df39ec691a65b30e31 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 21 Nov 2018 01:38:43 -0700 Subject: [PATCH 16/75] Attachments support! --- MessagesBridge.xcodeproj/project.pbxproj | 12 ++++ .../Operations/MBIMFetchAttachmentOperation.h | 17 +++++ .../Operations/MBIMFetchAttachmentOperation.m | 71 +++++++++++++++++++ .../Operations/Utilities/MBIMDataResponse.h | 18 +++++ .../Operations/Utilities/MBIMDataResponse.m | 32 +++++++++ .../Utilities/MBIMJSONDataResponse.h | 4 +- .../Utilities/MBIMJSONDataResponse.m | 10 +-- kordophone/Categories/IMMessageItem+Encoded.m | 15 ++++ 8 files changed, 168 insertions(+), 11 deletions(-) create mode 100644 kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 2be70e3..1e13936 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -77,6 +77,8 @@ 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 */; }; + CDE455A421A5308D0041F5DD /* MBIMFetchAttachmentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE455A321A5308D0041F5DD /* MBIMFetchAttachmentOperation.m */; }; + CDE455A721A531ED0041F5DD /* MBIMDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE455A621A531ED0041F5DD /* MBIMDataResponse.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 */; }; @@ -221,6 +223,10 @@ 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 = ""; }; + CDE455A221A5308D0041F5DD /* MBIMFetchAttachmentOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMFetchAttachmentOperation.h; sourceTree = ""; }; + CDE455A321A5308D0041F5DD /* MBIMFetchAttachmentOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMFetchAttachmentOperation.m; sourceTree = ""; }; + CDE455A521A531ED0041F5DD /* MBIMDataResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMDataResponse.h; sourceTree = ""; }; + CDE455A621A531ED0041F5DD /* MBIMDataResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMDataResponse.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; }; @@ -345,6 +351,8 @@ children = ( 1AA43E8D219EBB2D00EDF1A7 /* MBIMJSONDataResponse.h */, 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */, + CDE455A521A531ED0041F5DD /* MBIMDataResponse.h */, + CDE455A621A531ED0041F5DD /* MBIMDataResponse.m */, 1AA43E93219EC38E00EDF1A7 /* MBIMHTTPUtilities.h */, 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */, ); @@ -509,6 +517,8 @@ CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */, CD60205D219B674B0024D9C5 /* MBIMConversationListOperation.h */, CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */, + CDE455A221A5308D0041F5DD /* MBIMFetchAttachmentOperation.h */, + CDE455A321A5308D0041F5DD /* MBIMFetchAttachmentOperation.m */, CDE4559F21A365AD0041F5DD /* MBIMMarkOperation.h */, CDE455A021A365AD0041F5DD /* MBIMMarkOperation.m */, CD602060219B68950024D9C5 /* MBIMSendMessageOperation.h */, @@ -785,6 +795,7 @@ 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */, CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */, + CDE455A421A5308D0041F5DD /* MBIMFetchAttachmentOperation.m in Sources */, CD83E156219BE10A00F4CCEA /* hooking.m in Sources */, CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, CDF62335219A895D00690038 /* main.m in Sources */, @@ -794,6 +805,7 @@ CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */, CDE455A121A365AD0041F5DD /* MBIMMarkOperation.m in Sources */, + CDE455A721A531ED0041F5DD /* MBIMDataResponse.m in Sources */, CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */, CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, CDE4556421A3578A0041F5DD /* IMChat+Encoded.m in Sources */, diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.h b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.h new file mode 100644 index 0000000..c85012e --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.h @@ -0,0 +1,17 @@ +// +// MBIMFetchAttachmentOperation.h +// kordophoned +// +// Created by James Magahern on 11/20/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMFetchAttachmentOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m new file mode 100644 index 0000000..8ef6426 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m @@ -0,0 +1,71 @@ +// +// MBIMFetchAttachmentOperation.m +// kordophoned +// +// Created by James Magahern on 11/20/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMFetchAttachmentOperation.h" +#import "MBIMDataResponse.h" + +#import + +@implementation MBIMFetchAttachmentOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"attachment"; +} + +- (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; + } + + IMFileTransfer *transfer = [[IMFileTransferCenter sharedInstance] transferForGUID:guid]; + if (!transfer) { + NSLog(@"No transfer found for guid: %@", guid); + response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; + break; + } + + if (![transfer existsAtLocalPath]) { + NSLog(@"We don't have the file for this yet (still downloading to server?)"); + response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; + break; + } + + NSString *localPath = [transfer localPath]; + NSData *responseData = [NSData dataWithContentsOfFile:localPath]; + if (!responseData) { + NSLog(@"Wasn't able to load data from local path: %@", localPath); + response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; + break; + } + + NSString *mimeType = [transfer mimeType]; + response = [[MBIMDataResponse alloc] initWithData:responseData contentType:mimeType]; + } while (0); + + self.serverCompletionBlock(response); +} + +@end diff --git a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h new file mode 100644 index 0000000..2dce971 --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h @@ -0,0 +1,18 @@ +// +// MBIMDataResponse.h +// kordophoned +// +// Created by James Magahern on 11/20/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMDataResponse : HTTPDataResponse +- (instancetype)initWithData:(NSData *)data contentType:(NSString *)contentType; +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m new file mode 100644 index 0000000..e6ea79d --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m @@ -0,0 +1,32 @@ +// +// MBIMDataResponse.m +// kordophoned +// +// Created by James Magahern on 11/20/18. +// Copyright © 2018 James Magahern. All rights reserved. +// + +#import "MBIMDataResponse.h" + +@implementation MBIMDataResponse { + NSString *_contentType; +} + +- (instancetype)initWithData:(NSData *)data contentType:(NSString *)contentType +{ + self = [super initWithData:data]; + if (self) { + _contentType = contentType; + } + + return self; +} + +- (NSDictionary *)httpHeaders +{ + return @{ + @"Content-Type" : _contentType + }; +} + +@end diff --git a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h index be617b3..cf8fef0 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h +++ b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.h @@ -7,9 +7,9 @@ // #import -#import +#import "MBIMDataResponse.h" -@interface MBIMJSONDataResponse : HTTPDataResponse +@interface MBIMJSONDataResponse : MBIMDataResponse + (instancetype)responseWithJSONObject:(id)object; diff --git a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m index ec59aae..41bd25a 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m +++ b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m @@ -17,16 +17,8 @@ return nil; } - MBIMJSONDataResponse *response = [[self alloc] initWithData:data]; - + MBIMJSONDataResponse *response = [[self alloc] initWithData:data contentType:@"application/json; charset=utf-8"]; return response; } -- (NSDictionary *)httpHeaders -{ - return @{ - @"Content-Type" : @"application/json; charset=utf-8" - }; -} - @end diff --git a/kordophone/Categories/IMMessageItem+Encoded.m b/kordophone/Categories/IMMessageItem+Encoded.m index 27e25d4..479f3db 100644 --- a/kordophone/Categories/IMMessageItem+Encoded.m +++ b/kordophone/Categories/IMMessageItem+Encoded.m @@ -32,6 +32,21 @@ messageDict[@"date"] = MBIMWebServerFormatISO8601([self time]); messageDict[@"sender"] = [self sender]; + if ([self fileTransferGUIDs]) { + // Support only images right now + NSMutableArray *filteredFileTransferGUIDs = [NSMutableArray array]; + for (NSString *guid in self.fileTransferGUIDs) { + IMFileTransfer *transfer = [[IMFileTransferCenter sharedInstance] transferForGUID:guid]; + if ([[transfer mimeType] containsString:@"image"]) { + [filteredFileTransferGUIDs addObject:guid]; + } + } + + if ([filteredFileTransferGUIDs count]) { + messageDict[@"fileTransferGUIDs"] = filteredFileTransferGUIDs; + } + } + return messageDict; } From dba4910a821ac8408466b20e5ddb34626b0930dc Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 21 Nov 2018 15:51:51 -0700 Subject: [PATCH 17/75] Batch updates, and fixing bug where daemon would crash when accessing IMCore stuff from different threads --- kordophone/Bridge/MBIMUpdateQueue.h | 4 +- kordophone/Bridge/MBIMUpdateQueue.m | 53 ++++++++++++++++--- .../Bridge/Operations/MBIMBridgeOperation.h | 5 ++ .../Bridge/Operations/MBIMBridgeOperation.m | 27 ++++++++++ .../MBIMConversationListOperation.m | 14 ++--- .../Operations/MBIMFetchAttachmentOperation.m | 10 +--- .../Bridge/Operations/MBIMMarkOperation.m | 37 ++++++------- .../Operations/MBIMMessagesListOperation.m | 43 +++++++-------- .../Operations/MBIMSendMessageOperation.m | 34 ++++++------ .../Operations/MBIMUpdatePollOperation.m | 18 +++++-- 10 files changed, 155 insertions(+), 90 deletions(-) diff --git a/kordophone/Bridge/MBIMUpdateQueue.h b/kordophone/Bridge/MBIMUpdateQueue.h index b66ed94..64d7a1a 100644 --- a/kordophone/Bridge/MBIMUpdateQueue.h +++ b/kordophone/Bridge/MBIMUpdateQueue.h @@ -18,13 +18,13 @@ NS_ASSUME_NONNULL_BEGIN - (NSDictionary *)dictionaryRepresentation; @end -typedef void (^MBIMUpdateConsumer)(MBIMUpdateItem *item); +typedef void (^MBIMUpdateConsumer)(NSArray *items); @interface MBIMUpdateQueue : NSObject + (instancetype)sharedInstance; -- (void)addConsumer:(MBIMUpdateConsumer)consumer; +- (void)addConsumer:(MBIMUpdateConsumer)consumer withLastSyncedMessageSeq:(NSInteger)messageSeq; - (void)removeConsumer:(MBIMUpdateConsumer)consumer; - (void)enqueueUpdateItem:(MBIMUpdateItem *)item; diff --git a/kordophone/Bridge/MBIMUpdateQueue.m b/kordophone/Bridge/MBIMUpdateQueue.m index d8869ae..c8636aa 100644 --- a/kordophone/Bridge/MBIMUpdateQueue.m +++ b/kordophone/Bridge/MBIMUpdateQueue.m @@ -10,6 +10,8 @@ #import "IMMessageItem+Encoded.h" #import "IMChat+Encoded.h" +static const NSUInteger kUpdateItemsCullingLength = 100; + @interface MBIMUpdateItem (/*INTERNAL*/) @property (nonatomic, assign) NSUInteger messageSequenceNumber; @end @@ -18,6 +20,9 @@ NSUInteger _messageSequenceNumber; dispatch_queue_t _accessQueue; NSMutableArray *_consumers; + + // Maps message sequence number to update item + NSMutableDictionary *_updateItemHistory; } + (instancetype)sharedInstance @@ -38,16 +43,30 @@ _accessQueue = dispatch_queue_create("net.buzzert.MBIMUpdateQueue", DISPATCH_QUEUE_SERIAL); _consumers = [[NSMutableArray alloc] init]; _messageSequenceNumber = 0; + _updateItemHistory = [[NSMutableDictionary alloc] init]; } return self; } -- (void)addConsumer:(MBIMUpdateConsumer)consumer +- (void)addConsumer:(MBIMUpdateConsumer)consumer withLastSyncedMessageSeq:(NSInteger)messageSeq { __weak NSMutableArray *consumers = _consumers; + __weak NSMutableDictionary *updateItemHistory = _updateItemHistory; dispatch_async(_accessQueue, ^{ - [consumers addObject:consumer]; + if ((messageSeq >= 0) && messageSeq < self->_messageSequenceNumber) { + NSMutableArray *batchedUpdates = [NSMutableArray array]; + for (NSUInteger seq = messageSeq + 1; seq <= self->_messageSequenceNumber; seq++) { + MBIMUpdateItem *item = [updateItemHistory objectForKey:@(seq)]; + if (item) { + [batchedUpdates addObject:item]; + } + } + + consumer(batchedUpdates); + } else { + [consumers addObject:consumer]; + } }); } @@ -61,16 +80,36 @@ - (void)enqueueUpdateItem:(MBIMUpdateItem *)item { - _messageSequenceNumber++; - item.messageSequenceNumber = _messageSequenceNumber; - __weak NSMutableArray *consumers = _consumers; + __weak NSMutableDictionary *updateItemHistory = _updateItemHistory; dispatch_async(_accessQueue, ^{ + self->_messageSequenceNumber++; + item.messageSequenceNumber = self->_messageSequenceNumber; + for (MBIMUpdateConsumer consumer in consumers) { - consumer(item); + consumer(@[ item ]); } [consumers removeAllObjects]; + [updateItemHistory setObject:item forKey:@(item.messageSequenceNumber)]; + + [self _cullUpdateItems]; + }); +} + +- (void)_cullUpdateItems +{ + __weak NSMutableDictionary *updateItemHistory = _updateItemHistory; + dispatch_async(_accessQueue, ^{ + if ([updateItemHistory count] > kUpdateItemsCullingLength) { + NSArray *sortedKeys = [[updateItemHistory allKeys] sortedArrayUsingSelector:@selector(compare:)]; + for (NSValue *key in sortedKeys) { + [updateItemHistory removeObjectForKey:key]; + if ([updateItemHistory count] <= kUpdateItemsCullingLength) { + break; + } + } + } }); } @@ -80,7 +119,7 @@ - (NSDictionary *)dictionaryRepresentation { NSMutableDictionary *updateDict = [NSMutableDictionary dictionary]; - updateDict[@"messageSequenceNumber"] = @(_messageSequenceNumber); + updateDict[@"messageSequenceNumber"] = @(self.messageSequenceNumber); if ([self changedChat]) { updateDict[@"conversation"] = [[self changedChat] mbim_dictionaryRepresentation]; diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.h b/kordophone/Bridge/Operations/MBIMBridgeOperation.h index 6b09950..b07d1bc 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.h +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.h @@ -23,11 +23,16 @@ typedef void (^MBIMBridgeOperationCompletionBlock)(NSObject * _Nul @property (nonatomic, readonly) NSURL *requestURL; @property (nonatomic, readonly) MBIMBridgeOperationCompletionBlock serverCompletionBlock; ++ (dispatch_queue_t)sharedIMAccessQueue; + + (nullable Class)operationClassForEndpointName:(NSString *)endpointName; - (instancetype)initWithRequestURL:(NSURL *)requestURL completion:(MBIMBridgeOperationCompletionBlock)completionBlock; - (NSObject *)cancelAndReturnTimeoutResponse; +// convenience +- (nullable NSString *)valueForQueryItemWithName:(NSString *)queryItemName; + @end NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.m b/kordophone/Bridge/Operations/MBIMBridgeOperation.m index 40ee4f2..5e1ae26 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.m +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.m @@ -32,6 +32,17 @@ return operationClassMapping; } ++ (dispatch_queue_t)sharedIMAccessQueue +{ + static dispatch_once_t onceToken; + static dispatch_queue_t accessQueue = nil; + dispatch_once(&onceToken, ^{ + accessQueue = dispatch_queue_create("IMAccessQueue", DISPATCH_QUEUE_SERIAL); + }); + + return accessQueue; +} + + (void)load { if ([self class] != [MBIMBridgeOperation class]) { @@ -61,4 +72,20 @@ return [[HTTPErrorResponse alloc] initWithErrorCode:500]; } +- (NSString *)valueForQueryItemWithName:(NSString *)queryItemName +{ + NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:self.requestURL + resolvingAgainstBaseURL:NO]; + + NSString *value = nil; + for (NSURLQueryItem *queryItem in [urlComponents queryItems]) { + if ([[queryItem name] isEqualToString:queryItemName]) { + value = [queryItem value]; + break; + } + } + + return value; +} + @end diff --git a/kordophone/Bridge/Operations/MBIMConversationListOperation.m b/kordophone/Bridge/Operations/MBIMConversationListOperation.m index 06c8473..076346b 100644 --- a/kordophone/Bridge/Operations/MBIMConversationListOperation.m +++ b/kordophone/Bridge/Operations/MBIMConversationListOperation.m @@ -23,13 +23,15 @@ - (void)main { - NSArray *chats = [sChatRegistry allExistingChats]; + __block NSMutableArray *conversations = [NSMutableArray array]; - NSMutableArray *conversations = [NSMutableArray array]; - for (IMChat *chat in chats) { - NSDictionary *chatDict = [chat mbim_dictionaryRepresentation]; - [conversations addObject:chatDict]; - } + dispatch_sync([[self class] sharedIMAccessQueue], ^{ + NSArray *chats = [sChatRegistry allExistingChats]; + for (IMChat *chat in chats) { + NSDictionary *chatDict = [chat mbim_dictionaryRepresentation]; + [conversations addObject:chatDict]; + } + }); MBIMJSONDataResponse *response = [MBIMJSONDataResponse responseWithJSONObject:conversations]; self.serverCompletionBlock(response); diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m index 8ef6426..8d167a0 100644 --- a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m @@ -24,15 +24,7 @@ { 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; - } - } + NSString *guid = [self valueForQueryItemWithName:@"guid"]; if (!guid) { NSLog(@"No query item provided"); diff --git a/kordophone/Bridge/Operations/MBIMMarkOperation.m b/kordophone/Bridge/Operations/MBIMMarkOperation.m index 31c5cd1..5e5f091 100644 --- a/kordophone/Bridge/Operations/MBIMMarkOperation.m +++ b/kordophone/Bridge/Operations/MBIMMarkOperation.m @@ -20,17 +20,9 @@ - (void)main { - NSObject *response = nil; + __block 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; - } - } + NSString *guid = [self valueForQueryItemWithName:@"guid"]; if (!guid) { NSLog(@"No query item provided"); @@ -38,18 +30,19 @@ 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]; - } + dispatch_sync([[self class] sharedIMAccessQueue], ^{ + IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; + if (!chat) { + NSLog(@"Chat with guid: %@ not found", guid); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + } else { + // 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); diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m index a50c282..f58355c 100644 --- a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -23,17 +23,9 @@ - (void)main { - NSObject *response = nil; + __block 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; - } - } + NSString *guid = [self valueForQueryItemWithName:@"guid"]; if (!guid) { NSLog(@"No query item provided"); @@ -41,21 +33,22 @@ break; } - IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; - if (!chat) { - NSLog(@"Chat with guid: %@ not found", guid); - response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; - break; - } - - // Load messages - [chat loadMessagesBeforeDate:[NSDate date] limit:50 loadImmediately:YES]; - - NSMutableArray *messages = [NSMutableArray array]; - for (IMMessageItem *imMessage in [[chat chatItems] messages]) { - NSDictionary *messageDict = [imMessage mbim_dictionaryRepresentation]; - [messages addObject:messageDict]; - } + __block NSMutableArray *messages = [NSMutableArray array]; + dispatch_sync([[self class] sharedIMAccessQueue], ^{ + IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; + if (!chat) { + NSLog(@"Chat with guid: %@ not found", guid); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + } else { + // Load messages + [chat loadMessagesBeforeDate:[NSDate date] limit:50 loadImmediately:YES]; + + for (IMMessageItem *imMessage in [[chat chatItems] messages]) { + NSDictionary *messageDict = [imMessage mbim_dictionaryRepresentation]; + [messages addObject:messageDict]; + } + } + }); response = [MBIMJSONDataResponse responseWithJSONObject:messages]; } while (0); diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index b84c655..cfb545c 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -22,23 +22,27 @@ - (BOOL)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID { - IMChat *chat = [sChatRegistry existingChatWithGUID:chatGUID]; + __block BOOL result = YES; - // TODO: chat might not be an iMessage chat! - IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; - IMHandle *senderHandle = [iMessageAccount loginIMHandle]; + dispatch_sync([[self class] sharedIMAccessQueue], ^{ + IMChat *chat = [sChatRegistry existingChatWithGUID:chatGUID]; + + // TODO: chat might not be an iMessage chat! + IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; + IMHandle *senderHandle = [iMessageAccount loginIMHandle]; + + NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:messageBody]; + IMMessage *reply = [IMMessage fromMeIMHandle:senderHandle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; + + if (!chat) { + NSLog(@"Chat does not exist: %@", chatGUID); + result = NO; + } else { + [chat sendMessage:reply]; + } + }); - NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:messageBody]; - IMMessage *reply = [IMMessage fromMeIMHandle:senderHandle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; - - if (!chat) { - NSLog(@"Chat does not exist: %@", chatGUID); - return NO; - } - - [chat sendMessage:reply]; - - return YES; + return result; } - (void)main diff --git a/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m index 5c3d40d..939743a 100644 --- a/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m +++ b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m @@ -22,15 +22,25 @@ - (void)main { + NSInteger messageSeq = -1; + NSString *messageSeqString = [self valueForQueryItemWithName:@"seq"]; + if (messageSeqString) { + messageSeq = [messageSeqString integerValue]; + } + __weak __auto_type weakSelf = self; - _updateConsumer = ^(MBIMUpdateItem *nextUpdateItem) { - NSDictionary *updateDict = [nextUpdateItem dictionaryRepresentation]; + _updateConsumer = ^(NSArray *updates) { + NSMutableArray *encodedUpdates = [NSMutableArray array]; + for (MBIMUpdateItem *item in updates) { + NSDictionary *updateDict = [item dictionaryRepresentation]; + [encodedUpdates addObject:updateDict]; + } - MBIMJSONDataResponse *response = [MBIMJSONDataResponse responseWithJSONObject:updateDict]; + MBIMJSONDataResponse *response = [MBIMJSONDataResponse responseWithJSONObject:encodedUpdates]; weakSelf.serverCompletionBlock(response); }; - [[MBIMUpdateQueue sharedInstance] addConsumer:_updateConsumer]; + [[MBIMUpdateQueue sharedInstance] addConsumer:_updateConsumer withLastSyncedMessageSeq:messageSeq]; } - (void)cancel From 6aaa2ff5b35827ba8ba9933c8dfa62eef23ee547 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 4 Jan 2019 13:08:28 -0800 Subject: [PATCH 18/75] Plumb guid down for deduplication on the conversation level --- .../Operations/MBIMMessagesListOperation.m | 6 +++--- kordophone/Categories/IMMessageItem+Encoded.h | 5 ----- kordophone/Categories/IMMessageItem+Encoded.m | 18 +++--------------- 3 files changed, 6 insertions(+), 23 deletions(-) diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m index f58355c..2c5b04f 100644 --- a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -43,10 +43,10 @@ // Load messages [chat loadMessagesBeforeDate:[NSDate date] limit:50 loadImmediately:YES]; - for (IMMessageItem *imMessage in [[chat chatItems] messages]) { - NSDictionary *messageDict = [imMessage mbim_dictionaryRepresentation]; + [[chat chatItems] enumerateMessagesWithOptions:0 usingBlock:^(IMMessage *message, BOOL *stop) { + NSDictionary *messageDict = [message mbim_dictionaryRepresentation]; [messages addObject:messageDict]; - } + }]; } }); diff --git a/kordophone/Categories/IMMessageItem+Encoded.h b/kordophone/Categories/IMMessageItem+Encoded.h index 222d704..da78de1 100644 --- a/kordophone/Categories/IMMessageItem+Encoded.h +++ b/kordophone/Categories/IMMessageItem+Encoded.h @@ -16,9 +16,4 @@ NS_ASSUME_NONNULL_BEGIN @end -@interface IMMessageItem (Encoded) -- (NSDictionary *)mbim_dictionaryRepresentation; - -@end - NS_ASSUME_NONNULL_END diff --git a/kordophone/Categories/IMMessageItem+Encoded.m b/kordophone/Categories/IMMessageItem+Encoded.m index 479f3db..25b4084 100644 --- a/kordophone/Categories/IMMessageItem+Encoded.m +++ b/kordophone/Categories/IMMessageItem+Encoded.m @@ -16,21 +16,8 @@ NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; messageDict[@"text"] = [[self text] string]; messageDict[@"date"] = MBIMWebServerFormatISO8601([self time]); - messageDict[@"sender"] = [[self sender] displayID]; - - return messageDict; -} - -@end - -@implementation IMMessageItem (Encoded) - -- (NSDictionary *)mbim_dictionaryRepresentation -{ - NSMutableDictionary *messageDict = [NSMutableDictionary dictionary]; - messageDict[@"text"] = [[self body] string]; - messageDict[@"date"] = MBIMWebServerFormatISO8601([self time]); - messageDict[@"sender"] = [self sender]; + messageDict[@"sender"] = ([self isFromMe] ? nil : [[self sender] displayID]); // TODO: nil sender is still a weird way to represent this... + messageDict[@"guid"] = [self guid]; if ([self fileTransferGUIDs]) { // Support only images right now @@ -51,3 +38,4 @@ } @end + From 90775ebbba4900f7ec8c39f72c5210fcd02c5eaf Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 16 Jan 2019 14:17:31 -0800 Subject: [PATCH 19/75] Attachment uploading support --- MessagesBridge.xcodeproj/project.pbxproj | 6 ++ .../Operations/MBIMSendMessageOperation.m | 20 +++++- .../MBIMUploadAttachmentOperation.h | 17 +++++ .../MBIMUploadAttachmentOperation.m | 66 +++++++++++++++++++ 4 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 1e13936..d556933 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -63,6 +63,7 @@ 1ACFCFDA219EB2AC00E2C237 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */; }; 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */; }; + 1AD8936E21EFD986009B599A /* MBIMUploadAttachmentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AD8936D21EFD986009B599A /* MBIMUploadAttachmentOperation.m */; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */; }; CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A3219FF22700E7DD22 /* IMMessageItem+Encoded.m */; }; @@ -194,6 +195,8 @@ 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocket.h; sourceTree = ""; }; 1ACFCFE2219EB45300E2C237 /* MBIMHTTPConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMHTTPConnection.h; sourceTree = ""; }; 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMHTTPConnection.m; sourceTree = ""; }; + 1AD8936C21EFD986009B599A /* MBIMUploadAttachmentOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMUploadAttachmentOperation.h; sourceTree = ""; }; + 1AD8936D21EFD986009B599A /* MBIMUploadAttachmentOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMUploadAttachmentOperation.m; sourceTree = ""; }; CD14F18B219E2DB400E7DD22 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; CD14F18D219E2DB400E7DD22 /* CryptoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoTests.m; sourceTree = ""; }; CD14F18F219E2DB400E7DD22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -525,6 +528,8 @@ CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */, CD14F19F219FE7D600E7DD22 /* MBIMUpdatePollOperation.h */, CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */, + 1AD8936C21EFD986009B599A /* MBIMUploadAttachmentOperation.h */, + 1AD8936D21EFD986009B599A /* MBIMUploadAttachmentOperation.m */, ); path = Operations; sourceTree = ""; @@ -797,6 +802,7 @@ 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */, CDE455A421A5308D0041F5DD /* MBIMFetchAttachmentOperation.m in Sources */, CD83E156219BE10A00F4CCEA /* hooking.m in Sources */, + 1AD8936E21EFD986009B599A /* MBIMUploadAttachmentOperation.m in Sources */, CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, CDF62335219A895D00690038 /* main.m in Sources */, CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */, diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index cfb545c..0d1202b 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -20,7 +20,7 @@ return @"sendMessage"; } -- (BOOL)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID +- (BOOL)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID attachmentGUIDs:(NSArray *)guids { __block BOOL result = YES; @@ -32,7 +32,16 @@ IMHandle *senderHandle = [iMessageAccount loginIMHandle]; NSAttributedString *replyAttrString = [[NSAttributedString alloc] initWithString:messageBody]; - IMMessage *reply = [IMMessage fromMeIMHandle:senderHandle withText:replyAttrString fileTransferGUIDs:@[] flags:kIMMessageFinished]; + NSAttributedString *attrStringWithFileTransfers = IMCreateSuperFormatStringWithAppendedFileTransfers(replyAttrString, guids); + + IMMessage *reply = [IMMessage fromMeIMHandle:senderHandle + withText:attrStringWithFileTransfers + fileTransferGUIDs:guids + flags:(kIMMessageFinished | kIMMessageIsFromMe)]; + + for (NSString *guid in [reply fileTransferGUIDs]) { + [[IMFileTransferCenter sharedInstance] assignTransfer:guid toHandle:chat.recipient]; + } if (!chat) { NSLog(@"Chat does not exist: %@", chatGUID); @@ -63,7 +72,12 @@ return; } - BOOL result = [self _sendMessage:messageBody toChatWithGUID:guid]; + NSArray *transferGUIDs = [args objectForKey:@"fileTransferGUIDs"]; + if (!transferGUIDs) { + transferGUIDs = @[]; + } + + BOOL result = [self _sendMessage:messageBody toChatWithGUID:guid attachmentGUIDs:transferGUIDs]; if (result) { response = [[HTTPErrorResponse alloc] initWithErrorCode:200]; } diff --git a/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.h b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.h new file mode 100644 index 0000000..91e9fd5 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.h @@ -0,0 +1,17 @@ +// +// MBIMUploadAttachmentOperation.h +// kordophoned +// +// Created by James Magahern on 1/16/19. +// Copyright © 2019 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMUploadAttachmentOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m new file mode 100644 index 0000000..09db295 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m @@ -0,0 +1,66 @@ +// +// MBIMUploadAttachmentOperation.m +// kordophoned +// +// Created by James Magahern on 1/16/19. +// Copyright © 2019 James Magahern. All rights reserved. +// + +#import "MBIMUploadAttachmentOperation.h" +#import "MBIMDataResponse.h" + +#import + +@implementation MBIMUploadAttachmentOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"uploadAttachment"; +} + +- (void)main +{ + NSObject *response = nil; + do { + NSString *filename = [self valueForQueryItemWithName:@"filename"]; + if ([filename length] == 0) { + NSLog(@"No filename provided"); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + NSData *attachmentData = self.requestBodyData; + if ([attachmentData length] == 0) { + NSLog(@"No attachment data in request"); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + NSString *localPath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + NSURL *localURL = [NSURL fileURLWithPath:localPath]; + BOOL success = [attachmentData writeToURL:localURL atomically:NO]; + if (!success) { + NSLog(@"Error writing attachment to temporary directory"); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + NSString *guid = [[IMFileTransferCenter sharedInstance] guidForNewOutgoingTransferWithLocalURL:localURL]; + if (!guid) { + NSLog(@"There was some problem shuttling the file to IMCore"); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + NSDictionary *responseDict = @{ + @"fileTransferGUID" : guid + }; + response = [MBIMJSONDataResponse responseWithJSONObject:responseDict]; + } while (0); + + self.serverCompletionBlock(response); +} + +@end From 0cb907e2adcfd84a08de5740c4c9c3b98db80cd3 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 22 Jan 2019 23:31:36 -0800 Subject: [PATCH 20/75] Experimental SSL support --- MessagesBridge.xcodeproj/project.pbxproj | 66 +++++++++++ .../xcschemes/kordophoned.xcscheme | 2 +- README.md | 25 ++++ agentHook/hookAgent.sh | 1 + kordophone/Bridge/MBIMBridge.h | 6 +- kordophone/Bridge/MBIMBridge.m | 107 ++++++++++++++---- kordophone/Bridge/MBIMBridge_Private.h | 14 +++ kordophone/Bridge/MBIMHTTPConnection.m | 13 +++ .../Operations/MBIMFetchAttachmentOperation.m | 8 +- .../Bridge/Operations/MBIMMarkOperation.m | 4 +- .../Operations/MBIMMessagesListOperation.m | 4 +- .../Operations/MBIMSendMessageOperation.m | 2 +- .../MBIMUploadAttachmentOperation.m | 8 +- kordophone/Hooking/hooking.m | 6 +- kordophone/KPServer.pch | 14 +++ kordophone/Utilities/MBIMLogging.h | 34 ++++++ kordophone/Utilities/MBIMLogging.m | 44 +++++++ kordophone/main.m | 59 ++++++++-- 18 files changed, 370 insertions(+), 47 deletions(-) create mode 100644 kordophone/Bridge/MBIMBridge_Private.h create mode 100644 kordophone/KPServer.pch create mode 100644 kordophone/Utilities/MBIMLogging.h create mode 100644 kordophone/Utilities/MBIMLogging.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index d556933..3e6ee3e 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -10,6 +10,9 @@ 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */; }; 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */; }; 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */; }; + 1AAB32B121F82EB7004A2A72 /* MBIMLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AAB32B021F82EB7004A2A72 /* MBIMLogging.m */; }; + 1AAB32B421F837BB004A2A72 /* hookAgent.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = CD83E1B5219BF78E00F4CCEA /* hookAgent.sh */; }; + 1AAB32B621F83B68004A2A72 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AAB32B521F83B68004A2A72 /* Security.framework */; }; 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE01219EB2AB00E2C237 /* HTTPLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE02219EB2AB00E2C237 /* HTTPMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -106,6 +109,16 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 1AAB32B321F837AF004A2A72 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 7; + files = ( + 1AAB32B421F837BB004A2A72 /* hookAgent.sh in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CDF62330219A895D00690038 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -135,6 +148,11 @@ 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMJSONDataResponse.m; sourceTree = ""; }; 1AA43E93219EC38E00EDF1A7 /* MBIMHTTPUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMHTTPUtilities.h; sourceTree = ""; }; 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMHTTPUtilities.m; sourceTree = ""; }; + 1AAB32AC21F8212E004A2A72 /* MBIMBridge_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridge_Private.h; sourceTree = ""; }; + 1AAB32AF21F82EB7004A2A72 /* MBIMLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMLogging.h; sourceTree = ""; }; + 1AAB32B021F82EB7004A2A72 /* MBIMLogging.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMLogging.m; sourceTree = ""; }; + 1AAB32B221F835BD004A2A72 /* KPServer.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPServer.pch; sourceTree = ""; }; + 1AAB32B521F83B68004A2A72 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.Internal.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CocoaHTTPServer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 1ACFCDFE219EB2AB00E2C237 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = ""; }; @@ -262,6 +280,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1AAB32B621F83B68004A2A72 /* Security.framework in Frameworks */, CD14F1A7219FF2F400E7DD22 /* IMSharedUtilities.framework in Frameworks */, 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */, CDF62343219A9BE200690038 /* ContactsFoundation.framework in Frameworks */, @@ -310,6 +329,7 @@ 1A0C445E219A45B400F2AC00 /* Frameworks */ = { isa = PBXGroup; children = ( + 1AAB32B521F83B68004A2A72 /* Security.framework */, CD14F1A6219FF2F400E7DD22 /* IMSharedUtilities.framework */, CDF62342219A9BE200690038 /* ContactsFoundation.framework */, CDF62340219A9AAA00690038 /* EmailFoundation.framework */, @@ -327,6 +347,7 @@ children = ( CD60204C219B5D710024D9C5 /* Operations */, 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */, + 1AAB32AC21F8212E004A2A72 /* MBIMBridge_Private.h */, 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */, CD14F1A8219FF3B800E7DD22 /* MBIMUpdateQueue.h */, CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */, @@ -334,6 +355,7 @@ CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */, 1ACFCFE2219EB45300E2C237 /* MBIMHTTPConnection.h */, 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */, + 1AAB32A921F81AD0004A2A72 /* Security */, ); path = Bridge; sourceTree = ""; @@ -362,6 +384,22 @@ path = Utilities; sourceTree = ""; }; + 1AAB32A921F81AD0004A2A72 /* Security */ = { + isa = PBXGroup; + children = ( + ); + path = Security; + sourceTree = ""; + }; + 1AAB32AE21F82E73004A2A72 /* Utilities */ = { + isa = PBXGroup; + children = ( + 1AAB32AF21F82EB7004A2A72 /* MBIMLogging.h */, + 1AAB32B021F82EB7004A2A72 /* MBIMLogging.m */, + ); + path = Utilities; + sourceTree = ""; + }; 1ACFCDE3219EB28A00E2C237 /* CocoaHTTPServer */ = { isa = PBXGroup; children = ( @@ -555,10 +593,12 @@ CDF62333219A895D00690038 /* kordophone */ = { isa = PBXGroup; children = ( + 1AAB32AE21F82E73004A2A72 /* Utilities */, CD14F1A5219FF22B00E7DD22 /* Categories */, CD83E150219BDB4F00F4CCEA /* Hooking */, 1A0C446D219A4BCD00F2AC00 /* Bridge */, CDF62334219A895D00690038 /* main.m */, + 1AAB32B221F835BD004A2A72 /* KPServer.pch */, ); path = kordophone; sourceTree = ""; @@ -652,6 +692,7 @@ CD83E15D219BE91500F4CCEA /* Headers */, CD83E15E219BE91500F4CCEA /* Sources */, CD83E15F219BE91500F4CCEA /* Frameworks */, + 1AAB32B321F837AF004A2A72 /* CopyFiles */, ); buildRules = ( ); @@ -669,6 +710,7 @@ CDF6232E219A895D00690038 /* Sources */, CDF6232F219A895D00690038 /* Frameworks */, CDF62330219A895D00690038 /* CopyFiles */, + 1AAB32AD21F8245D004A2A72 /* Add current directory to rpath */, ); buildRules = ( ); @@ -743,6 +785,27 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 1AAB32AD21F8245D004A2A72 /* Add current directory to rpath */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Add current directory to rpath"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nRESULT=$(install_name_tool -delete_rpath $BUILT_PRODUCTS_DIR $BUILT_PRODUCTS_DIR/$EXECUTABLE_NAME 2> /dev/null)\n\ninstall_name_tool -add_rpath $BUILT_PRODUCTS_DIR $BUILT_PRODUCTS_DIR/$EXECUTABLE_NAME\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 1ACFCDDD219EB28A00E2C237 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -802,6 +865,7 @@ 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */, CDE455A421A5308D0041F5DD /* MBIMFetchAttachmentOperation.m in Sources */, CD83E156219BE10A00F4CCEA /* hooking.m in Sources */, + 1AAB32B121F82EB7004A2A72 /* MBIMLogging.m in Sources */, 1AD8936E21EFD986009B599A /* MBIMUploadAttachmentOperation.m in Sources */, CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, CDF62335219A895D00690038 /* main.m in Sources */, @@ -1082,6 +1146,7 @@ buildSettings = { CLANG_ENABLE_MODULES = NO; CODE_SIGN_STYLE = Automatic; + GCC_PREFIX_HEADER = kordophone/KPServer.pch; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx.internal; SYSTEM_FRAMEWORK_SEARCH_PATHS = ( @@ -1096,6 +1161,7 @@ buildSettings = { CLANG_ENABLE_MODULES = NO; CODE_SIGN_STYLE = Automatic; + GCC_PREFIX_HEADER = kordophone/KPServer.pch; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx.internal; SYSTEM_FRAMEWORK_SEARCH_PATHS = ( diff --git a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme index d87e6eb..d505b12 100644 --- a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme +++ b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme @@ -63,7 +63,7 @@ diff --git a/README.md b/README.md index e657bef..e8c32a4 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,28 @@ If you get dyld errors running from the command line, use `install_name_tool` to ## Running You need to hook imagent first to bypass entitlements check. Look at `hookAgent.sh` + + +## SSL +If you want to run with SSL, you have to generate a self-signed certificate, and have the Mac trust the root cert. + +### Generate a root cert +1. Generate root key + `openssl genrsa -out Kordophone-root.key 4096` +2. Generate root certificate + `openssl req -x509 -new -nodes -key Kordophone-root.key -sha256 -days 1024 -out Kordophone-root.crt` + +### Create signing certificate by signing a new cert with the root cert +1. Generate signing key + `openssl genrsa -out kp.localhost.key 2048` +2. Create certificate signing request + `openssl req -new -key kp.localhost.key -out kp.localhost.csr` +3. Sign the cert with the root cert + `openssl x509 -req -in kp.localhost.csr -CA Kordophone-root.crt -CAkey Kordophone-root.key -CAcreateserial -out kp.localhost.crt -days 365 -sha256` +4. kordophoned works with a signing cert in PKCS12 format. Convert the cert and the privkey to PKCS12 + `openssl pkcs12 -export -in kp.localhost.crt -inkey kp.localhost.key -out certificate.p12 -name "Kordophone"` + +### Start kordophone with the SSL options and provide the p12 +`kordophoned -s -c certificate.p12` + + diff --git a/agentHook/hookAgent.sh b/agentHook/hookAgent.sh index 5631265..3c6541b 100755 --- a/agentHook/hookAgent.sh +++ b/agentHook/hookAgent.sh @@ -16,4 +16,5 @@ echo "Telling imagent to launch with inserted libraries for uid $EUID" sudo launchctl debug gui/$EUID/com.apple.imagent --environment DYLD_INSERT_LIBRARIES=$LIB_PATH launchctl kill SIGKILL gui/501/com.apple.imagent +echo "\nYou might have to kill imagent for changes to take effect (killall imagent)" diff --git a/kordophone/Bridge/MBIMBridge.h b/kordophone/Bridge/MBIMBridge.h index a6a5572..d44ce62 100644 --- a/kordophone/Bridge/MBIMBridge.h +++ b/kordophone/Bridge/MBIMBridge.h @@ -14,9 +14,13 @@ NS_ASSUME_NONNULL_BEGIN @interface MBIMBridge : NSObject -@property (nonatomic, assign) const char *dylibPath; +@property (nonatomic, strong) NSString *dylibPath; +@property (nonatomic, assign) UInt16 port; @property (nonatomic, readonly) NSOperationQueue *operationQueue; +@property (nonatomic, assign) BOOL usesSSL; +@property (nonatomic, strong) NSString *sslCertPath; + + (instancetype)sharedInstance; - (instancetype)init NS_UNAVAILABLE; diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index ff2e01a..1a88222 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -7,6 +7,7 @@ // #import "MBIMBridge.h" +#import "MBIMBridge_Private.h" #import "MBIMBridgeOperation.h" #import "MBIMConcurrentHTTPServer.h" #import "MBIMHTTPConnection.h" @@ -21,9 +22,14 @@ #import #import +static const UInt16 kDefaultPort = 5738; + static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; -@interface MBIMBridge (/* INTERNAL */) +@interface MBIMBridge (/* INTERNAL */) { + __strong NSArray *_sslCertificateAndIdentity; +} + @property (nonatomic, strong) MBIMConcurrentHTTPServer *httpServer; @property (nonatomic, strong) NSOperationQueue *operationQueue; @@ -47,11 +53,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; { self = [super init]; if (self) { - [self registerForNotifications]; - [self startWebServer]; - - [sDaemonController setDelegate:self]; - [sDaemonListener addHandler:self]; + self.port = kDefaultPort; _operationQueue = [[NSOperationQueue alloc] init]; _operationQueue.maxConcurrentOperationCount = 5; @@ -63,7 +65,58 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; - (void)_terminate { // *shrug* - exit(0); + exit(1); +} + +- (NSArray *)sslCertificateAndIdentity +{ + if (!_sslCertificateAndIdentity && self.sslCertPath) { + // Get the p12 + NSError *error = nil; + NSData *certData = [NSData dataWithContentsOfFile:self.sslCertPath options:0 error:&error]; + if (!certData || error) { + MBIMLogError(@"Unable to load SSL certificate from file: %@", [error localizedDescription]); + return nil; + } + + CFArrayRef items = nil; + OSStatus status = SecPKCS12Import( + (__bridge CFDataRef)certData, + (__bridge CFDictionaryRef) @{ + (__bridge id)kSecImportExportPassphrase : @"xNAq3vn)^PNu}[&gyQ4MZeV?J" + }, + &items + ); + + if (status != noErr) { + MBIMLogError(@"Error importing PKCS12: SecPKCS12Import status: %d", status); + return nil; + } + + CFDictionaryRef certDict = CFArrayGetValueAtIndex(items, 0); + if (!certDict) { + MBIMLogError(@"Error parsing the SSL certificate"); + return nil; + } + + SecIdentityRef identity = (SecIdentityRef)CFDictionaryGetValue(certDict, kSecImportItemIdentity); + _sslCertificateAndIdentity = @[ (__bridge id)identity ]; + } + + return _sslCertificateAndIdentity; +} + +- (void)checkSSLCertificate +{ + if (self.usesSSL) { + NSArray *certAndIdentity = [self sslCertificateAndIdentity]; + if ([certAndIdentity count]) { + MBIMLogInfo(@"SSL Certificate looks okay"); + } else { + MBIMLogFatal(@"Wasn't able to load SSL certificate. Bailing..."); + [self _terminate]; + } + } } #pragma mark - @@ -76,18 +129,26 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; BOOL hooked = HookIMAgent(self.dylibPath, &errorString); if (!hooked) { NSString *errorNSString = [NSString stringWithUTF8String:errorString]; - NSLog(@"Error hooking imagent: %@", errorNSString); + MBIMLogInfo(@"Error hooking imagent: %@", errorNSString); return; } #endif - if (![sDaemonController hasListenerForID: MBIMBridgeToken]) { + [self registerForNotifications]; + + [sDaemonController setDelegate:self]; + [sDaemonListener addHandler:self]; + + if (![sDaemonController hasListenerForID:MBIMBridgeToken]) { if (![sDaemonController addListenerID:MBIMBridgeToken capabilities:(kFZListenerCapFileTransfers | kFZListenerCapManageStatus | kFZListenerCapChats | kFZListenerCapMessageHistory | kFZListenerCapIDQueries | kFZListenerCapSendMessages)]) { - NSLog(@"Failed to connect to imagent"); + MBIMLogFatal(@"Failed to connect to imagent"); [self _terminate]; } } + + [self checkSSLCertificate]; + [self startWebServer]; } - (void)disconnect @@ -116,7 +177,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; - (void)_messageReceived:(NSNotification *)notification { - NSLog(@"Received message from chat with GUID: %@", [[notification object] guid]); + MBIMLogInfo(@"Received message from chat with GUID: %@", [[notification object] guid]); IMChat *chat = [notification object]; IMMessage *message = [[notification userInfo] objectForKey:IMChatValueKey]; @@ -135,14 +196,14 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; - (void)_chatRegistryDidLoad:(NSNotification *)notification { - NSLog(@"Loaded chat registry. %lu existing chats", (unsigned long)[sChatRegistry numberOfExistingChats]); + MBIMLogInfo(@"Loaded chat registry. %lu existing chats", (unsigned long)[sChatRegistry numberOfExistingChats]); } - (void)_chatItemsDidChange:(NSNotification *)notification { IMChat *chat = [notification object]; if (chat) { - NSLog(@"Chat items change for GUID: %@", [chat guid]); + MBIMLogInfo(@"Chat items change for GUID: %@", [chat guid]); MBIMUpdateItem *updateItem = [[MBIMUpdateItem alloc] init]; updateItem.changedChat = chat; @@ -157,11 +218,13 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; { self.httpServer = [[MBIMConcurrentHTTPServer alloc] init]; [self.httpServer setConnectionClass:[MBIMHTTPConnection class]]; - [self.httpServer setPort:8080]; + [self.httpServer setPort:self.port]; NSError *error = nil; if (![self.httpServer start:&error]) { - NSLog(@"Error starting HTTP server: %@", [error localizedDescription]); + MBIMLogError(@"Error starting HTTP server: %@", [error localizedDescription]); + } else { + MBIMLogNotify(@"Started Kordophone HTTP server on port %u", self.port); } } @@ -170,31 +233,31 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; - (void)daemonControllerWillConnect { - NSLog(@"Connecting to imagent..."); + MBIMLogInfo(@"Connecting to imagent..."); } - (void)daemonControllerDidConnect { - NSLog(@"imagent responded."); + MBIMLogInfo(@"imagent responded."); IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; if (iMessageAccount) { - NSLog(@"Successfully got accounts from imagent"); - NSLog(@"iMessage account connected: %@", iMessageAccount); + MBIMLogInfo(@"Successfully got accounts from imagent"); + MBIMLogInfo(@"iMessage account connected: %@", iMessageAccount); } else { - NSLog(@"imagent returned no accounts (not entitled?)"); + MBIMLogFatal(@"ERROR: imagent returned no accounts (not entitled? speak with Agent Hook)"); [self _terminate]; } } - (void)daemonControllerDidDisconnect { - NSLog(@"Disconnected from imagent"); + MBIMLogInfo(@"Disconnected from imagent"); } - (void)daemonConnectionLost { - NSLog(@"Connection lost to imagent"); + MBIMLogError(@"Connection lost to imagent"); } @end diff --git a/kordophone/Bridge/MBIMBridge_Private.h b/kordophone/Bridge/MBIMBridge_Private.h new file mode 100644 index 0000000..8d1b80d --- /dev/null +++ b/kordophone/Bridge/MBIMBridge_Private.h @@ -0,0 +1,14 @@ +// +// MBIMBridge_Private.h +// MessagesBridge +// +// Created by James Magahern on 1/22/19. +// Copyright © 2019 James Magahern. All rights reserved. +// + +#import "MBIMBridge.h" + +@interface MBIMBridge (/*PRIVATE*/) +- (NSArray *)sslCertificateAndIdentity; + +@end diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index 5773681..da32de6 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -9,13 +9,26 @@ #import "MBIMHTTPConnection.h" #import "MBIMBridge.h" +#import "MBIMBridge_Private.h" #import "MBIMBridgeOperation.h" +#import + @implementation MBIMHTTPConnection { NSMutableData *_bodyData; MBIMBridgeOperation *_currentOperation; } +- (BOOL)isSecureServer +{ + return [[MBIMBridge sharedInstance] usesSSL]; +} + +- (NSArray *)sslIdentityAndCertificates +{ + return [[MBIMBridge sharedInstance] sslCertificateAndIdentity]; +} + - (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path { if ([method isEqualToString:@"GET"] || [method isEqualToString:@"POST"]) { diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m index 8d167a0..114afd0 100644 --- a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m @@ -27,20 +27,20 @@ NSString *guid = [self valueForQueryItemWithName:@"guid"]; if (!guid) { - NSLog(@"No query item provided"); + MBIMLogInfo(@"No query item provided"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } IMFileTransfer *transfer = [[IMFileTransferCenter sharedInstance] transferForGUID:guid]; if (!transfer) { - NSLog(@"No transfer found for guid: %@", guid); + MBIMLogInfo(@"No transfer found for guid: %@", guid); response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; break; } if (![transfer existsAtLocalPath]) { - NSLog(@"We don't have the file for this yet (still downloading to server?)"); + MBIMLogInfo(@"We don't have the file for this yet (still downloading to server?)"); response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; break; } @@ -48,7 +48,7 @@ NSString *localPath = [transfer localPath]; NSData *responseData = [NSData dataWithContentsOfFile:localPath]; if (!responseData) { - NSLog(@"Wasn't able to load data from local path: %@", localPath); + MBIMLogInfo(@"Wasn't able to load data from local path: %@", localPath); response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; break; } diff --git a/kordophone/Bridge/Operations/MBIMMarkOperation.m b/kordophone/Bridge/Operations/MBIMMarkOperation.m index 5e5f091..08992c7 100644 --- a/kordophone/Bridge/Operations/MBIMMarkOperation.m +++ b/kordophone/Bridge/Operations/MBIMMarkOperation.m @@ -25,7 +25,7 @@ NSString *guid = [self valueForQueryItemWithName:@"guid"]; if (!guid) { - NSLog(@"No query item provided"); + MBIMLogInfo(@"No query item provided"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } @@ -33,7 +33,7 @@ dispatch_sync([[self class] sharedIMAccessQueue], ^{ IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; if (!chat) { - NSLog(@"Chat with guid: %@ not found", guid); + MBIMLogInfo(@"Chat with guid: %@ not found", guid); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; } else { // TODO: be smarter about this and mark individual messages as read? Could lead diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m index 2c5b04f..e15e121 100644 --- a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -28,7 +28,7 @@ NSString *guid = [self valueForQueryItemWithName:@"guid"]; if (!guid) { - NSLog(@"No query item provided"); + MBIMLogInfo(@"No query item provided"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } @@ -37,7 +37,7 @@ dispatch_sync([[self class] sharedIMAccessQueue], ^{ IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; if (!chat) { - NSLog(@"Chat with guid: %@ not found", guid); + MBIMLogInfo(@"Chat with guid: %@ not found", guid); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; } else { // Load messages diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index 0d1202b..a69e21e 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -44,7 +44,7 @@ } if (!chat) { - NSLog(@"Chat does not exist: %@", chatGUID); + MBIMLogInfo(@"Chat does not exist: %@", chatGUID); result = NO; } else { [chat sendMessage:reply]; diff --git a/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m index 09db295..b77832e 100644 --- a/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m @@ -26,14 +26,14 @@ do { NSString *filename = [self valueForQueryItemWithName:@"filename"]; if ([filename length] == 0) { - NSLog(@"No filename provided"); + MBIMLogInfo(@"No filename provided"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } NSData *attachmentData = self.requestBodyData; if ([attachmentData length] == 0) { - NSLog(@"No attachment data in request"); + MBIMLogInfo(@"No attachment data in request"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } @@ -42,14 +42,14 @@ NSURL *localURL = [NSURL fileURLWithPath:localPath]; BOOL success = [attachmentData writeToURL:localURL atomically:NO]; if (!success) { - NSLog(@"Error writing attachment to temporary directory"); + MBIMLogInfo(@"Error writing attachment to temporary directory"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } NSString *guid = [[IMFileTransferCenter sharedInstance] guidForNewOutgoingTransferWithLocalURL:localURL]; if (!guid) { - NSLog(@"There was some problem shuttling the file to IMCore"); + MBIMLogInfo(@"There was some problem shuttling the file to IMCore"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; break; } diff --git a/kordophone/Hooking/hooking.m b/kordophone/Hooking/hooking.m index 3b98af6..0921629 100644 --- a/kordophone/Hooking/hooking.m +++ b/kordophone/Hooking/hooking.m @@ -13,7 +13,7 @@ BOOL HookIMAgent(const char *relativeDylibPath, char **errorString) { - NSLog(@"Hooking imagent"); + MBIMLogInfo(@"Hooking imagent"); const char *hookDylibPath = realpath(relativeDylibPath, NULL); @@ -61,10 +61,10 @@ BOOL HookIMAgent(const char *relativeDylibPath, char **errorString) return NO; } - NSLog(@"Successfully setup environment variables"); + MBIMLogInfo(@"Successfully setup environment variables"); // Kill imagent so the new one has the loaded bundle - NSLog(@"Killing imagent..."); + MBIMLogInfo(@"Killing imagent..."); int killAgentSuccess = system("killall imagent"); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ diff --git a/kordophone/KPServer.pch b/kordophone/KPServer.pch new file mode 100644 index 0000000..bb2f752 --- /dev/null +++ b/kordophone/KPServer.pch @@ -0,0 +1,14 @@ +// +// KPServer.pch +// MessagesBridge +// +// Created by James Magahern on 1/22/19. +// Copyright © 2019 James Magahern. All rights reserved. +// + +#ifndef KPServer_h +#define KPServer_h + +#include "MBIMLogging.h" + +#endif /* KPServer_h */ diff --git a/kordophone/Utilities/MBIMLogging.h b/kordophone/Utilities/MBIMLogging.h new file mode 100644 index 0000000..31ce4b9 --- /dev/null +++ b/kordophone/Utilities/MBIMLogging.h @@ -0,0 +1,34 @@ +// +// MBIMLogging.h +// kordophoned +// +// Created by James Magahern on 1/22/19. +// Copyright © 2019 James Magahern. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef enum { + ML_INFO, + ML_NOTIFY, + ML_ERROR, + ML_FATAL +} MBIMLogLevel; + +extern void __MBIMLogCommon(MBIMLogLevel level, NSString *format, ...); + +#define MBIMLogInfo(format, ...) \ + __MBIMLogCommon(ML_INFO, format, ##__VA_ARGS__) + +#define MBIMLogNotify(format, ...) \ + __MBIMLogCommon(ML_NOTIFY, format, ##__VA_ARGS__) + +#define MBIMLogError(format, ...) \ + __MBIMLogCommon(ML_ERROR, format, ##__VA_ARGS__) + +#define MBIMLogFatal(format, ...) \ + __MBIMLogCommon(ML_FATAL, format, ##__VA_ARGS__) + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Utilities/MBIMLogging.m b/kordophone/Utilities/MBIMLogging.m new file mode 100644 index 0000000..d089e26 --- /dev/null +++ b/kordophone/Utilities/MBIMLogging.m @@ -0,0 +1,44 @@ +// +// MBIMLogging.m +// kordophoned +// +// Created by James Magahern on 1/22/19. +// Copyright © 2019 James Magahern. All rights reserved. +// + +#import "MBIMLogging.h" + +#define ESC(inner) "\033[" inner "m" +#define CLR ESC("0") +#define BLD "1;" +#define RED "31;" + +extern void __MBIMLogCommon(MBIMLogLevel level, NSString *format, ...) +{ + static dispatch_once_t onceToken; + static NSDateFormatter *dateFormatter = nil; + dispatch_once(&onceToken, ^{ + dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.dateFormat = @"Y-MM-d HH:mm:ss"; + }); + + va_list args; + va_start(args, format); + NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + const char *c_fmt = "%s"; + if (level == ML_NOTIFY) { + // BOLD + c_fmt = ESC(BLD) "%s"; + } else if (level == ML_ERROR) { + c_fmt = ESC(RED) "%s"; + } else if (level == ML_FATAL) { + c_fmt = ESC(BLD RED) "%s"; + } + + NSString *dateStr = [dateFormatter stringFromDate:[NSDate date]]; + fprintf(stdout, "%s: ", [dateStr UTF8String]); + fprintf(stdout, c_fmt, [message UTF8String]); + fprintf(stdout, CLR "\n"); +} diff --git a/kordophone/main.m b/kordophone/main.m index 8e90311..a9a4e22 100644 --- a/kordophone/main.m +++ b/kordophone/main.m @@ -10,18 +10,62 @@ #import "MBIMBridge.h" -int main(int argc, const char * argv[]) { +void printUsage() +{ + fprintf(stderr, "Usage: kordophoned [-h] [-s | -c (certificate.p12)]\n"); + fprintf(stderr, "\t-h \t Show this help message\n"); + fprintf(stderr, "\t-s \t Use SSL (requires -c option)\n"); + fprintf(stderr, "\t-c \t SSL certificate path encoded as pkcs12\n"); +} + +int main(int argc, char *const argv[]) { @autoreleasepool { - MBIMBridge *bridge = [MBIMBridge sharedInstance]; + BOOL usesSSL = NO; + BOOL showHelp = NO; + const char *certPath = NULL; -#if HOOK_IMAGENT - if (argc < 2) { - fprintf(stderr, "Usage: kordophoned agentHook.dylib\n"); + int c = -1; + while ( (c = getopt(argc, argv, "hsc:")) != -1 ) { + switch (c) { + case 's': + usesSSL = YES; + break; + case 'c': + certPath = optarg; + break; + case 'h': + showHelp = YES; + break; + case '?': + if (optopt == 'c') { + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + } else if (isprint(optopt)) { + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + } else { + fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); + return 1; + } + default: + abort (); + } + } + + if (showHelp) { + printUsage(); return 1; } - bridge.dylibPath = argv[1]; -#endif + if (usesSSL && certPath == NULL) { + fprintf(stderr, "Error: wants SSL (-s) but no ssl certificate path (-c) provided\n"); + return 1; + } + + MBIMBridge *bridge = [MBIMBridge sharedInstance]; + + if (usesSSL && certPath != NULL) { + bridge.usesSSL = YES; + bridge.sslCertPath = [NSString stringWithCString:certPath encoding:NSASCIIStringEncoding]; + } [bridge connect]; @@ -30,5 +74,6 @@ int main(int argc, const char * argv[]) { [[NSRunLoop currentRunLoop] run]; } } + return 0; } From e6314b0f80941f471a37070321df48e4750254bd Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 22 Jan 2019 23:32:35 -0800 Subject: [PATCH 21/75] Addendum to README regarding self-signed ssl certs --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e8c32a4..3e5a0df 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ If you want to run with SSL, you have to generate a self-signed certificate, and `openssl genrsa -out Kordophone-root.key 4096` 2. Generate root certificate `openssl req -x509 -new -nodes -key Kordophone-root.key -sha256 -days 1024 -out Kordophone-root.crt` +3. Add this certificate to the Mac's trust store via Keychain Access. Set to "Always Trust" ### Create signing certificate by signing a new cert with the root cert 1. Generate signing key From de852a926d0e497be946051b1e403fc88dd06d0a Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 23 Jan 2019 20:26:35 -0800 Subject: [PATCH 22/75] Basic authentication support --- .../xcschemes/kordophoned.xcscheme | 2 +- README.md | 10 ++ kordophone/Bridge/MBIMBridge.h | 4 + kordophone/Bridge/MBIMHTTPConnection.m | 22 +++++ kordophone/main.m | 98 ++++++++++++++++++- 5 files changed, 133 insertions(+), 3 deletions(-) diff --git a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme index d505b12..b3bcf4c 100644 --- a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme +++ b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme @@ -63,7 +63,7 @@ diff --git a/README.md b/README.md index 3e5a0df..b08eeed 100644 --- a/README.md +++ b/README.md @@ -40,4 +40,14 @@ If you want to run with SSL, you have to generate a self-signed certificate, and ### Start kordophone with the SSL options and provide the p12 `kordophoned -s -c certificate.p12` +## Authentication +Basic Authentication is also optional, but requires SSL to be enabled as well. To configure basic authentication, create a file containing your username and password on two separate lines encrypted with your GPG key. + +`echo "username\npassword" > password.txt"` +`gpg -e -r (your email) -o password.asc password.txt` + +Then run kordophoned with the following option +`kordophone -s -c certificate.p12 -a password.asc` + +You may need to unlock your GPG keyring (via gpg-agent) when running kordophoned the first time. diff --git a/kordophone/Bridge/MBIMBridge.h b/kordophone/Bridge/MBIMBridge.h index d44ce62..5a6d031 100644 --- a/kordophone/Bridge/MBIMBridge.h +++ b/kordophone/Bridge/MBIMBridge.h @@ -18,6 +18,10 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign) UInt16 port; @property (nonatomic, readonly) NSOperationQueue *operationQueue; +@property (nonatomic, assign) BOOL usesAccessControl; +@property (nonatomic, strong) NSString *authUsername; +@property (nonatomic, strong) NSString *authPassword; + @property (nonatomic, assign) BOOL usesSSL; @property (nonatomic, strong) NSString *sslCertPath; diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index da32de6..5f3ef9a 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -29,6 +29,28 @@ return [[MBIMBridge sharedInstance] sslCertificateAndIdentity]; } +- (BOOL)isPasswordProtected:(NSString *)path +{ + return [[MBIMBridge sharedInstance] usesAccessControl]; +} + +- (NSString *)passwordForUser:(NSString *)username +{ + MBIMBridge *bridge = [MBIMBridge sharedInstance]; + if ([username isEqualToString:bridge.authUsername]) { + return bridge.authPassword; + } + + return @""; +} + +- (BOOL)useDigestAccessAuthentication +{ + // TODO: should use digest all the time, but it's a bit more complicated. Allow this to be NO if + // SSL is on, because then at least basic auth is encrypted + return ![[MBIMBridge sharedInstance] usesSSL]; +} + - (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path { if ([method isEqualToString:@"GET"] || [method isEqualToString:@"POST"]) { diff --git a/kordophone/main.m b/kordophone/main.m index a9a4e22..50689b5 100644 --- a/kordophone/main.m +++ b/kordophone/main.m @@ -12,20 +12,83 @@ void printUsage() { - fprintf(stderr, "Usage: kordophoned [-h] [-s | -c (certificate.p12)]\n"); + fprintf(stderr, "Usage: kordophoned [-h] [-s | -c (certificate.p12)] [-a (access control file)\n"); fprintf(stderr, "\t-h \t Show this help message\n"); fprintf(stderr, "\t-s \t Use SSL (requires -c option)\n"); fprintf(stderr, "\t-c \t SSL certificate path encoded as pkcs12\n"); + fprintf(stderr, "\t-a \t Optional GPG encrypted access control file\n"); +} + +BOOL acquireCredentials(const char *accessFile, NSString **out_username, NSString **out_password) +{ + NSPipe *stdoutPipe = [NSPipe pipe]; + NSPipe *stderrPipe = [NSPipe pipe]; + NSTask *task = [[NSTask alloc] init]; + task.launchPath = @"/usr/local/bin/gpg"; + task.arguments = @[ @"-q", @"-d", [NSString stringWithUTF8String:accessFile] ]; + task.standardOutput = stdoutPipe; + task.standardError = stderrPipe; + + NSError *launchError = nil; + BOOL success = [task launchAndReturnError:&launchError]; + [task waitUntilExit]; + + if (success) { + NSFileHandle *stdoutFile = stdoutPipe.fileHandleForReading; + NSData *data = [stdoutFile readDataToEndOfFile]; // blocks + [stdoutFile closeFile]; + + if ([task terminationStatus] != 0) { + NSData *stderrData = [[stderrPipe fileHandleForReading] readDataToEndOfFile]; + MBIMLogFatal(@"GPG error when decrypting access file: %@", [[NSString alloc] initWithData:stderrData encoding:NSUTF8StringEncoding]); + return NO; + } + + NSString *asString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSScanner *scanner = [NSScanner scannerWithString:asString]; + + BOOL scannerSuccess = NO; + NSString *username = nil; + scannerSuccess = [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] + intoString:&username]; + if (!scannerSuccess) { + MBIMLogFatal(@"Error parsing username from access file"); + return NO; + } + + NSString *password = nil; + scannerSuccess = [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] + intoString:&password]; + if (!scannerSuccess) { + MBIMLogFatal(@"Error parsing password from access file"); + return NO; + } + + if ([username length] && [password length]) { + *out_username = username; + *out_password = password; + } else { + MBIMLogFatal(@"Error parsing username or password from access file"); + return NO; + } + } else { + MBIMLogFatal(@"Unable to launch GPG executable to decrypt access file: %@", [launchError localizedDescription]); + return NO; + } + + return YES; } int main(int argc, char *const argv[]) { @autoreleasepool { BOOL usesSSL = NO; BOOL showHelp = NO; + BOOL usesAccessControl = NO; const char *certPath = NULL; + const char *accessFilePath = NULL; int c = -1; - while ( (c = getopt(argc, argv, "hsc:")) != -1 ) { + while ( (c = getopt(argc, argv, "hsc:a:")) != -1 ) { switch (c) { case 's': usesSSL = YES; @@ -33,6 +96,10 @@ int main(int argc, char *const argv[]) { case 'c': certPath = optarg; break; + case 'a': + usesAccessControl = YES; + accessFilePath = optarg; + break; case 'h': showHelp = YES; break; @@ -62,6 +129,33 @@ int main(int argc, char *const argv[]) { MBIMBridge *bridge = [MBIMBridge sharedInstance]; + if (usesAccessControl) { + NSString *username = nil; + NSString *password = nil; + + BOOL success = acquireCredentials(accessFilePath, &username, &password); + if (!success) { + MBIMLogInfo( + @"Access file must be a GPG encrypted file (encrypted with your private key, to your pub key) " + "with the follwing format: \n" + "(username)\n" + "(password)" + ); + + return 1; + } else { + const ssize_t ast_len = 55; + const unichar asterisks[ast_len] = u"*******************************************************"; + NSString *obscuredPassword = [NSString stringWithCharacters:asterisks + length:MIN([password length], ast_len)]; + MBIMLogNotify(@"Using access control credentials: username(%@) password(%@)", username, obscuredPassword); + + bridge.usesAccessControl = YES; + bridge.authUsername = username; + bridge.authPassword = password; + } + } + if (usesSSL && certPath != NULL) { bridge.usesSSL = YES; bridge.sslCertPath = [NSString stringWithCString:certPath encoding:NSASCIIStringEncoding]; From 6c089f737b3f07f34caac802b990f5d19421f644 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sun, 3 Mar 2019 14:23:54 -0800 Subject: [PATCH 23/75] Not sure why, but mimeType is not always populated --- .../Bridge/Operations/MBIMFetchAttachmentOperation.m | 7 +++++++ kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m index 114afd0..b7cc8b7 100644 --- a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m @@ -54,6 +54,13 @@ } NSString *mimeType = [transfer mimeType]; + // It's unusual, but if this is nil, try to guess the MIME type based on the filename + if (!mimeType) { + NSString *extension = [[localPath pathExtension] lowercaseString]; + + // XXX: REALLY hacky + mimeType = [NSString stringWithFormat:@"image/%@", extension]; + } response = [[MBIMDataResponse alloc] initWithData:responseData contentType:mimeType]; } while (0); diff --git a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m index e6ea79d..8758de0 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m +++ b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m @@ -25,7 +25,7 @@ - (NSDictionary *)httpHeaders { return @{ - @"Content-Type" : _contentType + @"Content-Type" : _contentType ?: @"application/octet-stream" }; } From 4f7a6d1b8756a689f47171b429f96600e608a14c Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 16 Dec 2019 17:29:53 -0800 Subject: [PATCH 24/75] Move off of macosxinternal sdk This moves kordophone off of using the internal SDK and switches to using class dumped headers instead. --- Config Files/DebugDefaults.xcconfig | 88 - Config Files/OSXDebugDefaults.xcconfig | 5 - Config Files/OSXReleaseDefaults.xcconfig | 5 - Config Files/ReleaseDefaults.xcconfig | 36 - Dumped Classes/IMCore_ClassDump.h | 4976 +++++++++++++++++ Dumped Classes/IMFoundation_ClassDump.h | 1900 +++++++ Dumped Classes/IMSharedUtilities_ClassDump.h | 1698 ++++++ MessagesBridge.xcodeproj/project.pbxproj | 34 +- .../xcschemes/kordophoned.xcscheme | 10 +- .../SOAPlugInControllerProtocol.h | 16 - kordophone/Bridge/MBIMBridge.m | 19 +- kordophone/Bridge/MBIMUpdateQueue.h | 4 +- .../MBIMConversationListOperation.m | 4 +- .../Operations/MBIMFetchAttachmentOperation.m | 2 +- .../Bridge/Operations/MBIMMarkOperation.m | 4 +- .../Operations/MBIMMessagesListOperation.m | 4 +- .../Operations/MBIMSendMessageOperation.m | 5 +- .../MBIMUploadAttachmentOperation.m | 2 +- kordophone/Categories/IMChat+Encoded.h | 2 +- kordophone/Categories/IMMessageItem+Encoded.h | 3 +- 20 files changed, 8610 insertions(+), 207 deletions(-) delete mode 100644 Config Files/DebugDefaults.xcconfig delete mode 100644 Config Files/OSXDebugDefaults.xcconfig delete mode 100644 Config Files/OSXReleaseDefaults.xcconfig delete mode 100644 Config Files/ReleaseDefaults.xcconfig create mode 100644 Dumped Classes/IMCore_ClassDump.h create mode 100644 Dumped Classes/IMFoundation_ClassDump.h create mode 100644 Dumped Classes/IMSharedUtilities_ClassDump.h delete mode 100644 Pilfered Headers/SOAPlugInControllerProtocol.h diff --git a/Config Files/DebugDefaults.xcconfig b/Config Files/DebugDefaults.xcconfig deleted file mode 100644 index a0dda08..0000000 --- a/Config Files/DebugDefaults.xcconfig +++ /dev/null @@ -1,88 +0,0 @@ -// -// Many defines in this file are based on the selected SDK; it does not set an SDK. -// NOTE: This is inherited by ALL projects and all types, be careful in here -// - -// ####################### HEADER SEARCH PATHS ######################## - -HEADER_SEARCH_PATHS = $(SDK_DIR)/usr/local/include $(SDK_DIR)/usr/include - -// ##################### FRAMEWORK SEARCH PATHS ####################### - -ALWAYS_SEARCH_USER_PATHS = NO -FRAMEWORK_SEARCH_PATHS[sdk=macosx*] = $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks $(SDK_DIR)/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks -FRAMEWORK_SEARCH_PATHS[sdk=embedded*] = $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks -FRAMEWORK_SEARCH_PATHS[sdk=embeddedsimulator*] = $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks - -// ###################### LIBRARY SEARCH PATHS ######################## - -LIBRARY_SEARCH_PATHS[sdk=embedded*] = $(SDK_DIR)/usr/local/lib $(SDK_DIR)/usr/lib -LIBRARY_SEARCH_PATHS[sdk=embeddedsimulator*] = $(SDK_DIR)/usr/local/lib $(SDK_DIR)/usr/lib - -// ############################# FLAGS ################################ - -OTHER_CFLAGS = -Wshadow -DIM_DEBUG -D_FORTIFY_SOURCE=2 -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations -OTHER_CFLAGS[sdk=embedded*] = -Wshadow -DIM_DEBUG -D_FORTIFY_SOURCE=2 -DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations -OTHER_CFLAGS[sdk=embeddedsimulator*] = -Wshadow -DIM_DEBUG -D_FORTIFY_SOURCE=2 -DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations - -WARNING_CFLAGS = -Wno-error=deprecated-declarations - -// ######################### ARCHITECTURES ########################### - -ARCHS[sdk=macosx*] = $(ARCHS_STANDARD_64_BIT) - -VALID_ARCHS[sdk=macosx*] = x86_64 -VALID_ARCHS[sdk=embeddedsimulator*] = i386 x86_64 - -// ######################### CONFIGURATION ########################### - -CODE_SIGN_IDENTITY = - - -DYLIB_CURRENT_VERSION = 800 -DYLIB_COMPATIBILITY_VERSION = 1 - -CLANG_WARN_CONSTANT_CONVERSION = YES; -CLANG_WARN_ENUM_CONVERSION = YES; -CLANG_WARN_INT_CONVERSION = YES; -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - -GCC_WARN_UNINITIALIZED_AUTOS = YES; -GCC_WARN_UNUSED_VARIABLE = YES; - -ONLY_ACTIVE_ARCH = YES - -TARGETED_DEVICE_FAMILY = 1,2 -TARGETED_DEVICE_FAMILY[sdk=watch*] = 4 - -// ######################## INSTALLATION ############################# - -SKIP_INSTALL = NO - -// ########################### CLANG ################################# - -CLANG_MODULES_AUTOLINK = NO -RUN_CLANG_STATIC_ANALYZER = YES - -// ######################### COMPILER ################################ - -GCC_VERSION = com.apple.compilers.llvm.clang.1_0; -GCC_WARN_ABOUT_RETURN_TYPE = YES - -// ######################### LANGUAGE MISC ########################### - -GCC_C_LANGUAGE_STANDARD = c99 - -// ########################## DEBUGGING ############################## - -GCC_OPTIMIZATION_LEVEL = 0 - -// ############################ MISC ################################# - -VERSIONING_SYSTEM = apple-generic - -// ############################ USER OVERRIDE ################################# - -// Override global settings in a git ignored UserDebug.xcconfig file at the repo root. -// I seem to have to restart Xcode if I add/remove this file. -#include? "UserDebug.xcconfig" - diff --git a/Config Files/OSXDebugDefaults.xcconfig b/Config Files/OSXDebugDefaults.xcconfig deleted file mode 100644 index 5630ba2..0000000 --- a/Config Files/OSXDebugDefaults.xcconfig +++ /dev/null @@ -1,5 +0,0 @@ -// -// To be used by OSX targets -// - -SDKROOT = macosx.internal \ No newline at end of file diff --git a/Config Files/OSXReleaseDefaults.xcconfig b/Config Files/OSXReleaseDefaults.xcconfig deleted file mode 100644 index 695d65e..0000000 --- a/Config Files/OSXReleaseDefaults.xcconfig +++ /dev/null @@ -1,5 +0,0 @@ -#include "OSXDebugDefaults.xcconfig" - -// -// To be used by OSX targets -// diff --git a/Config Files/ReleaseDefaults.xcconfig b/Config Files/ReleaseDefaults.xcconfig deleted file mode 100644 index be6e3e4..0000000 --- a/Config Files/ReleaseDefaults.xcconfig +++ /dev/null @@ -1,36 +0,0 @@ -#include "DebugDefaults.xcconfig" - -// #################### INSTALLATION FLAGS ##################### - -SKIP_INSTALL = NO - -// ####################### DEBUG FLAGS ######################### - -STRIP_INSTALLED_PRODUCT = YES -STRIP_STYLE = non-global; - -COPY_PHASE_STRIP = YES - -GCC_OPTIMIZATION_LEVEL = s -GCC_GENERATE_DEBUGGING_SYMBOLS = YES -GCC_SYMBOLS_PRIVATE_EXTERN = YES - -ONLY_ACTIVE_ARCH = NO - -DEBUG_INFORMATION_FORMAT = dwarf-with-dsym - -// ######################### C FLAGS ########################### - -OTHER_CFLAGS = -Wshadow -D_FORTIFY_SOURCE=2 -D__IMCORE_INTERNAL__ -OTHER_CFLAGS[sdk=embedded*] = -Wshadow -D_FORTIFY_SOURCE=2 -DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations -OTHER_CFLAGS[sdk=embeddedsimulator*] = -Wshadow -D_FORTIFY_SOURCE=2 -DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS -D__IMCORE_INTERNAL__ -Wno-error=deprecated-declarations - -// ########################## CLANG ############################ - -RUN_CLANG_STATIC_ANALYZER = NO - -// ####################### Order File ########################## - -ORDER_FILE = Order Files/$(PROJECT_NAME).order - -GCC_PREPROCESSOR_DEFINITIONS = NDEBUG diff --git a/Dumped Classes/IMCore_ClassDump.h b/Dumped Classes/IMCore_ClassDump.h new file mode 100644 index 0000000..16bee13 --- /dev/null +++ b/Dumped Classes/IMCore_ClassDump.h @@ -0,0 +1,4976 @@ +// +// Generated by class-dump 3.5 (64 bit). +// +// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard. +// + +#import "IMSharedUtilities_ClassDump.h" + +NSAttributedString *IMCreateSuperFormatStringWithAppendedFileTransfers(NSAttributedString *inString, NSArray *fileTransferGUIDs) NS_RETURNS_RETAINED; +NSAttributedString *IMCreateSuperFormatStringByAttachingMessageParts(NSAttributedString *inString) NS_RETURNS_RETAINED; + +typedef NS_ENUM(uint64_t, IMMessageFlags) { + kIMMessageFinished = 0x1, + kIMMessageIsEmote = 0x2, + kIMMessageIsFromMe = 0x4, + kIMMessageIsEmpty = 0x8, + kIMMessageIsDelayed = 0x20, + kIMMessageIsAutoReply = 0x40, + kIMMessageIsAlert = 0x200, + kIMMessageIsAddressedToMe = 0x800, + kIMMessageIsDelivered = 0x1000, + kIMMessageIsRead = 0x2000, + kIMMessageIsSystemMessage = 0x4000, + kIMMessageIsSent = 0x8000, + kIMMessageHasDDResults = 0x10000, + kIMMessageIsServiceMessage = 0x20000, + kIMMessageIsForward = 0x40000, + kIMMessageWasDowngraded = 0x80000, + kIMMessageWasDataDetected = 0x100000, + kIMMessageIsAudioMessage = 0x200000, + kIMMessageIsPlayed = 0x400000, + kIMMessageIsLocatingMessage = 0x800000, + kIMMessageIsExpirable = 0x1000000, + kIMMessageIsFromExtSource = 0x2000000, + kIMMessageLegacyBits = 0xee000000, +}; + +typedef uint32_t FZListenerCapabilities; +extern const FZListenerCapabilities kFZListenerCapManageStatus; +extern const FZListenerCapabilities kFZListenerCapNotifications; +extern const FZListenerCapabilities kFZListenerCapChats; +extern const FZListenerCapabilities kFZListenerCapAppleVC; +extern const FZListenerCapabilities kFZListenerCapAVChatInfo; +extern const FZListenerCapabilities kFZListenerCapAuxInput; +extern const FZListenerCapabilities kFZListenerCapVCInvitations; +extern const FZListenerCapabilities kFZListenerCapAppleLegacyVC; +extern const FZListenerCapabilities kFZListenerCapFileTransfers; +extern const FZListenerCapabilities kFZListenerCapAccounts; +extern const FZListenerCapabilities kFZListenerCapBuddyList; +extern const FZListenerCapabilities kFZListenerCapSendMessages; +extern const FZListenerCapabilities kFZListenerCapMessageHistory; +extern const FZListenerCapabilities kFZListenerCapIDQueries; +extern const FZListenerCapabilities kFZListenerCapChatCountsObserver; +extern const FZListenerCapabilities kFZListenerCapSentMessageObserver; +extern const FZListenerCapabilities kFZListenerCapDatabaseUpdateObserver; +extern const FZListenerCapabilities kFZListenerCapModifyReadState; +extern const FZListenerCapabilities kFZListenerCapAppleAC; +extern const FZListenerCapabilities kFZListenerCapAVObserver; +extern const FZListenerCapabilities kFZListenerCapOnDemandChatRegistry; +extern const FZListenerCapabilities kFZListenerCapTruncatedChatRegistry; +extern const FZListenerCapabilities kFZListenerCapOneTimeCode; +extern const FZListenerCapabilities kFZListenerCapSkipLastMessageLoad; +extern const FZListenerCapabilities kFZListenerCapEvenMoreTruncatedChatRegistry; +extern const FZListenerCapabilities kFZListenerCapBlackholedChatRegistry; + +extern NSString *const IMChatMessageReceivedNotification; // IMChatValueKey = IMMessage +extern NSString *const IMChatMessageSendFailedNotification; // IMChatValueKey = IMMessage +extern NSString *const IMChatRegistryDidLoadNotification; +extern NSString *const IMChatItemsDidChangeNotification; +extern NSString *const IMChatRegistryUnreadCountChangedNotification; + +extern NSString *const IMChatValueKey; +extern NSString *const IMChatOldValueKey; +extern NSString *const IMChatIndexKey; +extern NSString *const IMChatQueryIDKey; +extern NSString *const IMChatErrorKey; + +#pragma mark Blocks + +typedef void (^CDUnknownBlockType)(void); // return type and parameters are unknown + +#pragma mark Named Structures + +struct IMAssociatedMessageGeometryDescriptor { + unsigned long long layoutIntent; + unsigned long long associatedLayoutIntent; + float parentPreviewWidth; + float xScalar; + float yScalar; + float scale; + float rotation; +}; + +struct _FZChatRoomValidity { + int _field1; + unsigned short _field2; +}; + + +#pragma mark - + +// +// File: Versions/A/IMCore +// UUID: CF1C1FD6-2BE4-320F-BDFD-C9547A2D9010 +// +// Arch: x86_64 +// Current version: 800.0.0 +// Compatibility version: 1.0.0 +// Source version: 1981.1.15.0.0 +// +// Objective-C Garbage Collection: Unsupported +// + +@interface IMDirectlyObservableObject : NSObject +{ + NSArray *_observers; +} + +@property(retain) NSArray *observers; // @synthesize observers=_observers; + +- (void)informObserversOfNotification:(id)arg1; +- (void)removeObserver:(id)arg1; +- (void)addObserver:(id)arg1; +- (void)_objectDidPostNotification:(id)arg1; +- (void)dealloc; + +@end + +__attribute__((visibility("default"))) @interface IMService : NSObject { } + ++ (NSURL *)imageURLForStatus:(NSNumber *)status; + ++ (NSArray *)allServices; ++ (IMService *)serviceWithName:(NSString *)name; ++ (NSNotificationCenter *)notificationCenter; ++ (NSNumber *)myStatus; ++ (NSDate*)myIdleTime; +- (NSString *)localizedName; +- (NSString *)localizedShortName; +- (NSString*)name; +- (NSNumber *)status; +- (NSDictionary *)infoForScreenName: (NSString*)screenName; +- (NSArray *)infoForAllScreenNames; +- (NSArray *)infoForPreferredScreenNames; +- (NSArray *)peopleWithScreenName:(NSString *)screenName; +// - (NSArray *)screenNamesForPerson:(ABPerson *)person; + +@end + + +@interface IMService (IMService_GetService) ++ (id)smsService; ++ (id)iMessageService; ++ (id)facetimeService; ++ (id)callService; ++ (id)jabberService; ++ (id)subnetService; ++ (id)aimService; +@end + + +@class IMAccount; +@interface IMServiceImpl : IMService +{ + NSString *_name; + NSString *_localizedName; + NSString *_localizedShortName; + NSMutableDictionary *_cardMap; + NSDictionary *_personToIDMap; + NSString *_countryCode; + IMAccount *_bestAccount; + NSDictionary *_serviceDefaults; + NSDictionary *_serviceProps; + NSDictionary *_defaultSettings; + NSData *_imageData; + NSArray *_abProperties; + NSArray *_emailDomains; + NSArray *_siblingServiceNames; + unsigned int _screenNameSensitivity; + BOOL _hasLoadedServiceProperties; + BOOL _handlesChatInvites; + BOOL _supportsSMS; + BOOL _supportsPhoneNumberMapping; + BOOL _supportsGroupAttachments; + BOOL _supportsMutatingGroupMembers; + BOOL _supportsOneSessionForAllAccounts; + BOOL _supportsAuthorization; + BOOL _supportsRegistration; + BOOL _supportsAdding; + BOOL _supportsPresence; + BOOL _supportsIDStatusLookup; + BOOL _supportsDatabaseStorage; + BOOL _supportsAudioMessages; + BOOL _shouldInternationalizeNumbers; + BOOL _supportsOfflineTransfers; + BOOL _shouldDisableDeactivation; + BOOL _ignoresNetworkConnectivity; + BOOL _isPersistent; + BOOL _isPlugInService; + BOOL _allowsMultipleConnections; +} + ++ (BOOL)systemSupportsSendingAttachmentsOfTypes:(id)arg1 error:(long long *)arg2; ++ (BOOL)systemSupportsSMSSending; ++ (id)supportedCountryCodes; ++ (BOOL)iMessageEnabled; ++ (BOOL)mmsEnabled; ++ (BOOL)smsEnabled; ++ (BOOL)iMessageEnabledForSenderLastAddressedHandle:(id)arg1 simID:(id)arg2 previousService:(id)arg3; ++ (BOOL)iMessageEnabledForSenderLastAddressedHandle:(id)arg1 simID:(id)arg2; ++ (BOOL)hasAlias:(id)arg1 onAccountForService:(id)arg2; ++ (BOOL)mmsEnabledforPhoneNumber:(id)arg1 simID:(id)arg2; ++ (id)operationalServicesWithCapability:(unsigned long long)arg1; ++ (id)connectedServicesWithCapability:(unsigned long long)arg1; ++ (id)servicesWithCapability:(unsigned long long)arg1; ++ (id)connectedServices; ++ (id)activeServices; ++ (id)serviceWithInternalName:(id)arg1; ++ (id)serviceWithName:(id)arg1; ++ (id)allServicesNonBlocking; ++ (id)allServices; ++ (void)setServiceClass:(Class)arg1; ++ (Class)serviceClass; +@property(readonly, nonatomic) NSString *shortName; // @synthesize shortName=_localizedShortName; +@property(readonly, nonatomic) NSString *name; // @synthesize name=_name; +@property(readonly, nonatomic) NSArray *emailDomains; // @synthesize emailDomains=_emailDomains; +@property(readonly, nonatomic) NSArray *addressBookProperties; // @synthesize addressBookProperties=_abProperties; +@property(readonly, nonatomic) unsigned int IDSensitivity; // @synthesize IDSensitivity=_screenNameSensitivity; +@property(readonly, nonatomic) BOOL shouldDisableDeactivation; // @synthesize shouldDisableDeactivation=_shouldDisableDeactivation; +@property(readonly, nonatomic) BOOL allowsMultipleConnections; // @synthesize allowsMultipleConnections=_allowsMultipleConnections; +@property(readonly, nonatomic) BOOL isPlugInService; // @synthesize isPlugInService=_isPlugInService; +@property(readonly, nonatomic) BOOL supportsAdding; // @synthesize supportsAdding=_supportsAdding; +@property(readonly, nonatomic) BOOL supportsGroupAttachments; // @synthesize supportsGroupAttachments=_supportsGroupAttachments; +@property(readonly, nonatomic) BOOL supportsOneSessionForAllAccounts; // @synthesize supportsOneSessionForAllAccounts=_supportsOneSessionForAllAccounts; +@property(readonly, nonatomic) BOOL supportsMutatingGroupMembers; // @synthesize supportsMutatingGroupMembers=_supportsMutatingGroupMembers; +@property(readonly, nonatomic) BOOL supportsPresence; // @synthesize supportsPresence=_supportsPresence; +@property(readonly, nonatomic) BOOL supportsOfflineTransfers; // @synthesize supportsOfflineTransfers=_supportsOfflineTransfers; +@property(readonly, nonatomic) BOOL ignoresNetworkConnectivity; // @synthesize ignoresNetworkConnectivity=_ignoresNetworkConnectivity; +@property(readonly, nonatomic) BOOL supportsRegistration; // @synthesize supportsRegistration=_supportsRegistration; +@property(readonly, nonatomic) BOOL handlesChatInvites; // @synthesize handlesChatInvites=_handlesChatInvites; +@property(readonly, nonatomic) BOOL isPersistent; // @synthesize isPersistent=_isPersistent; +@property(readonly, nonatomic) BOOL supportsAuthorization; // @synthesize supportsAuthorization=_supportsAuthorization; +@property(readonly, nonatomic) BOOL supportsPhoneNumberMapping; // @synthesize supportsPhoneNumberMapping=_supportsPhoneNumberMapping; +@property(readonly, nonatomic) BOOL supportsAudioMessages; // @synthesize supportsAudioMessages=_supportsAudioMessages; +@property(readonly, nonatomic) BOOL supportsIDStatusLookup; // @synthesize supportsIDStatusLookup=_supportsIDStatusLookup; +@property(retain, nonatomic) NSDictionary *defaultAccountSettings; // @synthesize defaultAccountSettings=_defaultSettings; +@property(retain, nonatomic) NSDictionary *serviceDefaults; // @synthesize serviceDefaults=_serviceDefaults; + +@property(readonly, nonatomic) Class accountClass; +- (void)activeAccountsChanged:(id)arg1; +- (void)defaultsChanged:(id)arg1; +- (id)screenNamesForPerson:(id)arg1; +- (id)screenNamesForIMPerson:(id)arg1; +- (id)_personToIDMap; +- (id)peopleWithScreenName:(id)arg1; +- (id)imABPeopleWithScreenName:(id)arg1 options:(unsigned long long)arg2; +- (id)imABPeopleWithScreenName:(id)arg1; +- (id)imABPeopleWithScreenName:(id)arg1 identifier:(int *)arg2; +- (id)imABPeopleWithScreenName:(id)arg1 countryCode:(id)arg2 identifier:(int *)arg3; +@property(readonly, nonatomic) NSDictionary *cardMap; +- (void)clearIDToCardMap; +@property(retain, nonatomic) NSString *countryCode; +- (void)updateIDToCardMapWithNotification:(id)arg1; +- (id)_newIDToCardMap; +- (void)_dumpCardMap; +- (void)_addAddressBookCards:(id)arg1 toMap:(id)arg2; +- (id)_IDsToMapForIMPerson:(id)arg1; +- (id)description; +@property(readonly, nonatomic) NSArray *accountIDs; +@property(readonly, nonatomic) long long buddyNotesMaxByteLength; +@property(readonly, nonatomic) NSString *internalName; +@property(readonly, nonatomic) NSArray *siblingServices; +@property(readonly, nonatomic) NSString *addressBookProperty; +- (id)localizedShortName; +- (id)localizedName; +@property(readonly, nonatomic) BOOL _wantsInternationizedNumbers; +@property(readonly, nonatomic) BOOL _supportsDatabaseStorage; +- (BOOL)isEnabled; +@property(readonly, nonatomic) long long maxAttachmentSize; +- (long long)maxChatParticipantsForHandle:(id)arg1 simID:(id)arg2; +@property(readonly, nonatomic) NSData *serviceImageData; +- (id)subtypeInformationForAccount:(id)arg1; +@property(retain, nonatomic) NSDictionary *serviceProperties; +- (void)_loadPropertiesIfNeeded; +- (id)_abPropertiesBySanitizingABProperties:(id)arg1; +- (id)myScreenNames; +- (id)infoForPreferredScreenNames; +- (id)infoForAllScreenNames; +- (id)infoForScreenName:(id)arg1; +- (unsigned long long)status; +- (void)_blockUntilInitialSyncPerformed; +- (long long)compareNames:(id)arg1; +- (id)canonicalFormOfID:(id)arg1; +- (id)normalizedFormOfID:(id)arg1; +- (BOOL)equalID:(id)arg1 andID:(id)arg2; +- (void)statusChangedForAccount:(id)arg1 from:(unsigned long long)arg2 to:(unsigned long long)arg3; +- (void)disconnect; +- (void)doneSetup; +- (BOOL)initialSyncPerformed; +- (void)_calculateBestAccount; +- (void)_syncWithRemoteBuddies; +- (void)dealloc; +- (id)initWithName:(id)arg1; +@property(readonly, nonatomic, getter=isDiscontinued) BOOL discontinued; +@property(readonly, getter=isLegacyService) BOOL legacyService; // @dynamic legacyService; + +@end + +@class IMPeople, IMHandle; +@interface IMAccount : NSObject +{ + IMServiceImpl *_service; + IMPeople *_buddyList; + NSRecursiveLock *_lock; + NSMapTable *_imHandles; + IMHandle *_loginIMHandle; + NSArray *_cachedAllowList; + NSArray *_cachedBlockList; + NSString *_loginID; + NSString *_displayName; + NSString *_uniqueID; + long long _accountType; + NSString *_strippedLogin; + NSDictionary *_data; + NSMutableDictionary *_dataChanges; + NSMutableDictionary *_localCache; + NSDictionary *_profile; + NSMutableDictionary *_profileChanges; + NSString *_countryCode; + long long _profileStatus; + NSDictionary *_accountPreferences; + NSMutableDictionary *_accountPreferencesChanges; + NSDictionary *_accountPersistentProperties; + NSMutableDictionary *_accountPersistentPropertiesChanges; + NSArray *_groups; + NSMutableDictionary *_sortOrders; + NSDictionary *_members; + NSMutableDictionary *_coalescedChanges; + NSArray *_targetGroupState; + NSArray *_lastReceivedGroupState; + NSDictionary *_subtypeInfo; + NSArray *_vettedAliases; + NSArray *_aliases; + unsigned long long _myStatus; + NSMutableDictionary *_currentAccountStatus; + NSString *_myStatusMessage; + NSDictionary *_myNowPlaying; + NSDate *_myIdleSince; + NSData *_myPictureData; + NSData *_accountImageData; + unsigned long long _capabilities; + unsigned long long _defaultHandleCapabilities; + BOOL _hasCheckedDefaultHandleCapabilities; + NSAttributedString *_myProfile; + long long _registrationStatus; + long long _registrationFailureReason; + NSDictionary *_registrationAlertInfo; + unsigned long long _loginStatus; + BOOL _isActive; + BOOL _hasPostedOfflineNotification; + BOOL _justLoggedIn; + BOOL _useMeCardName; + unsigned int _cachedBlockingMode; + BOOL _blockIdleStatus; + BOOL _syncedWithRemoteBuddyList; + BOOL _hasReceivedSync; + int _numHolding; + int _coalesceCount; + BOOL _needToCheckForWatchedIMHandles; + BOOL _iconChecked; + BOOL _hasBeenRemoved; + id _smallImage; + id _accountImage; + BOOL _asleep; +} + ++ (id)allBuddyListIMHandles; ++ (id)arrayOfAllIMHandles; ++ (id)nameOfLoginStatus:(unsigned long long)arg1; ++ (id)_groupSummaryFromGroupList:(id)arg1; ++ (void)removeTemporaryPasswordForAccount:(id)arg1 forServiceName:(id)arg2; ++ (void)setTemporaryPassword:(id)arg1 forAccount:(id)arg2 forAuthID:(id)arg3 forServiceName:(id)arg4; ++ (id)temporaryPasswordForAccount:(id)arg1 forAuthID:(id)arg2 forServiceName:(id)arg3; ++ (void)removePasswordForAccount:(id)arg1 forServiceName:(id)arg2; ++ (void)setPassword:(id)arg1 forAccount:(id)arg2 forAuthID:(id)arg3 forServiceName:(id)arg4; ++ (id)passwordForAccount:(id)arg1 forServiceName:(id)arg2; +@property(readonly, nonatomic) BOOL justLoggedIn; // @synthesize justLoggedIn=_justLoggedIn; +@property(readonly, nonatomic) IMPeople *buddyList; // @synthesize buddyList=_buddyList; +@property(readonly, nonatomic) id loginIMHandle; // @synthesize loginIMHandle=_loginIMHandle; +@property(readonly, nonatomic) NSDictionary *accountSubtypeInfo; // @synthesize accountSubtypeInfo=_subtypeInfo; +@property(readonly, nonatomic) BOOL isActive; // @synthesize isActive=_isActive; +@property(nonatomic) unsigned int blockingMode; // @synthesize blockingMode=_cachedBlockingMode; +@property(nonatomic) BOOL blockIdleStatus; // @synthesize blockIdleStatus=_blockIdleStatus; +@property(readonly, nonatomic) unsigned long long loginStatus; // @synthesize loginStatus=_loginStatus; +@property(readonly, nonatomic) unsigned long long capabilities; // @synthesize capabilities=_capabilities; +@property(readonly, nonatomic) NSDate *myIdleSince; // @synthesize myIdleSince=_myIdleSince; +@property(readonly, nonatomic) NSData *myPictureData; // @synthesize myPictureData=_myPictureData; +@property(readonly, nonatomic) NSString *myStatusMessage; // @synthesize myStatusMessage=_myStatusMessage; +@property(readonly, nonatomic) unsigned long long myStatus; // @synthesize myStatus=_myStatus; +@property(readonly, nonatomic) NSAttributedString *myProfile; // @synthesize myProfile=_myProfile; +@property(readonly, nonatomic) NSDictionary *myStatusDictionary; // @synthesize myStatusDictionary=_currentAccountStatus; +@property(readonly, nonatomic) __weak IMServiceImpl *service; // @synthesize service=_service; +@property(readonly, nonatomic) NSString *strippedLogin; // @synthesize strippedLogin=_strippedLogin; +@property(retain, nonatomic) NSString *login; // @synthesize login=_loginID; + +- (void)_handleIncomingCommand:(id)arg1 withProperties:(id)arg2 fromBuddyInfo:(id)arg3; +- (void)_handleDeliveredCommand:(id)arg1 withProperties:(id)arg2 fromBuddyInfo:(id)arg3; +- (BOOL)_updateDisplayName:(id)arg1; +@property(copy, nonatomic) NSString *displayName; +- (void)setInteger:(int)arg1 forPreferenceKey:(id)arg2; +- (int)integerForPreferenceKey:(id)arg1; +- (void)setBool:(BOOL)arg1 forPreferenceKey:(id)arg2; +- (BOOL)boolForPreferenceKey:(id)arg1; +- (void)setString:(id)arg1 forPreferenceKey:(id)arg2; +- (id)stringForPreferenceKey:(id)arg1; +- (id)dictionaryDataForPreferenceKey:(id)arg1; +- (void)setDictionaryData:(id)arg1 forPreferenceKey:(id)arg2; +- (void)removeObjectForPreferenceKey:(id)arg1; +- (void)setObject:(id)arg1 forPreferenceKey:(id)arg2; +- (id)objectForPreferenceKey:(id)arg1; +@property(readonly, nonatomic) NSDictionary *accountPreferences; +- (void)_removePersistentPropertyForKey:(id)arg1; +- (void)_setPersistentPropertyObject:(id)arg1 forKey:(id)arg2; +- (id)_persistentPropertyForKey:(id)arg1; +@property(readonly, nonatomic) NSDictionary *_persistentProperties; +@property(readonly, nonatomic) BOOL isAsleep; +- (void)systemWillSleep; +- (void)systemDidWake; +- (void)_setInteger:(long long)arg1 forKey:(id)arg2; +- (void)setInteger:(long long)arg1 forKey:(id)arg2; +- (long long)integerForKey:(id)arg1; +- (void)_setBool:(BOOL)arg1 forKey:(id)arg2; +- (void)setBool:(BOOL)arg1 forKey:(id)arg2; +- (BOOL)boolForKey:(id)arg1; +- (void)_setString:(id)arg1 forKey:(id)arg2; +- (void)setString:(id)arg1 forKey:(id)arg2; +- (id)stringForKey:(id)arg1; +- (id)dictionaryDataForKey:(id)arg1; +- (void)_setDictionaryData:(id)arg1 forKey:(id)arg2; +- (void)setDictionaryData:(id)arg1 forKey:(id)arg2; +- (void)_removeObjectForKey:(id)arg1; +- (void)removeObjectForKey:(id)arg1; +- (void)setObject:(id)arg1 forKey:(id)arg2; +- (void)_setLocalCachedObject:(id)arg1 forKey:(id)arg2; +- (void)_setObject:(id)arg1 forKey:(id)arg2; +- (id)objectForKey:(id)arg1; +- (long long)validationErrorReasonForAlias:(id)arg1 type:(long long)arg2; +- (long long)validationErrorReasonForAlias:(id)arg1; +- (long long)validationStatusForAlias:(id)arg1 type:(long long)arg2; +- (long long)validationStatusForAlias:(id)arg1; +- (BOOL)validateAlias:(id)arg1 type:(long long)arg2; +- (BOOL)validateAliases:(id)arg1; +- (BOOL)validateAlias:(id)arg1; +- (BOOL)unvalidateAliases:(id)arg1; +- (BOOL)unvalidateAlias:(id)arg1; +- (long long)typeForAlias:(id)arg1; +- (BOOL)removeAlias:(id)arg1 type:(long long)arg2; +- (BOOL)removeAliases:(id)arg1; +- (BOOL)removeAlias:(id)arg1; +- (BOOL)addAlias:(id)arg1 type:(long long)arg2; +- (BOOL)addAliases:(id)arg1; +- (BOOL)addAlias:(id)arg1; +- (id)aliasesForType:(long long)arg1; +- (BOOL)hasAlias:(id)arg1 type:(long long)arg2; +- (BOOL)hasAlias:(id)arg1; +- (void)_invalidateCachedAliases; +@property(readonly, nonatomic) NSArray *aliases; +@property(readonly, nonatomic, getter=isMakoAccount) BOOL makoAccount; +- (id)_statuses; +- (id)_aliasInfoForAlias:(id)arg1; +- (BOOL)_aliasIsVisible:(id)arg1; +- (id)_aliases; +@property(readonly, nonatomic) NSArray *aliasesToRegister; +@property(readonly, nonatomic) NSArray *vettedAliases; +- (void)_updateProfileInfo:(id)arg1; +- (long long)profileValidationErrorReason; +- (long long)profileValidationStatus; +- (BOOL)validateProfile; +- (BOOL)setProfileString:(id)arg1 forKey:(id)arg2; +- (BOOL)setProfileValue:(id)arg1 forKey:(id)arg2; +- (BOOL)removeProfileValueForKey:(id)arg1; +- (id)profileStringForKey:(id)arg1; +- (id)profileValueForKey:(id)arg1; +@property(readonly, nonatomic) NSDictionary *profileInfo; +@property(readonly, nonatomic) NSString *countryCode; +- (BOOL)updateAuthorizationCredentials:(id)arg1 token:(id)arg2; +- (void)enrollSelfDeviceInSMSRelay; +- (void)unEnrollDeviceInSMSRelay:(id)arg1; +- (void)enrollDeviceInSMSRelay:(id)arg1; +- (BOOL)authenticateAccount; +- (BOOL)requestNewAuthorizationCredentials; +@property(readonly, nonatomic) NSString *authorizationToken; +@property(readonly, nonatomic) NSString *authorizationID; +@property(readonly, nonatomic) BOOL supportsAuthorization; +- (struct _FZChatRoomValidity)validityOfChatRoomName:(id)arg1; +- (id)defaultChatSuffix; +- (id)chatIDForRoomName:(id)arg1; +- (void)nowLoggedOut; +- (void)nowLoggedIn; +- (void)handleSubscriptionRequestFrom:(id)arg1 withMessage:(id)arg2; +- (void)imHandle:(id)arg1 buddyStatusChanged:(BOOL)arg2; +- (void)disconnectAllIMHandles; +- (void)unregisterIMHandleWithID:(id)arg1; +- (void)registerIMHandle:(id)arg1; +- (void)_refreshLoginIMHandle; +- (void)forgetAllWatches; +- (void)stopWatchingIMHandle:(id)arg1; +- (void)startWatchingIMHandle:(id)arg1; +- (void)watchBuddiesIfNecessary; +- (void)_watchBuddiesIfNecessary; +- (BOOL)removeIMHandle:(id)arg1 fromIMPerson:(id)arg2; +- (BOOL)addIMHandle:(id)arg1 toIMPerson:(id)arg2; +- (id)imHandlesForIMPerson:(id)arg1; +- (void)requestBuddyListAuthorizationFromIMHandle:(id)arg1; +- (void)setBuddyListAuthorization:(BOOL)arg1 forIMHandle:(id)arg2; +- (unsigned long long)sortOrderForIMHandle:(id)arg1 inGroup:(id)arg2; +- (id)personSibsForIMHandle:(id)arg1; +- (id)personForIMHandle:(id)arg1 identifier:(int *)arg2; +- (id)personForIMHandle:(id)arg1; +- (id)imHandleWithID:(id)arg1; +- (id)existingIMHandleWithID:(id)arg1 countryCode:(id)arg2; +- (id)imHandleWithID:(id)arg1 countryCode:(id)arg2; +- (id)_imHandleWithID:(id)arg1 alreadyCanonical:(BOOL)arg2 originalID:(id)arg3 countryCode:(id)arg4; +- (id)imHandleWithID:(id)arg1 alreadyCanonical:(BOOL)arg2; +- (unsigned long long)defaultHandleCapabilities; +- (id)existingIMHandleWithID:(id)arg1; +- (id)existingIMHandleWithID:(id)arg1 alreadyCanonical:(BOOL)arg2; +- (id)existingIMHandleWithInfo:(id)arg1 alreadyCanonical:(BOOL)arg2; +- (id)imHandleWithInfo:(id)arg1 alreadyCanonical:(BOOL)arg2; +- (id)existingIMHandleWithInfo:(id)arg1; +- (id)imHandleWithInfo:(id)arg1; +- (Class)imHandleClass; +@property(readonly, nonatomic) NSArray *arrayOfAllIMHandles; +- (void)recalculateSubtypeInfo; +- (void)_clearImageCache; +- (id)recalculatedSubtypeInfo; +- (long long)compareNames:(id)arg1; +- (void)groupsChanged:(id)arg1 error:(id)arg2; +- (void)_syncWithRemoteBuddies; +- (void)setIMAccountLoginStatus:(unsigned long long)arg1 errorMessage:(id)arg2 reason:(int)arg3; +- (void)setIMAccountLoginStatus:(unsigned long long)arg1 errorMessage:(id)arg2; +- (void)setIMAccountLoginStatus:(unsigned long long)arg1; +- (void)setIsActive:(BOOL)arg1; +@property(readonly, nonatomic) BOOL isConnected; +@property(readonly, nonatomic) BOOL isConnecting; +@property(readonly, nonatomic) NSString *loginStatusMessage; +- (void)_notJustLoggedIn; +- (BOOL)unregisterAccount; +- (BOOL)registerAccount; +@property(readonly, nonatomic) long long registrationFailureReason; +@property(readonly, nonatomic) long long registrationStatus; +- (void)_updateRegistrationStatus:(int)arg1 error:(int)arg2 info:(id)arg3; +@property(readonly, nonatomic) BOOL supportsRegistration; +@property(readonly, nonatomic) NSDictionary *registrationFailureAlertInfo; +@property(readonly, nonatomic) BOOL canSendMessages; +@property(readonly, nonatomic) BOOL isOperational; +@property(readonly, nonatomic) BOOL isRegistered; +@property(readonly, nonatomic) BOOL _isUsableForSending; +- (void)accountDidDeactivate; +- (void)accountDidBecomeActive; +- (void)accountWillBeRemoved; +- (void)_serviceDidDisconnect:(id)arg1; +- (void)_serviceDidReconnect:(id)arg1; +- (void)_serviceDidConnect:(id)arg1; +- (void)_registrationStatusChanged:(id)arg1; +- (void)setBuddyProperties:(id)arg1 buddyPictures:(id)arg2; +- (void)buddyPictureChanged:(id)arg1 imageData:(id)arg2 imageHash:(id)arg3; +- (void)buddyPropertiesChanged:(id)arg1; +- (void)resumeBuddyUpdates; +- (void)_resumeBuddyUpdatesNow; +- (void)holdBuddyUpdates; +@property(readonly, nonatomic) BOOL makingChanges; +- (void)endChanges; +- (id)memberGroups:(id)arg1; +@property(readonly, nonatomic) NSArray *groupList; +- (id)groupMembers:(id)arg1; +- (id)propertiesForGroup:(id)arg1; +- (void)reorderGroups:(id)arg1; +- (void)reorderGroup:(id)arg1 order:(id)arg2; +- (void)renameGroup:(id)arg1 to:(id)arg2; +- (void)changeBuddyList:(id)arg1 add:(BOOL)arg2 groups:(id)arg3 atLocation:(long long)arg4; +- (void)addBuddyToBuddyList:(id)arg1; +- (BOOL)removeIMHandle:(id)arg1 fromGroups:(id)arg2; +- (BOOL)addIMHandle:(id)arg1 toGroups:(id)arg2 atLocation:(long long)arg3; +- (BOOL)removePeople:(id)arg1 fromGroups:(id)arg2; +- (BOOL)addPeople:(id)arg1 toGroups:(id)arg2 atLocation:(long long)arg3; +- (void)_ensureGroupsExists:(id)arg1; +- (void)syncWithRemoteBuddies; +- (void)_markHasSyncedWithRemoteBuddies; +@property(readonly, nonatomic) BOOL hasSyncedWithRemoteBuddies; +- (void)requestGroups; +- (void)hookupToDaemon; +- (void)beginChanges; +- (void)_applyChangesToTemporaryCache:(id)arg1; +- (void)setTargetGroupsState:(id)arg1; +- (void)updateWithTargetGroups; +- (void)setWaitForTargetState; +- (void)targetGroupStateTimeout; +@property(readonly, nonatomic) BOOL hasTargetGroupStateBeenMet; +@property(readonly, nonatomic) BOOL isAwaitingTargetGroupState; +- (void)clearTargetState; +@property(nonatomic) BOOL blockOtherAddresses; +@property(retain, nonatomic) NSArray *allowList; +@property(retain, nonatomic) NSArray *blockList; +- (void)blockMessages:(BOOL)arg1 fromID:(id)arg2; +- (void)setCachedBlockIdleStatus:(BOOL)arg1; +- (void)setCachedBlockingMode:(unsigned int)arg1; +- (void)setCachedBlockList:(id)arg1; +- (void)setCachedAllowList:(id)arg1; +@property(readonly, nonatomic) NSArray *emailDomains; +@property(readonly, nonatomic) NSString *addressBookProperty; +@property(readonly, nonatomic) NSArray *addressBookProperties; +@property(readonly, nonatomic) NSDictionary *dictionary; +- (void)loadFromDictionary:(id)arg1; +- (void)_loadFromDictionary:(id)arg1 force:(BOOL)arg2; +- (void)setValue:(id)arg1 ofExtraProperty:(id)arg2 ofIMHandle:(id)arg3; +- (void)requestProperty:(id)arg1 ofIMHandle:(id)arg2; +@property(readonly, nonatomic) long long invalidSettings; +@property(readonly, nonatomic) BOOL isManaged; +@property(readonly, nonatomic) BOOL validServer; +@property(readonly, nonatomic) BOOL validPort; +@property(readonly, nonatomic) BOOL validLogin; +@property(readonly, nonatomic) BOOL canActivate; +@property(readonly, nonatomic) BOOL isSMSRelayCapable; +@property(readonly, nonatomic) BOOL allowsMMSRelay; +@property(readonly, nonatomic) BOOL allowsSMSRelay; +@property(nonatomic) BOOL allowsVCRelay; +@property(nonatomic) BOOL goIdle; +@property(readonly, nonatomic) long long port; +@property(readonly, nonatomic) NSString *server; +- (id)_serverWithSSL:(BOOL)arg1; +- (id)description; +@property(readonly, nonatomic) BOOL useSSL; +@property(nonatomic) BOOL autoLogin; +@property(readonly, nonatomic) BOOL hasCustomDescription; +@property(retain, nonatomic) NSString *accountDescription; +@property(nonatomic, getter=isInvisible) BOOL invisible; +- (void)removeTemporaryPassword; +- (void)setTemporaryPassword:(id)arg1; +@property(readonly, nonatomic) NSString *temporaryPassword; +- (void)removePassword; +- (void)setPassword:(id)arg1; +@property(readonly, nonatomic) NSString *password; +@property(readonly, nonatomic) BOOL handlesChatInvites; +- (void)updateCapabilities:(unsigned long long)arg1; +- (BOOL)hasCapability:(unsigned long long)arg1; +- (long long)compareServices:(id)arg1; +- (long long)compareIDs:(id)arg1; +- (long long)compareStatus:(id)arg1; +- (long long)compareAccountNames:(id)arg1; +- (long long)compareLoginStatus:(id)arg1; +- (BOOL)emailAddressIsID:(id)arg1; +- (void)resetToDefaults; +- (void)writeSettings; +- (BOOL)equalID:(id)arg1 andID:(id)arg2; +- (id)canonicalFormOfID:(id)arg1 countryCode:(id)arg2; +- (id)canonicalFormOfID:(id)arg1; +@property(readonly, nonatomic) NSData *accountImageData; +@property(readonly, nonatomic) NSString *serviceName; +@property(readonly, nonatomic) NSString *name; +@property(readonly, nonatomic) NSString *internalName; +@property(readonly, nonatomic) NSString *shortName; +- (void)setUniqueID:(id)arg1; +@property(readonly, nonatomic) NSString *uniqueID; +@property(readonly, nonatomic) NSString *myNowPlayingString; +- (void)setCurrentAccountStatus:(id)arg1; +- (void)_updateMyStatus:(unsigned long long)arg1 message:(id)arg2; +@property(readonly, nonatomic) long long accountType; +- (void)_updateLogin:(id)arg1; +- (void)loginStatusChanged:(unsigned int)arg1 message:(id)arg2 reason:(int)arg3 properties:(id)arg4; +- (void)logoutAccount; +- (void)loginAccount; +- (void)autoLoginAccount; +- (void)_loginWithAutoLogin:(BOOL)arg1; +- (id)initWithUniqueID:(id)arg1 service:(id)arg2; +- (id)initWithService:(id)arg1; +- (void)clearServiceCaches; +- (void)dealloc; + +@end + +@class IMPerson; +@interface IMHandle : IMDirectlyObservableObject +{ + IMAccount *_account; + NSString *_id; + NSString *_uncanonicalID; + NSString *_countryCode; + NSDictionary *_otherServiceIDs; + NSDate *_idleSince; + NSDate *_feedUpdatedDate; + NSDictionary *_extraProps; + NSDictionary *_certs; + NSSet *_groups; + IMPerson *_person; + NSString *_abFirstName; + NSString *_abLastName; + NSString *_abFullName; + NSString *_abNickname; + NSString *_displayID; + NSString *_firstName; + NSString *_lastName; + NSString *_fullName; + NSString *_nickname; + NSArray *_emails; + NSString *_normalizedFormOfID; + NSString *_IDWithoutResource; + NSString *_IDWithTrimmedServer; + NSString *_uniqueName; + NSData *_pictureData; + NSString *_statusMsg; + NSString *_processedStatusMsg; + NSAttributedString *_richStatusMsg; + NSDate *_whenWentOffline; + NSDate *_whenStatusChanged; + NSString *_prevStatusMsg; + NSMutableArray *_notificationNameQueue; + NSMutableArray *_notificationQueue; + struct __CFPhoneNumber *_phoneNumberRef; + NSString *_formattedNumber; + BOOL _hasCheckedPhoneNumber; + unsigned long long _status; + unsigned long long _prevStatus; + unsigned long long _capabilities; + unsigned int _authRequestStatus; + unsigned long long _resourceIndex; + long long _IDStatus; + BOOL _blockNotifications; + BOOL _hasTemporaryWatch; + BOOL _isMobile; + BOOL _isBot; + BOOL _isAnonymous; + BOOL _beingTornDown; + BOOL _hasCheckedCardMap; + long long _priority; + int _addressBookIdentifier; + int _notificationQueueCount; + NSNumber *_isBusiness; + NSNumber *_isMako; + NSNumber *_isApple; + BOOL _hasCheckedForSuggestions; + NSString *_personCentricID; + NSString *_guid; + + NSData *_mapItemImageData; + NSData *_mapItemBannerImageData; + + NSURL *_statusURL; + id _cachedStatusMessageAsURL; + NSString *_suggestedName; +} + ++ (id)filterIMHandlesForBestAccountSiblings:(id)arg1; ++ (id)filterIMHandlesForAccountSiblings:(id)arg1 onAccount:(id)arg2; ++ (id)bestIMHandleInArray:(id)arg1; ++ (id)imHandlesForIMPerson:(id)arg1; ++ (BOOL)supportsSecureCoding; ++ (id)nameOfStatus:(unsigned long long)arg1; ++ (void)_loadStatusNames; ++ (BOOL)notificationsEnabled; ++ (void)setNotificationsEnabled:(BOOL)arg1; ++ (void)handlesForPersons:(id)arg1 useBestHandle:(BOOL)arg2 useExtendedAsyncLookup:(BOOL)arg3 completion:(CDUnknownBlockType)arg4; ++ (void)validHandlesForPersons:(id)arg1 useExtendedAsyncLookup:(BOOL)arg2 completion:(CDUnknownBlockType)arg3; ++ (void)validHandlesForPersons:(id)arg1 completion:(CDUnknownBlockType)arg2; ++ (void)bestHandlesForPersons:(id)arg1 useExtendedAsyncLookup:(BOOL)arg2 completion:(CDUnknownBlockType)arg3; ++ (void)bestHandlesForPersons:(id)arg1 completion:(CDUnknownBlockType)arg2; +@property(nonatomic) BOOL hasCheckedForSuggestions; // @synthesize hasCheckedForSuggestions=_hasCheckedForSuggestions; +@property(copy, nonatomic) NSString *suggestedName; // @synthesize suggestedName=_suggestedName; +@property(retain, nonatomic) id cachedStatusMessageAsURL; // @synthesize cachedStatusMessageAsURL=_cachedStatusMessageAsURL; +@property(retain, nonatomic) NSURL *statusURL; // @synthesize statusURL=_statusURL; +@property(nonatomic) long long IDStatus; // @synthesize IDStatus=_IDStatus; +// @property(retain, nonatomic) CNContact *cnContact; // @synthesize cnContact=_cnContact; +@property(retain, nonatomic) NSData *mapItemBannerImageData; // @synthesize mapItemBannerImageData=_mapItemBannerImageData; +@property(retain, nonatomic) NSData *mapItemImageData; // @synthesize mapItemImageData=_mapItemImageData; +// @property(retain, nonatomic) MKMapItem *mapItem; // @synthesize mapItem=_mapItem; +@property(readonly, retain, nonatomic) NSString *guid; // @synthesize guid=_guid; +@property(readonly, nonatomic) int addressBookIdentifier; // @synthesize addressBookIdentifier=_addressBookIdentifier; +@property(retain, nonatomic) NSDictionary *otherServiceIDs; // @synthesize otherServiceIDs=_otherServiceIDs; +@property(readonly, retain, nonatomic) NSData *pictureData; // @synthesize pictureData=_pictureData; +@property(readonly, nonatomic) BOOL isMobile; // @synthesize isMobile=_isMobile; +@property(readonly, nonatomic) BOOL isBot; // @synthesize isBot=_isBot; +@property(nonatomic) long long priority; // @synthesize priority=_priority; +@property(readonly, retain, nonatomic) NSDate *feedUpdatedDate; // @synthesize feedUpdatedDate=_feedUpdatedDate; +@property(readonly, nonatomic) unsigned int authRequestStatus; // @synthesize authRequestStatus=_authRequestStatus; +@property(readonly, retain, nonatomic) IMAccount *account; // @synthesize account=_account; +@property(readonly, retain, nonatomic) NSString *uniqueName; // @synthesize uniqueName=_uniqueName; +@property(retain, nonatomic) NSString *personCentricID; // @synthesize personCentricID=_personCentricID; +@property(readonly, retain, nonatomic) NSString *ID; // @synthesize ID=_id; +@property(readonly, retain, nonatomic) NSAttributedString *richStatusMessage; // @synthesize richStatusMessage=_richStatusMsg; +@property(readonly, retain, nonatomic) NSString *previousStatusMessage; // @synthesize previousStatusMessage=_prevStatusMsg; +@property(readonly, nonatomic) unsigned long long previousStatus; // @synthesize previousStatus=_prevStatus; +@property(readonly, retain, nonatomic) NSDictionary *extraProperties; // @synthesize extraProperties=_extraProps; +@property(readonly, retain, nonatomic) NSString *originalID; // @synthesize originalID=_uncanonicalID; + +- (void)_mapItemBannerImageDataFetchedWithResponse:(id)arg1 statusCode:(long long)arg2 resultData:(id)arg3 remoteURLConnectionError:(id)arg4; +- (void)_fetchMapItemBannerImageDataForMapItem:(id)arg1; +- (void)_mapItemImageDataFetchedWithResponse:(id)arg1 statusCode:(long long)arg2 resultData:(id)arg3 remoteURLConnectionError:(id)arg4; +- (void)_fetchMapItemImageDataForMapItem:(id)arg1; +- (void)_postOnScreenChangedNotificationForProperty:(id)arg1; +- (void)_mapItemFetchedWithMapItems:(id)arg1 error:(id)arg2; +- (void)_fetchBusinessInfo; +- (void)sendNotificationABPersonChanged; +- (id)description; +- (void)setCustomPictureData:(id)arg1 key:(id)arg2; +- (void)setCustomPictureData:(id)arg1; +- (id)customPictureData; +- (void)customPictureDataChanged:(id)arg1 key:(id)arg2; +- (void)_imPersonPictureChanged:(id)arg1; +- (void)_sendCommand:(id)arg1 properties:(id)arg2; +- (void)_sendAutomationData:(id)arg1 properties:(id)arg2; +@property(readonly, nonatomic) BOOL hasMultiwayAudio; +@property(readonly, nonatomic) BOOL hasAudio; +@property(readonly, nonatomic) BOOL hasMultiwayVideo; +@property(readonly, nonatomic) BOOL hasVideo; +@property(readonly, nonatomic) BOOL isConferenceAvailable; +@property(readonly, nonatomic) BOOL hasConferencing; +- (BOOL)hasCapability:(unsigned long long)arg1; +- (BOOL)_setCapabilities:(unsigned long long)arg1; +- (void)setCapabilities:(unsigned long long)arg1; +@property(readonly, nonatomic) unsigned long long capabilities; +- (id)_bestChatSibling; +- (id)_chatSiblingsArray; +- (id)_chatSiblings; +- (BOOL)_isChatSiblingOf:(id)arg1; +- (BOOL)isSiblingOf:(id)arg1; +- (BOOL)isAccountSiblingOf:(id)arg1; +@property(readonly, retain, nonatomic) NSSet *siblings; +- (id)chatSiblingsArray; +- (id)existingChatSiblingsArray; +@property(readonly, retain, nonatomic) NSArray *accountSiblingsArray; +@property(readonly, retain, nonatomic) NSArray *existingAccountSiblingsArray; +@property(readonly, retain, nonatomic) NSArray *siblingsArray; +@property(readonly, nonatomic) BOOL hasOtherSiblings; +- (BOOL)matchesIMHandle:(id)arg1; +- (long long)compareAccountNames:(id)arg1; +- (long long)compareNormalizedIDs:(id)arg1; +- (long long)compareIDs:(id)arg1; +- (long long)compareStatus:(id)arg1; +- (long long)compareLastNames:(id)arg1; +- (long long)compareFirstNames:(id)arg1; +- (id)_nameForComparisonPreferFirst:(BOOL)arg1; +@property(readonly, nonatomic) double timeSinceStatusChanged; +@property(readonly, nonatomic) double timeSinceWentOffline; +- (void)setStatus:(unsigned long long)arg1 message:(id)arg2 richMessage:(id)arg3; +- (void)_clearStatusMessageURLCache; +@property(readonly, retain, nonatomic) NSString *statusMessage; +- (void)_filterStatusMessage; +@property(readonly, retain, nonatomic) NSString *idleString; +@property(readonly, retain, nonatomic) NSString *offlineString; +- (void)setFeedUpdatedDate:(id)arg1; +- (void)setIdleSince:(id)arg1; +- (void)_setIDStatus:(long long)arg1; +@property(readonly, nonatomic) double idleTime; +@property(readonly, retain, nonatomic) NSString *nameOfStatus; +- (void)statusChanged:(unsigned long long)arg1; +- (void)statusMessageChanged:(id)arg1; +- (void)statusChanged:(unsigned long long)arg1 message:(id)arg2; +- (void)setPersonStatus:(unsigned long long)arg1; +@property(readonly, nonatomic) unsigned long long status; +- (void)setAuthRequestStatus:(unsigned int)arg1; +- (void)_updateStatusBasedOnAuthRequestStatus; +- (void)_stopRetainingAccount:(id)arg1; +- (id)dependentIMHandles; +- (id)existingIMHandleWithoutResource; +- (id)imHandleWithoutResource; +@property(readonly, retain, nonatomic) NSString *IDWithoutResource; +@property(readonly, retain, nonatomic) NSString *resource; +@property(readonly, retain, nonatomic) NSString *accountTypeName; +- (unsigned int)sortOrderInGroup:(id)arg1; +@property(nonatomic, setter=setBlocked:) BOOL isBlocked; +@property(readonly, nonatomic) BOOL isVisiblyBlocked; +- (BOOL)_isMyIDInList:(id)arg1; +- (void)propertiesChanged:(id)arg1; +- (void)_setExtraProperties:(id)arg1; +@property(readonly, nonatomic) id bestSibling; +- (id)bestIMHandleForAccount:(id)arg1 onService:(id)arg2 inGroup:(id)arg3 otherThan:(id)arg4; +@property(readonly, retain, nonatomic) id bestAccountSibling; +- (id)bestIMHandleForAccount:(id)arg1; +- (id)bestIMHandleForService:(id)arg1; +- (BOOL)isBetterThanIMHandle:(id)arg1; +- (void)setHasTemporaryWatch:(BOOL)arg1; +@property(readonly, nonatomic) BOOL watchingIMHandle; +- (void)setValue:(id)arg1 ofExtraProperty:(id)arg2; +- (void)requestValueOfProperty:(id)arg1; +- (id)_formattedPhoneNumber; +- (void)_updateOriginalID:(id)arg1; +- (struct __CFPhoneNumber *)phoneNumberRef; +- (void)_createPhoneNumberRefIfNeeded; +@property(readonly, nonatomic) BOOL isLoginIMHandle; +@property(readonly, nonatomic) BOOL isLoginIMHandleForAnyAccount; +@property(readonly, nonatomic) BOOL isBuddy; +@property(readonly, retain, nonatomic) NSString *server; +- (BOOL)hasResource; +@property(readonly, nonatomic) BOOL hasLocation; +- (BOOL)hasServer; +@property(readonly, retain, nonatomic) NSString *mobileDeviceName; +- (void)setIsBot:(BOOL)arg1; +- (void)setIsMobile:(BOOL)arg1; +@property(readonly, nonatomic) BOOL isSystemUser; +@property(readonly, nonatomic) BOOL canBeAdded; +- (void)_contactStoreDidChange:(id)arg1; +- (void)setEmails:(id)arg1; +- (void)setEmail:(id)arg1; +- (void)setFirstName:(id)arg1 lastName:(id)arg2; +@property(readonly, retain, nonatomic) NSArray *emails; +- (void)setEmails:(id)arg1 andUpdateABPerson:(BOOL)arg2; +@property(readonly, retain, nonatomic) NSString *email; +- (void)setEmail:(id)arg1 andUpdateABPerson:(BOOL)arg2; +- (void)setFirstName:(id)arg1 lastName:(id)arg2 fullName:(id)arg3 andUpdateABPerson:(BOOL)arg4; +- (void)setLocalNickname:(id)arg1; +- (void)setImageData:(id)arg1; +- (void)_setBaseFirstName:(id)arg1 lastName:(id)arg2 fullName:(id)arg3; +- (void)_setABPersonFirstName:(id)arg1 lastName:(id)arg2; +@property(readonly, retain, nonatomic) NSString *lastName; +@property(readonly, retain, nonatomic) NSString *firstName; +@property(readonly, retain, nonatomic) NSString *nickname; +@property(readonly, nonatomic) BOOL hasName; +- (void)resetUniqueName; +@property(readonly, retain, nonatomic) NSString *nameAndID; +@property(readonly, retain, nonatomic) NSString *fullName; +@property(readonly, retain, nonatomic) NSString *_displayNameWithAbbreviation; +- (id)displayNameForChat:(id)arg1; +@property(readonly, retain, nonatomic) NSString *normalizedID; +@property(readonly, retain, nonatomic) NSString *displayID; +- (id)immediateNameWithNeedsSuggestedNameFetch:(char *)arg1 useSuggestedName:(BOOL)arg2; +- (void)scheduleSuggestedNameFetchIfNecessary; +@property(readonly, retain, nonatomic) NSString *name; +- (BOOL)_hasABName; +- (BOOL)_hasServiceNameProperties; +- (id)_IDWithTrimmedServer; +@property(retain, nonatomic, setter=setIMPerson:) IMPerson *person; +- (id)_cachedPerson; +- (void)_clearABPersonLookup; +- (void)resetABProperties; +- (void)_clearABProperties; +- (BOOL)areABPropertiesRecent; +- (id)_abPersonCreateIfNeeded; +- (BOOL)resetABPerson; +- (void)clearABPerson; +- (BOOL)isContact; +- (unsigned long long)hash; +@property(readonly, retain, nonatomic) IMServiceImpl *service; +@property(readonly, retain, nonatomic) NSString *nameAndEmail; +- (void)setUniqueName:(id)arg1; +- (void)postNotificationName:(id)arg1; +- (void)_postNotificationName:(id)arg1 userInfo:(id)arg2; +- (void)_postNotification:(id)arg1; +- (void)_registerForNotifications; +@property(readonly, nonatomic) BOOL isAnonymous; +- (void)setAnonymous:(BOOL)arg1; +@property(readonly, retain, nonatomic) NSSet *groups; +@property(readonly, retain, nonatomic) NSArray *groupsArray; +- (id)imHandleForOtherAccount:(id)arg1; +@property(readonly, nonatomic) BOOL canBeDeleted; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithCoder:(id)arg1; +- (BOOL)isApple; +- (BOOL)isMako; +- (BOOL)isBusiness; +- (void)_setOriginalID:(id)arg1; +- (void)_setCountryCode:(id)arg1 updateSiblings:(BOOL)arg2; +- (void)_setOriginalID:(id)arg1 updateSiblings:(BOOL)arg2; +@property(readonly, retain, nonatomic) NSString *countryCode; +- (void)_setOriginalID:(id)arg1 countryCode:(id)arg2 updateSiblings:(BOOL)arg3; +- (id)_handleInfo; +- (void)dealloc; +- (id)initWithAccount:(id)arg1 ID:(id)arg2; +- (id)initWithAccount:(id)arg1 ID:(id)arg2 alreadyCanonical:(BOOL)arg3; +- (id)init; +- (void)setStatusURLFromString:(id)arg1; +@property(readonly, nonatomic) NSURL *statusMessageAsURL; +- (id)fmfSiblingHandles; +- (id)fmfHandle; +- (void)releaseNotificationQueue; +- (void)beginNotificationQueue; +- (BOOL)shouldQueueNotifications; +- (id)publicAPIPropertiesDictionary; +- (void)_sendRemoteLogDumpRequest; +- (void)_sendRemoteLogDumpRequest:(id)arg1; + +@end + + + +@protocol IMDaemonListenerProtocol +- (void)lastMessageForAllChats:(NSDictionary *)arg1; +- (void)didFetchCloudKitSyncDebuggingInfo:(NSDictionary *)arg1; +- (void)receivedUrgentRequestForMessages:(NSArray *)arg1; +- (void)oneTimeCodesDidChange:(NSArray *)arg1; +- (void)didAttemptToDisableiCloudBackups:(long long)arg1 error:(NSError *)arg2; +- (void)didFetchRampState:(NSDictionary *)arg1; +- (void)didFetchSyncStateStats:(NSDictionary *)arg1; +- (void)didAttemptToDisableAllDevicesResult:(BOOL)arg1; +- (void)didPerformAdditionalStorageRequiredCheckWithSuccess:(BOOL)arg1 additionalStorageRequired:(unsigned long long)arg2 forAccountId:(NSString *)arg3 error:(NSError *)arg4; +- (void)didAttemptToSetEnabledTo:(BOOL)arg1 result:(BOOL)arg2; +- (void)returnMOCEnabledState:(unsigned long long)arg1; +- (void)updateCloudKitStateWithDictionary:(NSDictionary *)arg1; +- (void)updateCloudKitState; +- (void)qosClassWhileServicingRequestsResponse:(unsigned int)arg1 identifier:(NSString *)arg2; +- (void)stickerPackRemoved:(NSArray *)arg1; +- (void)stickerPackUpdated:(NSDictionary *)arg1; +- (void)pinCodeAlertCompleted:(NSString *)arg1 deviceName:(NSString *)arg2 deviceType:(NSString *)arg3 phoneNumber:(NSString *)arg4 responseFromDevice:(BOOL)arg5 wasCancelled:(BOOL)arg6; +- (void)displayPinCodeForAccount:(NSString *)arg1 pinCode:(NSNumber *)arg2 deviceName:(NSString *)arg3 deviceType:(NSString *)arg4 phoneNumber:(NSString *)arg5; +- (void)lastFailedMessageDateChanged:(long long)arg1; +- (void)unreadCountChanged:(long long)arg1; +- (void)databaseChatSpamUpdated:(NSString *)arg1; +- (void)databaseNoLongerFull; +- (void)databaseFull; +- (void)databaseUpdated:(NSString *)arg1; +- (void)databaseUpdated; +- (void)account:(NSString *)arg1 relay:(NSString *)arg2 handleCancel:(NSDictionary *)arg3 fromPerson:(NSDictionary *)arg4; +- (void)account:(NSString *)arg1 relay:(NSString *)arg2 handleUpdate:(NSDictionary *)arg3 fromPerson:(NSDictionary *)arg4; +- (void)account:(NSString *)arg1 relay:(NSString *)arg2 handleInitate:(NSDictionary *)arg3 fromPerson:(NSDictionary *)arg4; +- (void)account:(NSString *)arg1 postedError:(NSError *)arg2; +- (void)account:(NSString *)arg1 statusChanged:(NSDictionary *)arg2; +- (void)persistentProperty:(NSString *)arg1 changedTo:(id)arg2 from:(id)arg3; +- (void)property:(NSString *)arg1 changedTo:(id)arg2 from:(id)arg3; +- (void)showForgotPasswordNotificationForAccount:(NSString *)arg1; +- (void)showInvalidCertNotificationForAccount:(NSString *)arg1; +- (void)account:(NSString *)arg1 avAction:(unsigned int)arg2 withArguments:(NSDictionary *)arg3 toAVChat:(NSString *)arg4 isVideo:(BOOL)arg5; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 invitationSentSuccessfully:(BOOL)arg3; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 peerID:(NSString *)arg3 propertiesUpdated:(NSDictionary *)arg4; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 peerIDChangedFromID:(NSString *)arg3 toID:(NSString *)arg4; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 changedToNewConferenceID:(NSString *)arg3; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 receivedAVMessage:(unsigned int)arg3 from:(NSDictionary *)arg4 sessionID:(unsigned int)arg5 userInfo:(NSDictionary *)arg6; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 receivedUpdateFrom:(NSDictionary *)arg3 data:(NSData *)arg4; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 receivedCounterProposalFrom:(NSDictionary *)arg3 properties:(NSDictionary *)arg4; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 receivedCancelInvitationFrom:(NSDictionary *)arg3 properties:(NSDictionary *)arg4; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 receivedResponseToInvitationFrom:(NSDictionary *)arg3 properties:(NSDictionary *)arg4; +- (void)account:(NSString *)arg1 conference:(NSString *)arg2 receivedInvitationFrom:(NSDictionary *)arg3 properties:(NSDictionary *)arg4; +- (void)fileTransferHighQualityDownloadFailed:(NSString *)arg1; +- (void)fileTransfer:(NSString *)arg1 highQualityDownloadSucceededWithPath:(NSString *)arg2; +- (void)fileTransfer:(NSString *)arg1 updatedWithCurrentBytes:(unsigned long long)arg2 totalBytes:(unsigned long long)arg3 averageTransferRate:(unsigned long long)arg4; +- (void)fileTransfers:(NSArray *)arg1 createdWithLocalPaths:(NSArray *)arg2; +- (void)fileTransfer:(NSString *)arg1 updatedWithProperties:(NSDictionary *)arg2; +- (void)fileTransfer:(NSString *)arg1 createdWithProperties:(NSDictionary *)arg2; +- (void)standaloneFileTransferRegistered:(NSString *)arg1; +- (void)chatLoadedWithChatIdentifier:(NSString *)arg1 chats:(NSArray *)arg2; +- (void)frequentRepliesQuery:(NSString *)arg1 chatID:(NSString *)arg2 services:(NSArray *)arg3 finishedWithResult:(NSArray *)arg4 limit:(unsigned long long)arg5; +- (void)historicalMessageGUIDsDeleted:(NSArray *)arg1 chatGUIDs:(NSArray *)arg2 queryID:(NSString *)arg3; +- (void)markAsSpamQuery:(NSString *)arg1 chatID:(NSString *)arg2 services:(NSArray *)arg3 finishedWithResult:(NSNumber *)arg4; +- (void)finishedDownloadingPurgedAssetsForChatIDs:(NSArray *)arg1; +- (void)downloadedPurgedAssetBatchForChatIDs:(NSArray *)arg1 completedTransferGUIDs:(NSArray *)arg2; +- (void)isDownloadingQuery:(NSString *)arg1 chatID:(NSString *)arg2 services:(NSArray *)arg3 finishedWithResult:(BOOL)arg4; +- (void)uncachedAttachmentCountQuery:(NSString *)arg1 chatID:(NSString *)arg2 services:(NSArray *)arg3 finishedWithResult:(NSNumber *)arg4; +- (void)attachmentQuery:(NSString *)arg1 chatID:(NSString *)arg2 services:(NSArray *)arg3 finishedWithResult:(NSArray *)arg4; +- (void)pagedHistoryQuery:(NSString *)arg1 chatID:(NSString *)arg2 services:(NSArray *)arg3 numberOfMessagesBefore:(unsigned long long)arg4 numberOfMessagesAfter:(unsigned long long)arg5 finishedWithResult:(NSArray *)arg6; +- (void)historyQuery:(NSString *)arg1 chatID:(NSString *)arg2 services:(NSArray *)arg3 finishedWithResult:(NSArray *)arg4 limit:(unsigned long long)arg5; +- (void)messageQuery:(NSString *)arg1 finishedWithResult:(IMMessageItem *)arg2 chatGUIDs:(NSArray *)arg3; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 member:(NSDictionary *)arg5 statusChanged:(int)arg6; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 groupID:(NSString *)arg5 chatPersonCentricID:(NSString *)arg6 statusChanged:(int)arg7 handleInfo:(NSArray *)arg8; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 error:(NSError *)arg5; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 messagesUpdated:(NSArray *)arg5; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 notifySentMessage:(IMMessageItem *)arg5 sendTime:(NSNumber *)arg6; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 messageUpdated:(IMItem *)arg5; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 groupID:(NSString *)arg5 chatPersonCentricID:(NSString *)arg6 messagesReceived:(NSArray *)arg7; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 groupID:(NSString *)arg5 chatPersonCentricID:(NSString *)arg6 messageReceived:(IMItem *)arg7; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 groupID:(NSString *)arg5 chatPersonCentricID:(NSString *)arg6 messageSent:(IMMessageItem *)arg7; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 updateProperties:(NSDictionary *)arg5; +- (void)account:(NSString *)arg1 chat:(NSString *)arg2 style:(unsigned char)arg3 chatProperties:(NSDictionary *)arg4 invitationReceived:(IMMessageItem *)arg5; +- (void)loadedChats:(NSArray *)arg1; +- (void)engroupParticipantsUpdatedForChat:(NSString *)arg1; +- (void)leftChat:(NSString *)arg1; +- (void)chat:(NSString *)arg1 engramIDUpdated:(NSString *)arg2; +- (void)chat:(NSString *)arg1 isFilteredUpdated:(BOOL)arg2; +- (void)chat:(NSString *)arg1 lastAddressedSIMIDUpdated:(NSString *)arg2; +- (void)chat:(NSString *)arg1 lastAddressedHandleUpdated:(NSString *)arg2; +- (void)chat:(NSString *)arg1 displayNameUpdated:(NSString *)arg2; +- (void)chat:(NSString *)arg1 propertiesUpdated:(NSDictionary *)arg2; +- (void)chat:(NSString *)arg1 updated:(NSDictionary *)arg2; +- (void)account:(NSString *)arg1 buddyInfo:(NSDictionary *)arg2 commandDelivered:(NSNumber *)arg3 properties:(NSDictionary *)arg4; +- (void)account:(NSString *)arg1 buddyInfo:(NSDictionary *)arg2 commandReceived:(NSNumber *)arg3 properties:(NSDictionary *)arg4; +- (void)account:(NSString *)arg1 handleSubscriptionRequestFrom:(NSDictionary *)arg2 withMessage:(NSString *)arg3; +- (void)account:(NSString *)arg1 buddyProperties:(NSDictionary *)arg2 buddyPictures:(NSDictionary *)arg3; +- (void)account:(NSString *)arg1 groupsChanged:(NSArray *)arg2 error:(NSError *)arg3; +- (void)account:(NSString *)arg1 buddyPictureChanged:(NSString *)arg2 imageData:(NSData *)arg3 imageHash:(NSString *)arg4; +- (void)account:(NSString *)arg1 blockIdleStatusChanged:(BOOL)arg2; +- (void)account:(NSString *)arg1 blockingModeChanged:(unsigned int)arg2; +- (void)account:(NSString *)arg1 allowListChanged:(NSArray *)arg2; +- (void)account:(NSString *)arg1 blockListChanged:(NSArray *)arg2; +- (void)account:(NSString *)arg1 buddyPropertiesChanged:(NSArray *)arg2; +- (void)accountRemoved:(NSString *)arg1; +- (void)accountAdded:(NSString *)arg1 defaults:(NSDictionary *)arg2 service:(NSString *)arg3; +- (void)account:(NSString *)arg1 capabilitiesChanged:(unsigned long long)arg2; +- (void)account:(NSString *)arg1 defaultsChanged:(NSDictionary *)arg2; +- (void)account:(NSString *)arg1 loginStatusChanged:(unsigned int)arg2 message:(NSString *)arg3 reason:(int)arg4 properties:(NSDictionary *)arg5; +- (void)account:(NSString *)arg1 defaults:(NSDictionary *)arg2 blockList:(NSArray *)arg3 allowList:(NSArray *)arg4 blockingMode:(unsigned int)arg5 blockIdleStatus:(BOOL)arg6 status:(NSDictionary *)arg7 capabilities:(unsigned long long)arg8 serviceLoginStatus:(unsigned int)arg9 loginStatusMessage:(NSString *)arg10; +- (void)activeAccountsChanged:(NSArray *)arg1 forService:(NSString *)arg2; +- (void)defaultsChanged:(NSDictionary *)arg1 forService:(NSString *)arg2; +- (void)vcCapabilitiesChanged:(unsigned long long)arg1; +- (void)pendingACRequestComplete; +- (void)pendingVCRequestComplete; +- (void)setupComplete; +- (void)setupComplete:(BOOL)arg1 info:(NSDictionary *)arg2; +@end + +@protocol IMMessageChatItem +@property(readonly, nonatomic) IMHandle *sender; +@property(readonly, nonatomic) NSDate *time; +@property(readonly, nonatomic) BOOL failed; +@property(readonly, nonatomic) BOOL isFromMe; +@end + +@protocol IMPluginChatItemProtocol +@property(readonly, nonatomic) BOOL isFromMe; +// @property(readonly, retain, nonatomic) IMBalloonPluginDataSource *dataSource; +@property(readonly, retain, nonatomic) NSString *type; +@end + +@protocol IMRemoteAppExtensionContextProtocol /* */ +@end + +@protocol IMRemoteDaemonProtocol +- (void)preWarm; +- (void)simulateMessageReceive:(NSString *)arg1 serviceName:(NSString *)arg2 handles:(NSArray *)arg3 sender:(NSString *)arg4; +- (void)simulateOneTimeCodeArriving:(NSDictionary *)arg1; +- (void)consumeCodeWithMessageGUID:(NSString *)arg1; +- (void)requestOneTimeCodeStatus; +- (void)closeSessionChatID:(NSString *)arg1 identifier:(NSString *)arg2 style:(unsigned char)arg3 account:(NSString *)arg4; +- (void)requestMOCEnabledState; +- (void)tryToAutoCollectLogsWithErrorString:(NSString *)arg1 sendLogsTo:(NSString *)arg2; +- (void)fetchCloudKitSyncStateDebuggingInfo:(NSDictionary *)arg1; +- (void)syncDeletesToCloudKit; +- (void)printCachedRampState; +- (void)fetchLatestRampState; +- (void)reportMetricToCK:(NSString *)arg1 withDict:(NSDictionary *)arg2; +- (void)writeCloudKitSyncCounts:(NSDictionary *)arg1; +- (void)fetchSyncStateStatistics; +- (void)fetchSyncStateStats; +- (void)updateAttachmentFileSizes; +- (void)metricAttachments:(long long)arg1; +- (void)purgeAttachments:(long long)arg1; +- (void)deleteSalt; +- (void)printCachedSalt; +- (void)fetchLatestSalt; +- (void)fetchSecurityLevelAndUpdateMiCSwitchEligibility; +- (void)broadcastCloudKitStateAfterClearingErrors; +- (void)clearAnalyticDefaultsAndLocalSyncState; +- (void)uploadDailyAnalyticstoCloudKit; +- (void)broadcastCloudKitStateAfterFetchingAccountStatus; +- (void)broadcastCloudKitState; +- (void)initiateSync; +- (void)tryToDisableAllDevices; +- (void)performAdditionalStorageRequiredCheck; +- (void)setCloudKitEnabled:(BOOL)arg1; +- (void)sendRestoreFailuresLogDumps; +- (void)clearDataFromCloudKit; +- (void)clearLocalCloudKitSyncState; +- (void)deleteExitRecord; +- (void)fetchExitRecord; +- (void)writeExitRecord; +- (void)loadDeletedMessagesWithLimit:(long long)arg1; +- (void)loadDirtyMessagesWithLimit:(long long)arg1; +- (void)initiatePeriodicSync; +- (void)syncMessages; +- (void)deleteMessagesZone; +- (void)writeDirtyMessages; +- (void)downloadAttachmentAssets; +- (void)syncAttachments; +- (void)writeAttachments; +- (void)deleteAttachmentZone; +- (void)createAttachmentZone; +- (void)clearChatZoneSyncToken; +- (void)markAllChatsAsDirty; +- (void)syncChats; +- (void)writeDirtyChats; +- (void)deleteChatZone; +- (void)createChatZone; +- (void)requestQOSClassWhileServicingRequestsWithID:(NSString *)arg1; +- (void)stopRecordingMessagesReplayDatabase; +- (void)beginRecordingMessagesToReplayDatabase:(NSString *)arg1; +- (void)replayMessagesFromDatabasePath:(NSString *)arg1; +- (void)downloadStickerPackWithGUID:(NSString *)arg1 isIncomingMessage:(BOOL)arg2 ignoreCache:(BOOL)arg3; +- (void)downloadStickerWithGUID:(NSString *)arg1; +- (void)enrollSelfDeviceForSMSRelay:(NSString *)arg1; +- (void)unEnrollDeviceForSMSRelay:(NSString *)arg1 account:(NSString *)arg2; +- (void)enrollDeviceForSMSRelay:(NSString *)arg1 account:(NSString *)arg2; +- (void)importMessage:(NSDictionary *)arg1 isRead:(BOOL)arg2; +- (void)validateProfileAccount:(NSString *)arg1; +- (void)unvalidateAliases:(NSArray *)arg1 account:(NSString *)arg2; +- (void)validateAliases:(NSArray *)arg1 account:(NSString *)arg2; +- (void)removeAliases:(NSArray *)arg1 account:(NSString *)arg2; +- (void)addAliases:(NSArray *)arg1 account:(NSString *)arg2; +- (void)relay:(NSString *)arg1 sendCancel:(NSDictionary *)arg2 toPerson:(NSString *)arg3 account:(NSString *)arg4; +- (void)relay:(NSString *)arg1 sendUpdate:(NSDictionary *)arg2 toPerson:(NSString *)arg3 account:(NSString *)arg4; +- (void)relay:(NSString *)arg1 sendInitateRequest:(NSDictionary *)arg2 toPerson:(NSString *)arg3 account:(NSString *)arg4; +- (void)sendAVMessageToPerson:(NSString *)arg1 sessionID:(unsigned int)arg2 type:(unsigned int)arg3 userInfo:(NSDictionary *)arg4 conference:(NSString *)arg5 account:(NSString *)arg6; +- (void)sendVCUpdate:(NSData *)arg1 toPerson:(NSString *)arg2 conference:(NSString *)arg3 account:(NSString *)arg4; +- (void)sendCounterProposalToPerson:(NSString *)arg1 properties:(NSDictionary *)arg2 conference:(NSString *)arg3 account:(NSString *)arg4; +- (void)cancelVCRequestWithPerson:(NSString *)arg1 properties:(NSDictionary *)arg2 conference:(NSString *)arg3 reason:(NSNumber *)arg4 account:(NSString *)arg5; +- (void)cancelVCRequestWithPerson:(NSString *)arg1 properties:(NSDictionary *)arg2 conference:(NSString *)arg3 account:(NSString *)arg4; +- (void)respondToVCInvitationWithPerson:(NSString *)arg1 properties:(NSDictionary *)arg2 conference:(NSString *)arg3 account:(NSString *)arg4; +- (void)requestVCWithPerson:(NSString *)arg1 properties:(NSDictionary *)arg2 conference:(NSString *)arg3 account:(NSString *)arg4; +- (void)sendCommand:(NSNumber *)arg1 withProperties:(NSDictionary *)arg2 toPerson:(NSString *)arg3 account:(NSString *)arg4 toChatID:(NSString *)arg5 identifier:(NSString *)arg6 style:(unsigned char)arg7; +- (void)sendCommand:(NSNumber *)arg1 withProperties:(NSDictionary *)arg2 toPerson:(NSString *)arg3 account:(NSString *)arg4; +- (void)sendNotificationMessageToUniqueID:(NSString *)arg1 withCommand:(long long)arg2; +- (void)passwordUpdatedAccount:(NSString *)arg1; +- (void)setBlockIdleStatus:(BOOL)arg1 account:(NSString *)arg2; +- (void)setBlockList:(NSArray *)arg1 account:(NSString *)arg2; +- (void)setAllowList:(NSArray *)arg1 account:(NSString *)arg2; +- (void)setBlockingMode:(unsigned int)arg1 account:(NSString *)arg2; +- (void)setProperties:(NSDictionary *)arg1 ofParticipant:(NSString *)arg2 inChatID:(NSString *)arg3 identifier:(NSString *)arg4 style:(unsigned char)arg5 account:(NSString *)arg6; +- (void)updateBalloonPayload:(NSData *)arg1 attachments:(NSArray *)arg2 forMessageGUID:(NSString *)arg3; +- (void)sendBalloonPayload:(NSData *)arg1 attachments:(NSArray *)arg2 withMessageGUID:(NSString *)arg3 bundleID:(NSString *)arg4; +- (void)sendSavedReceiptForMessage:(IMMessageItem *)arg1 toChatID:(NSString *)arg2 identifier:(NSString *)arg3 style:(unsigned char)arg4 account:(NSString *)arg5; +- (void)sendPlayedReceiptForMessage:(IMMessageItem *)arg1 toChatID:(NSString *)arg2 identifier:(NSString *)arg3 style:(unsigned char)arg4 account:(NSString *)arg5; +- (void)sendReadReceiptForMessage:(IMMessageItem *)arg1 toChatID:(NSString *)arg2 identifier:(NSString *)arg3 style:(unsigned char)arg4 account:(NSString *)arg5; +- (void)sendStickerAtPath:(NSString *)arg1 toChatID:(NSString *)arg2 forNBubbleFromTheBottom:(unsigned long long)arg3 atX:(NSString *)arg4 atY:(NSString *)arg5 scale:(NSString *)arg6 balloonWidth:(NSString *)arg7; +- (void)logDumpAndSendMessageTo:(NSString *)arg1 forHours:(int)arg2; +- (void)sendMessage:(IMMessageItem *)arg1 toChatID:(NSString *)arg2 identifier:(NSString *)arg3 style:(unsigned char)arg4 account:(NSString *)arg5; +- (void)eagerUploadCancel:(NSURL *)arg1; +- (void)eagerUploadTransfer:(NSDictionary *)arg1; +- (void)declineInvitationToChatID:(NSString *)arg1 identifier:(NSString *)arg2 style:(unsigned char)arg3 account:(NSString *)arg4; +- (void)removePersonInfoFromiMessageChat:(NSDictionary *)arg1 chatID:(NSString *)arg2 identifier:(NSString *)arg3 style:(unsigned char)arg4 account:(NSString *)arg5; +- (void)removePersonInfo:(NSDictionary *)arg1 chatID:(NSString *)arg2 identifier:(NSString *)arg3 style:(unsigned char)arg4 account:(NSString *)arg5; +- (void)invitePersonInfoToiMessageChat:(NSDictionary *)arg1 withMessage:(IMMessageItem *)arg2 toChatID:(NSString *)arg3 identifier:(NSString *)arg4 style:(unsigned char)arg5 account:(NSString *)arg6; +- (void)invitePersonInfo:(NSDictionary *)arg1 withMessage:(IMMessageItem *)arg2 toChatID:(NSString *)arg3 identifier:(NSString *)arg4 style:(unsigned char)arg5 account:(NSString *)arg6; +- (void)removeChatID:(NSString *)arg1 identifier:(NSString *)arg2 style:(unsigned char)arg3 account:(NSString *)arg4; +- (void)leaveiMessageChatID:(NSString *)arg1 identifier:(NSString *)arg2 style:(unsigned char)arg3 account:(NSString *)arg4; +- (void)leaveChatID:(NSString *)arg1 identifier:(NSString *)arg2 style:(unsigned char)arg3 account:(NSString *)arg4; +- (void)joinChatID:(NSString *)arg1 handleInfo:(NSArray *)arg2 identifier:(NSString *)arg3 style:(unsigned char)arg4 groupID:(NSString *)arg5 lastAddressedHandle:(NSString *)arg6 lastAddressedSIMID:(NSString *)arg7 joinProperties:(NSDictionary *)arg8 account:(NSString *)arg9; +- (void)joinChatID:(NSString *)arg1 handleInfo:(NSArray *)arg2 identifier:(NSString *)arg3 style:(unsigned char)arg4 joinProperties:(NSDictionary *)arg5 account:(NSString *)arg6; +- (void)updateAuthorizationCredentials:(NSString *)arg1 token:(NSString *)arg2 account:(NSString *)arg3; +- (void)setValue:(id)arg1 ofProperty:(NSString *)arg2 ofPerson:(NSString *)arg3 account:(NSString *)arg4; +- (void)requestProperty:(NSString *)arg1 ofPerson:(NSString *)arg2 account:(NSString *)arg3; +- (void)stopWatchingBuddy:(NSString *)arg1 account:(NSString *)arg2; +- (void)startWatchingBuddy:(NSString *)arg1 account:(NSString *)arg2; +- (void)requestSubscriptionTo:(NSString *)arg1 account:(NSString *)arg2; +- (void)acceptSubscriptionRequest:(BOOL)arg1 from:(NSString *)arg2 account:(NSString *)arg3; +- (void)renameGroup:(NSString *)arg1 to:(NSString *)arg2 account:(NSString *)arg3; +- (void)changeGroup:(NSString *)arg1 changes:(NSDictionary *)arg2 account:(NSString *)arg3; +- (void)changeGroups:(NSDictionary *)arg1 account:(NSString *)arg2; +- (void)requestGroupsAccount:(NSString *)arg1; +- (void)unregisterAccount:(NSString *)arg1; +- (void)registerAccount:(NSString *)arg1; +- (void)authenticateAccount:(NSString *)arg1; +- (void)resumeBuddyUpdatesAccount:(NSString *)arg1; +- (void)holdBuddyUpdatesAccount:(NSString *)arg1; +- (void)sendMappingPacket:(NSString *)arg1 toHandle:(NSString *)arg2 account:(NSString *)arg3; +- (void)logoutAccount:(NSString *)arg1; +- (void)loginAccount:(NSString *)arg1; +- (void)autoReconnectAccount:(NSString *)arg1; +- (void)autoLoginAccount:(NSString *)arg1; +- (void)archiveChat:(NSString *)arg1; +- (void)initiateCNContactBasedChatMerge:(BOOL)arg1; +- (void)debugUpdateGroupParticipantversion:(unsigned long long)arg1 chatIdentifier:(NSString *)arg2; +- (void)loadChatWithChatIdentifier:(NSString *)arg1; +- (void)removeChat:(NSString *)arg1; +- (void)silenceChat:(NSString *)arg1 untilDate:(NSDate *)arg2; +- (void)chat:(NSString *)arg1 updateLastAddressedSIMID:(NSString *)arg2; +- (void)chat:(NSString *)arg1 updateLastAddressHandle:(NSString *)arg2; +- (void)chat:(NSString *)arg1 updateIsFiltered:(BOOL)arg2; +- (void)chat:(NSString *)arg1 updateDisplayName:(NSString *)arg2; +- (void)chat:(NSString *)arg1 updateProperties:(NSDictionary *)arg2; +- (void)cleanupAttachments; +- (void)requestLastMessagesForChats; +- (void)loadIsDownloadingPurgedAttachmentsForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 chatID:(NSString *)arg4 queryID:(NSString *)arg5; +- (void)downloadPurgedAttachmentsForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 chatID:(NSString *)arg4; +- (unsigned long long)loadUncachedAttachmentCountForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 chatID:(NSString *)arg4 queryID:(NSString *)arg5; +- (void)loadAttachmentsForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 chatID:(NSString *)arg4 queryID:(NSString *)arg5; +- (void)loadUnreadForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 limit:(unsigned long long)arg4 fallbackGUID:(NSString *)arg5 chatId:(NSString *)arg6 queryID:(NSString *)arg7; +- (void)loadFrequentRepliesForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 limit:(unsigned long long)arg4 chatID:(NSString *)arg5 queryID:(NSString *)arg6; +- (void)updateUnformattedID:(NSString *)arg1 forBuddyID:(NSString *)arg2 onService:(NSString *)arg3; +- (void)markHasHadSuccessfulQueryForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3; +- (void)markSavedForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 message:(IMMessageItem *)arg4; +- (void)markSavedForMessageGUID:(NSString *)arg1; +- (void)markPlayedExpressiveSendForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 message:(IMMessageItem *)arg4; +- (void)markPlayedForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 message:(IMMessageItem *)arg4; +- (void)markPlayedForMessageGUID:(NSString *)arg1; +- (void)storeItem:(IMItem *)arg1 inChatGUID:(NSString *)arg2; +- (void)markReadForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 messages:(NSArray *)arg4 clientUnreadCount:(unsigned long long)arg5; +- (void)markReadForMessageGUID:(NSString *)arg1 callerOrigin:(long long)arg2; +- (void)markReadForMessageGUID:(NSString *)arg1; +- (void)markMessageAsCorrupt:(NSString *)arg1 setCorrupt:(BOOL)arg2; +- (void)updateMessage:(IMMessageItem *)arg1; +- (void)markAsSpamForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 chatID:(NSString *)arg4 queryID:(NSString *)arg5 autoReport:(BOOL)arg6; +- (void)clearHistoryForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 beforeGUID:(NSString *)arg4 afterGUID:(NSString *)arg5 chatID:(NSString *)arg6 queryID:(NSString *)arg7; +- (void)deleteMessageWithGUIDs:(NSArray *)arg1 queryID:(NSString *)arg2; +- (void)requestPendingMessages; +- (void)loadPagedHistoryForGUID:(NSString *)arg1 chatIdentifiers:(NSArray *)arg2 style:(unsigned char)arg3 onServices:(NSArray *)arg4 numberOfMessagesBefore:(unsigned long long)arg5 numberOfMessagesAfter:(unsigned long long)arg6 chatID:(NSString *)arg7 queryID:(NSString *)arg8; +- (void)loadHistoryForIDs:(NSArray *)arg1 style:(unsigned char)arg2 onServices:(NSArray *)arg3 limit:(unsigned long long)arg4 beforeGUID:(NSString *)arg5 afterGUID:(NSString *)arg6 chatID:(NSString *)arg7 queryID:(NSString *)arg8; +- (void)loadMessageWithGUID:(NSString *)arg1 queryID:(NSString *)arg2; +- (void)loadChatsWithChatID:(NSString *)arg1; +- (void)setListenerCapabilities:(unsigned int)arg1; +- (void)account:(NSString *)arg1 avAction:(unsigned int)arg2 withArguments:(NSDictionary *)arg3 toAVChat:(NSString *)arg4 isVideo:(BOOL)arg5; +- (void)conference:(NSString *)arg1 account:(NSString *)arg2 notifyInvitationCancelledFromPerson:(NSString *)arg3; +- (void)clearPendingVCRequestsWithPerson:(NSString *)arg1 forAccount:(NSString *)arg2; +- (BOOL)markAttachment:(NSString *)arg1 sender:(NSString *)arg2 recipients:(NSArray *)arg3 isIncoming:(BOOL)arg4; +- (void)fileTransferRemoved:(NSString *)arg1; +- (void)fileTransferStopped:(NSString *)arg1; +- (void)fileTransfer:(NSString *)arg1 acceptedWithPath:(NSString *)arg2 autoRename:(BOOL)arg3 overwrite:(BOOL)arg4; +- (void)fileTransfer:(NSString *)arg1 updatedWithProperties:(NSDictionary *)arg2; +- (void)fileTransfer:(NSString *)arg1 createdWithProperties:(NSDictionary *)arg2; +- (void)downloadHighQualityVariantOfFileTransferWithGUID:(NSString *)arg1; +- (void)deleteFileTransferWithGUID:(NSString *)arg1; +- (void)sendStandaloneFileTransfer:(NSString *)arg1; +- (void)requestBuddyPicturesAndPropertiesForAccount:(NSString *)arg1; +- (void)writeAccount:(NSString *)arg1 defaults:(NSDictionary *)arg2; +- (void)removeAccount:(NSString *)arg1; +- (void)addAccount:(NSString *)arg1 defaults:(NSDictionary *)arg2 service:(NSString *)arg3; +- (void)deactivateAccounts:(NSArray *)arg1; +- (void)activateAccounts:(NSArray *)arg1; +- (void)requestPendingACInvites; +- (void)requestPendingVCInvites; +- (void)setVCCapabilities:(unsigned long long)arg1; +- (void)setValue:(id)arg1 ofPersistentProperty:(NSString *)arg2; +- (void)setValue:(id)arg1 ofProperty:(NSString *)arg2; +- (void)changeMyStatus:(NSDictionary *)arg1 forAccount:(NSString *)arg2; +- (void)terminateForcingIfNeeded:(BOOL)arg1; +- (void)logoutAllAccounts; +- (void)loginAllAccounts; +- (void)autoLoginActiveAccountsIfNecessary; +@end + +@class IMSendProgress; +@protocol IMSendProgressDelegate +- (void)sendProgress:(IMSendProgress *)arg1 progressDidChange:(float)arg2 sendingMessages:(NSDictionary *)arg3 sendCount:(unsigned long long)arg4 totalCount:(unsigned long long)arg5 finished:(BOOL)arg6; +@end + +@protocol IMSendProgressTimeDataSource +@property(readonly) double timeIntervalSinceReferenceDate; +@end + + +@protocol IMSystemMonitorListener + +@optional +- (void)systemDidEnterDataProtectionLock; +- (void)systemDidLeaveDataProtectionLock; +- (void)systemDidLeaveFirstDataProtectionLock; +- (void)systemScreenDidPowerDown; +- (void)systemScreenDidPowerUp; +- (void)systemDidUnlock; +- (void)systemDidLock; +- (void)systemDidLogout; +- (void)systemDidFastUserSwitchIn; +- (void)systemDidFastUserSwitchOut; +- (void)systemRestoreStateDidChange; +- (void)systemDidFinishMigration; +- (void)systemDidStopBackup; +- (void)systemDidStartBackup; +- (void)notificationCenterDidDisappear; +- (void)notificationCenterWillAppear; +- (void)systemApplicationDidResumeForEventsOnly; +- (void)systemApplicationDidSuspendForEventsOnly; +- (void)systemApplicationDidResume; +- (void)systemApplicationDidSuspend; +- (void)systemApplicationWillResignActive; +- (void)systemApplicationDidBecomeActive; +- (void)systemApplicationWillEnterForeground; +- (void)systemApplicationDidEnterBackground; +- (void)systemWillShutdown; +- (void)systemDidLeaveMemoryPressure; +- (void)systemDidEnterMemoryPressure; +- (void)systemDidWake; +- (void)systemWillSleep; +- (void)screenUnlocked; +- (void)screenLocked; +- (void)screenSaverDidStop; +- (void)screenSaverDidStart; +- (void)systemDidBecomeUnidle; +- (void)systemDidBecomeIdle; +@end + +@protocol IMVisibleAssociatedMessageHost +@property(retain, nonatomic, setter=_setVisibleAssociatedMessageChatItems:) NSArray *visibleAssociatedMessageChatItems; +@end + +@protocol INSpeakable +@property(readonly) NSArray *alternativeSpeakableMatches; +@property(readonly) NSString *vocabularyIdentifier; +@property(readonly) NSString *pronunciationHint; +@property(readonly) NSString *spokenPhrase; + +@optional +@property(readonly) NSString *identifier; +@end + + +@interface IMTranscriptEffectHelper : NSObject +{ +} + ++ (BOOL)shouldShowReplayButtonForEffectIdentifier:(id)arg1; ++ (BOOL)isFeatureEnabled; ++ (id)sendWithStringForEffectIdentifier:(id)arg1; ++ (id)replayStringForEffectIdentifier:(id)arg1; ++ (id)nameForEffectIdentifier:(id)arg1; ++ (id)findIdentifierByMathcingPartialSufix:(id)arg1; ++ (id)sendWithEffectStringMap; ++ (id)replayStringMap; ++ (id)identifierNameMap; ++ (BOOL)effectIdentifierIsImpactEffect:(id)arg1; ++ (BOOL)effectIdentifierIsFullScreenMoment:(id)arg1; ++ (BOOL)identifierIsEffectIdentifier:(id)arg1; ++ (id)allEffectIdentifiers; ++ (void)setFeatureEnabled:(BOOL)arg1; + +@end + +@interface IMCloudKitSyncState : NSObject +{ + BOOL _hasExited; + BOOL _isDisablingDevices; + BOOL _accountIsEnabled; + unsigned long long _syncControllerSyncState; + long long _syncControllerSyncType; + long long _syncControllerRecordType; + NSDate *_exitDate; + long long _changingEnabledState; + NSDate *_lastSyncDate; + NSArray *_errors; + long long _accountStatus; + long long _syncState; +} + ++ (id)logHandle; +@property(readonly, nonatomic) long long syncState; // @synthesize syncState=_syncState; +@property(readonly, nonatomic) BOOL accountIsEnabled; // @synthesize accountIsEnabled=_accountIsEnabled; +@property(readonly, nonatomic) long long accountStatus; // @synthesize accountStatus=_accountStatus; +@property(readonly, nonatomic) NSArray *errors; // @synthesize errors=_errors; +@property(readonly, nonatomic) NSDate *lastSyncDate; // @synthesize lastSyncDate=_lastSyncDate; +@property(readonly, nonatomic) BOOL isDisablingDevices; // @synthesize isDisablingDevices=_isDisablingDevices; +@property(readonly, nonatomic) long long changingEnabledState; // @synthesize changingEnabledState=_changingEnabledState; +@property(readonly, copy, nonatomic) NSDate *exitDate; // @synthesize exitDate=_exitDate; +@property(readonly, nonatomic) BOOL hasExited; // @synthesize hasExited=_hasExited; +@property(readonly, nonatomic) long long syncControllerRecordType; // @synthesize syncControllerRecordType=_syncControllerRecordType; +@property(readonly, nonatomic) long long syncControllerSyncType; // @synthesize syncControllerSyncType=_syncControllerSyncType; +@property(readonly, nonatomic) unsigned long long syncControllerSyncState; // @synthesize syncControllerSyncState=_syncControllerSyncState; + +@property(readonly, nonatomic) BOOL isSyncEnabledForDisplayOnly; +@property(readonly, nonatomic) BOOL canChangeEnabledSetting; +@property(readonly, nonatomic) BOOL canStartSyncing; +- (BOOL)_isChangingEnabledState; +@property(readonly, nonatomic) BOOL canEnableSyncing; +- (id)description; +@property(readonly, nonatomic) BOOL syncingFailed; +@property(readonly, nonatomic) BOOL isSyncingAvailable; +@property(readonly, nonatomic) BOOL isSyncingEnabled; +- (id)syncErrorWithDomain:(id)arg1 code:(long long)arg2; +@property(readonly, nonatomic) BOOL isSyncingPaused; +@property(readonly, nonatomic) BOOL isSyncing; +- (id)initWithAccountEnabled:(BOOL)arg1 stateDictionary:(id)arg2; +- (id)logHandle; +- (id)createSyncProgressWithSyncStatistics:(id)arg1; +- (BOOL)shouldFetchSyncStatistics; +- (BOOL)shouldRescheduleSyncSyncProgress; +- (BOOL)_shouldHideProgressInFirstSevenDays; + +@end + +@interface IMItemsController : NSObject +{ + struct __CFArray *_items; + unsigned long long _capacity; +} + ++ (id)_charactersToIgnoreWhenParsingTextContent; +@property(nonatomic) unsigned long long capacity; // @synthesize capacity=_capacity; +- (BOOL)_trimIfNeeded; +- (id)_lastRelatedIncomingFinishedMessageTextContentWithLimit:(long long)arg1; +- (id)_lastIncomingFinishedMessageWithTextContent; +- (id)_lastIncomingFinishedMessage; +- (id)_lastIncomingMessage; +- (id)_lastFinishedMessage; +- (id)_lastSentMessage; +- (id)_lastMessage; +- (id)_firstMessage; +- (id)_typingMessage; +- (id)_itemForGUID:(id)arg1; +- (id)_member:(id)arg1; +- (unsigned long long)_indexOfItem:(id)arg1; +- (void)_setSortID:(id)arg1; +- (void)_replaceStaleTypingMessage; +- (void)_removeAllItems; +- (void)_replaceItems:(id)arg1; +- (void)_removeItem:(id)arg1; +- (void)_handleItem:(id)arg1; +- (void)_itemsDidChange:(id)arg1; +- (id)_items; +- (id)_initWithItems:(id)arg1; +- (void)assignSortIDsToItems:(id)arg1; +@property(readonly, nonatomic) BOOL isMoreToLoad; +- (void)dealloc; +- (id)init; + +@end + +@interface IMAutomationPersonCentricChats : NSObject +{ +} + +- (void)initiateCNContactBasedMerging; + +@end + +@class IMChat, IMPluginPayload, IMMessage; +@interface IMBalloonPluginDataSource : NSObject +{ + BOOL _payloadInShelf; + BOOL _initialMessageIsFromMe; + BOOL _isLast; + BOOL _isShowingLatestMessageAsBreadcrumb; + BOOL _hasInvalidatedSize; + BOOL _parentChatHasAllUnknownRecipients; + BOOL _showingLatestMessageAsBreadcrumb; + IMChat *_chat; + IMPluginPayload *_pluginPayload; + NSURL *_url; + // DDScannerResult *_dataDetectedResult; + NSArray *_attachmentGUIDs; + NSURL *_URLToOpenOnTapAction; + NSArray *_pendingAttachmentData; + NSMutableSet *_temporaryAttachmentURLs; + NSString *__imMessageGUID; + NSString *_messageGUID; + NSString *_sessionGUID; + NSString *_bundleID; + NSArray *_consumedPayloads; + NSString *_guidOfLastMessageInSession; + long long _messageIDOfLastMessageInSession; +} + ++ (id)replaceHandleWithContactNameInString:(id)arg1 forAccount:(id)arg2 additionalHandles:(id)arg3; ++ (BOOL)supportsIndividualPreviewSummaries; ++ (id)previewSummary; ++ (id)previewSummaryForPluginPayload:(id)arg1 withBundleID:(id)arg2 previewAttachmentURL:(id *)arg3 previewAttachmentUTI:(id *)arg4; ++ (id)previewSummaryForPluginBundle:(id)arg1; ++ (id)unlocalizedPreviewSummaryForPluginBundle:(id)arg1 pluginDisplayName:(id)arg2; ++ (BOOL)supportsURL:(id)arg1; +@property(readonly, nonatomic) long long messageIDOfLastMessageInSession; // @synthesize messageIDOfLastMessageInSession=_messageIDOfLastMessageInSession; +@property(readonly, retain, nonatomic) NSString *guidOfLastMessageInSession; // @synthesize guidOfLastMessageInSession=_guidOfLastMessageInSession; +@property(readonly, nonatomic, getter=isShowingLatestMessageAsBreadcrumb) BOOL showingLatestMessageAsBreadcrumb; // @synthesize showingLatestMessageAsBreadcrumb=_showingLatestMessageAsBreadcrumb; +@property(nonatomic) BOOL parentChatHasAllUnknownRecipients; // @synthesize parentChatHasAllUnknownRecipients=_parentChatHasAllUnknownRecipients; +@property(retain, nonatomic) NSArray *consumedPayloads; // @synthesize consumedPayloads=_consumedPayloads; +@property(nonatomic) BOOL hasInvalidatedSize; // @synthesize hasInvalidatedSize=_hasInvalidatedSize; +@property(readonly, retain, nonatomic) NSString *bundleID; // @synthesize bundleID=_bundleID; +@property(retain, nonatomic) NSString *sessionGUID; // @synthesize sessionGUID=_sessionGUID; +@property(retain, nonatomic) NSString *messageGUID; // @synthesize messageGUID=_messageGUID; +@property(nonatomic, setter=setShowingLatestMessageAsBreadcrumb:) BOOL isShowingLatestMessageAsBreadcrumb; // @synthesize isShowingLatestMessageAsBreadcrumb=_isShowingLatestMessageAsBreadcrumb; +@property(retain, nonatomic) NSString *_imMessageGUID; // @synthesize _imMessageGUID=__imMessageGUID; +@property(retain, nonatomic) NSMutableSet *temporaryAttachmentURLs; // @synthesize temporaryAttachmentURLs=_temporaryAttachmentURLs; +@property(retain, nonatomic) NSArray *pendingAttachmentData; // @synthesize pendingAttachmentData=_pendingAttachmentData; +@property(nonatomic, setter=setLast:) BOOL isLast; // @synthesize isLast=_isLast; +@property(nonatomic) BOOL initialMessageIsFromMe; // @synthesize initialMessageIsFromMe=_initialMessageIsFromMe; +@property(readonly, nonatomic) NSURL *URLToOpenOnTapAction; // @synthesize URLToOpenOnTapAction=_URLToOpenOnTapAction; +@property(retain, nonatomic) NSArray *attachmentGUIDs; // @synthesize attachmentGUIDs=_attachmentGUIDs; +// @property(retain, nonatomic) DDScannerResult *dataDetectedResult; // @synthesize dataDetectedResult=_dataDetectedResult; +@property(retain, nonatomic) NSURL *url; // @synthesize url=_url; +@property(nonatomic) BOOL payloadInShelf; // @synthesize payloadInShelf=_payloadInShelf; +@property(retain, nonatomic) IMPluginPayload *pluginPayload; // @synthesize pluginPayload=_pluginPayload; +@property(retain, nonatomic) IMChat *chat; // @synthesize chat=_chat; + +- (id)description; +- (void)_reloadLatestUnconsumedBreadcrumb; +- (void)endShowingLastConsumedBreadcrumb; +- (void)beginShowingLastConsumedBreadcrumbForOutgoingPayload:(id)arg1; +- (id)_replaceHandleWithContactNameInString:(id)arg1; +// @property(readonly, nonatomic) LPLinkMetadata *richLinkMetadata; +- (void)datasourceWasMovedToNewGuid:(id)arg1; +- (struct CGSize)sizeThatFits:(struct CGSize)arg1; +- (id)individualPreviewAttachmentFileAndUTI:(id *)arg1; +- (id)_summaryText; +- (id)individualPreviewSummary; +- (void)stopPlayback; +- (void)playbackWithCompletionBlock:(CDUnknownBlockType)arg1; +- (unsigned long long)playbackType; +- (void)markAsPlayed; +- (void)needsResize; +@property(readonly, nonatomic) BOOL supportsDynamicSize; +- (void)statusStringNeedsUpdate; +@property(readonly, nonatomic) BOOL wantsReplyFromContentView; +- (void)didTapStatusItem; +@property(readonly, retain, nonatomic) NSAttributedString *statusAttributedString; +@property(readonly, retain, nonatomic) NSString *statusString; +@property(readonly, nonatomic) BOOL wantsStatusItem; +- (void)payloadWillSendFromShelf; +- (void)payloadWillEnterShelf; +- (void)thumbnailURLWithSize:(struct CGSize)arg1 completion:(CDUnknownBlockType)arg2; +- (void)payloadDidChange; +- (void)pluginPayloadDidChange:(unsigned long long)arg1; +@property(readonly, nonatomic) BOOL isPlayed; +@property(readonly, nonatomic) BOOL isFromMe; +- (unsigned long long)_updateWithPluginPayload:(id)arg1 messageID:(long long)arg2 messageGUID:(id)arg3; +- (void)_removeTemporaryAttachmentURLs; +- (void)_updateTemporaryAttachmentURLsForPluginPayload; +- (BOOL)_senderIsSameBetweenPayload:(id)arg1 andOtherPayload:(id)arg2; +- (void)_updatePayload:(id)arg1 messageID:(long long)arg2 messageGUID:(id)arg3; +- (void)updatePayload:(id)arg1 attachments:(id)arg2; +- (void)updatePayload:(id)arg1; +- (void)sendPayload:(id)arg1 attachments:(id)arg2; +- (void)sendPayload:(id)arg1; +@property(readonly, nonatomic) IMMessage *imMessage; +@property(readonly, retain, nonatomic) NSData *messagePayloadDataForSending; +- (void)setPayload:(id)arg1 attachments:(id)arg2; +@property(retain, nonatomic) NSData *payload; +@property(readonly, nonatomic) NSArray *allPayloads; +- (id)initWithPluginPayload:(id)arg1; +- (id)initWithMessageGUID:(id)arg1 payload:(id)arg2 dataDetectedResult:(id)arg3 url:(id)arg4; + +@end + +@interface IMChatItem : NSObject +{ + IMItem *_item; +} + + +@property(readonly, retain, nonatomic) NSString *balloonBundleID; +- (void)_setTimeAdded:(id)arg1; +- (id)_timeAdded; +- (id)_timeStale; +- (id)_item; +- (id)_initWithItem:(id)arg1; +@property(readonly, nonatomic) BOOL canDelete; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)description; + +@end + + +@interface IMTranscriptChatItem : IMChatItem +{ + NSString *_guid; + unsigned char _contiguousType; + unsigned char _attachmentContiguousType; + unsigned int _contiguousLoaded:1; +} + +@property(copy, nonatomic, setter=_setGUID:) NSString *guid; // @synthesize guid=_guid; + +- (void)_setAttachmentContiguousType:(unsigned char)arg1; +- (void)_setContiguousType:(unsigned char)arg1; +- (void)_setContiguousLoaded:(BOOL)arg1; +- (BOOL)_isContiguousLoaded; +@property(readonly, nonatomic, getter=isContiguous) BOOL contiguous; +@property(readonly, nonatomic) unsigned char attachmentContiguousType; +@property(readonly, nonatomic) unsigned char contiguousType; +- (BOOL)isAttachmentContiguousWithChatItem:(id)arg1; +- (BOOL)isContiguousWithChatItem:(id)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (BOOL)isEqual:(id)arg1; +- (unsigned long long)hash; +- (id)description; + +@end + +@interface IMReportSpamChatItem : IMTranscriptChatItem +{ + BOOL _wasReportedAsSpam; + BOOL _isGroupMessage; + BOOL _hasMultipleMessages; + BOOL _showReportSMSSpam; +} + +@property(readonly, nonatomic) BOOL showReportSMSSpam; // @synthesize showReportSMSSpam=_showReportSMSSpam; +@property(readonly, nonatomic) BOOL hasMultipleMessages; // @synthesize hasMultipleMessages=_hasMultipleMessages; +@property(readonly, nonatomic) BOOL isGroupMessage; // @synthesize isGroupMessage=_isGroupMessage; +@property(readonly, nonatomic) BOOL wasReportedAsSpam; // @synthesize wasReportedAsSpam=_wasReportedAsSpam; +- (id)_initWithItem:(id)arg1 wasReportedAsSpam:(BOOL)arg2 isGroup:(BOOL)arg3 hasMultipleMessages:(BOOL)arg4 showReportSMSSpam:(BOOL)arg5; + +@end + +@interface IMServiceChatItem : IMTranscriptChatItem +{ + IMHandle *_handle; + IMServiceImpl *_service; +} + +@property(readonly, nonatomic) IMHandle *handle; // @synthesize handle=_handle; +@property(readonly, nonatomic) IMServiceImpl *service; // @synthesize service=_service; + +- (id)_initWithItem:(id)arg1 service:(id)arg2 handle:(id)arg3; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMNumberChangedChatItem : IMTranscriptChatItem +{ + NSString *_sender; +} + +@property(readonly, nonatomic) NSString *sender; // @synthesize sender=_sender; + +- (id)_initWithItem:(id)arg1 senderHandle:(id)arg2; + +@end + +@interface IMDateChatItem : IMTranscriptChatItem +{ +} + +- (id)_initWithItem:(id)arg1; +@property(readonly, nonatomic) NSDate *date; + +@end + +@interface IMSenderChatItem : IMTranscriptChatItem +{ + IMHandle *_handle; +} + +@property(readonly, nonatomic) IMHandle *handle; // @synthesize handle=_handle; + +- (id)_initWithItem:(id)arg1 handle:(id)arg2; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMMessageChatItem : IMTranscriptChatItem +{ +} + +@property(readonly, nonatomic) IMHandle *sender; +@property(readonly, nonatomic) NSDate *time; +@property(readonly, nonatomic) BOOL failed; +@property(readonly, nonatomic) BOOL isFromMe; +@property(readonly, nonatomic) IMMessage *message; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly) Class superclass; + +@end + +@interface IMMessagePartChatItem : IMMessageChatItem +{ + NSAttributedString *_text; + NSAttributedString *_fallbackCorruptText; + long long _index; + struct _NSRange _messagePartRange; + NSArray *_visibleAssociatedMessageChatItems; + NSArray *_messageEditChatItems; + BOOL _isBusiness; + BOOL _chatInScrutinyMode; + BOOL _whitelistedRichLinkSender; +} + ++ (id)_messageItemWithPartsDeleted:(id)arg1 fromMessageItem:(id)arg2; ++ (id)_newMessagePartsForMessageItem:(id)arg1 shouldDisplayLink:(BOOL)arg2 isBusiness:(BOOL)arg3 parentChatIsSpam:(BOOL)arg4 hasKnownParticipants:(BOOL)arg5; ++ (BOOL)_supportsRichLinkURL:(id)arg1 forSender:(id)arg2 isWhitelistedRichLinkSender:(BOOL)arg3; ++ (id)_richLinkRangesForMessageText:(id)arg1 sender:(id)arg2 isWhitelistedRichLinkSender:(BOOL)arg3; ++ (id)_additionalSupportedRichLinkSchemesForWhitelistedSender:(id)arg1; ++ (BOOL)_isWhitelistedRichLinkSender:(id)arg1 isBusiness:(BOOL)arg2; ++ (id)_defaultRichLinkSenderWhitelist; ++ (BOOL)_isWhiteListedURL:(id)arg1; ++ (id)_defaultRichLinkWhiteList; ++ (id)_newMessagePartsForMessageItem:(id)arg1; ++ (id)_guidForMessage:(id)arg1 url:(id)arg2; +@property(nonatomic, getter=isWhitelistedRichLinkSender) BOOL whitelistedRichLinkSender; // @synthesize whitelistedRichLinkSender=_whitelistedRichLinkSender; +@property(readonly, copy, nonatomic) NSAttributedString *fallbackCorruptText; // @synthesize fallbackCorruptText=_fallbackCorruptText; +@property(nonatomic) BOOL chatInScrutinyMode; // @synthesize chatInScrutinyMode=_chatInScrutinyMode; +@property(readonly, nonatomic) NSArray *messageEditChatItems; // @synthesize messageEditChatItems=_messageEditChatItems; +@property(retain, nonatomic, setter=_setVisibleAssociatedMessageChatItems:) NSArray *visibleAssociatedMessageChatItems; // @synthesize visibleAssociatedMessageChatItems=_visibleAssociatedMessageChatItems; +@property(nonatomic) struct _NSRange messagePartRange; // @synthesize messagePartRange=_messagePartRange; +@property(nonatomic) long long index; // @synthesize index=_index; +@property(readonly, copy, nonatomic) NSAttributedString *text; // @synthesize text=_text; + +- (BOOL)canSendMessageAcknowledgment; +- (void)_setMessageEditChatItems:(id)arg1; +- (id)_initWithItem:(id)arg1 text:(id)arg2 index:(long long)arg3 messagePartRange:(struct _NSRange)arg4 visibleAssociatedMessageChatItems:(id)arg5; +- (id)_initWithItem:(id)arg1 messagePartRange:(struct _NSRange)arg2; +@property(readonly, nonatomic) BOOL isCorrupt; +@property(nonatomic) BOOL isBusiness; // @synthesize isBusiness=_isBusiness; +- (BOOL)canDelete; +- (id)copyWithZone:(struct _NSZone *)arg1; +@property(readonly, copy) NSString *description; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly) Class superclass; + +@end + +@interface IMTextMessagePartChatItem : IMMessagePartChatItem +{ + NSAttributedString *_subject; +} + +@property(readonly, copy, nonatomic) NSAttributedString *subject; // @synthesize subject=_subject; + +- (id)_initWithItem:(id)arg1 text:(id)arg2 index:(long long)arg3 messagePartRange:(struct _NSRange)arg4 subject:(id)arg5 visibleAssociatedMessageChatItems:(id)arg6; +- (id)_initWithItem:(id)arg1 text:(id)arg2 index:(long long)arg3 messagePartRange:(struct _NSRange)arg4 subject:(id)arg5; +- (id)_initWithItem:(id)arg1 text:(id)arg2 index:(long long)arg3 messagePartRange:(struct _NSRange)arg4 subject:(id)arg5 shouldDisplayLink:(BOOL)arg6; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)description; +- (void)setShouldDisplayRichLink:(BOOL)arg1; +- (BOOL)shouldDisplayRichLink; + +@end + +@interface IMTranscriptPluginChatItem : IMMessagePartChatItem +{ + BOOL _isLastChatItemOfPluginType; + BOOL _hasSetIsLastChatItemOfPluginType; + BOOL _parentChatHasKnownParticipants; + IMPluginPayload *_initialPayload; + NSString *_bundleIdentifier; + IMBalloonPluginDataSource *_dataSource; +} + +@property(retain, nonatomic) IMBalloonPluginDataSource *dataSource; // @synthesize dataSource=_dataSource; +@property(readonly, nonatomic) BOOL parentChatHasKnownParticipants; // @synthesize parentChatHasKnownParticipants=_parentChatHasKnownParticipants; +@property(nonatomic) BOOL hasSetIsLastChatItemOfPluginType; // @synthesize hasSetIsLastChatItemOfPluginType=_hasSetIsLastChatItemOfPluginType; +@property(nonatomic, setter=setLastChatItemOfPluginType:) BOOL isLastChatItemOfPluginType; // @synthesize isLastChatItemOfPluginType=_isLastChatItemOfPluginType; +@property(retain, nonatomic) NSString *bundleIdentifier; // @synthesize bundleIdentifier=_bundleIdentifier; +@property(retain, nonatomic) IMPluginPayload *initialPayload; // @synthesize initialPayload=_initialPayload; + +- (BOOL)wantsAutoPlayback; +@property(readonly, nonatomic) BOOL isSaved; +@property(readonly, nonatomic) BOOL isPlayed; +@property(readonly, nonatomic) unsigned long long playbackType; +@property(readonly, nonatomic) NSString *pluginSessionGUID; +@property(readonly, nonatomic) BOOL isDataSourceInitialized; +- (id)_initWithItem:(id)arg1 initialPayload:(id)arg2 messagePartRange:(struct _NSRange)arg3 parentChatHasKnownParticipants:(BOOL)arg4; +- (id)copyWithZone:(struct _NSZone *)arg1; +@property(readonly, copy) NSString *description; +@property(readonly, retain, nonatomic) NSString *type; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, nonatomic) BOOL isFromMe; +@property(readonly) Class superclass; + +@end + +@interface IMTranscriptPluginBreadcrumbChatItem : IMTranscriptChatItem +{ + IMBalloonPluginDataSource *_dataSource; + NSString *_rawStatusText; + NSString *_statusText; + unsigned long long _optionFlags; +} + +@property(readonly, nonatomic) unsigned long long optionFlags; // @synthesize optionFlags=_optionFlags; +@property(readonly, nonatomic) NSString *statusText; // @synthesize statusText=_statusText; +@property(readonly, nonatomic) NSString *rawStatusText; // @synthesize rawStatusText=_rawStatusText; +@property(retain, nonatomic) IMBalloonPluginDataSource *dataSource; // @synthesize dataSource=_dataSource; + +@property(readonly, nonatomic) BOOL isFromMe; +@property(readonly, retain, nonatomic) NSString *type; +- (void)configureStatusTextWithAccount:(id)arg1; +- (BOOL)isEqual:(id)arg1; +- (id)_initWithItem:(id)arg1 datasource:(id)arg2 statusText:(id)arg3 optionFlags:(unsigned long long)arg4; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly) Class superclass; + +@end + +@interface IMAttachmentMessagePartChatItem : IMMessagePartChatItem +{ + NSString *_transferGUID; + unsigned int _wantsAttachmentContiguous:1; + BOOL _parentChatIsSpam; +} + +@property(readonly, nonatomic) BOOL parentChatIsSpam; // @synthesize parentChatIsSpam=_parentChatIsSpam; +@property(readonly, copy, nonatomic) NSString *transferGUID; // @synthesize transferGUID=_transferGUID; + +- (id)_initWithItem:(id)arg1 text:(id)arg2 index:(long long)arg3 messagePartRange:(struct _NSRange)arg4 transferGUID:(id)arg5 parentChatIsSpam:(BOOL)arg6 visibleAssociatedMessageChatItems:(id)arg7; +- (id)_initWithItem:(id)arg1 text:(id)arg2 index:(long long)arg3 messagePartRange:(struct _NSRange)arg4 transferGUID:(id)arg5 parentChatIsSpam:(BOOL)arg6; +- (BOOL)isAttachmentContiguousWithChatItem:(id)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)description; + +@end + +@interface IMAnimatedEmojiMessagePartChatItem : IMAttachmentMessagePartChatItem +{ +} + +- (BOOL)isAttachmentContiguousWithChatItem:(id)arg1; + +@end + +@interface IMErrorMessagePartChatItem : IMAttachmentMessagePartChatItem +{ +} + +@end + +@interface IMExpirableMessageChatItem : IMAttachmentMessagePartChatItem +{ +} + +@property(readonly, nonatomic) BOOL isSaved; +@property(readonly, nonatomic) BOOL isPlayed; + +@end + +@interface IMAudioMessageChatItem : IMExpirableMessageChatItem +{ +} + +- (BOOL)isAttachmentContiguousWithChatItem:(id)arg1; + +@end + +@interface IMTypingChatItem : IMMessageChatItem +{ +} + +- (id)_initWithItem:(id)arg1; + +@end + +@interface IMTypingPluginChatItem : IMTypingChatItem +{ + NSData *_typingIndicatorIcon; + IMBalloonPluginDataSource *_dataSource; +} + +@property(retain, nonatomic) IMBalloonPluginDataSource *dataSource; // @synthesize dataSource=_dataSource; +@property(readonly, nonatomic) NSData *typingIndicatorIcon; // @synthesize typingIndicatorIcon=_typingIndicatorIcon; + +- (id)_initWithItem:(id)arg1 dataSource:(id)arg2; +@property(readonly, retain, nonatomic) NSString *type; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly, nonatomic) BOOL isFromMe; +@property(readonly) Class superclass; + +@end + +@interface IMLocatingChatItem : IMMessageChatItem +{ +} + +- (id)_initWithItem:(id)arg1; + +@end + +@interface IMEmoteMessageChatItem : IMMessageChatItem +{ +} + +- (id)_initWithItem:(id)arg1; +@property(readonly, copy, nonatomic) NSAttributedString *text; + +@end + +@interface IMMessageStatusChatItem : IMTranscriptChatItem +{ + long long _statusType; + NSDate *_time; + long long _expireStatusType; + NSDate *_timeAdded; + NSDate *_timeStale; + unsigned long long _count; +} + +@property(readonly, nonatomic) unsigned long long count; // @synthesize count=_count; +@property(readonly, nonatomic) long long expireStatusType; // @synthesize expireStatusType=_expireStatusType; +@property(readonly, nonatomic) NSDate *time; // @synthesize time=_time; +@property(readonly, nonatomic) long long statusType; // @synthesize statusType=_statusType; + +- (id)_initWithItem:(id)arg1 statusType:(long long)arg2 time:(id)arg3 count:(unsigned long long)arg4 expireStatusType:(long long)arg5; +- (id)_initWithItem:(id)arg1 expireStatusType:(long long)arg2 count:(unsigned long long)arg3; +- (id)_initWithItem:(id)arg1 statusType:(long long)arg2 time:(id)arg3 count:(unsigned long long)arg4; +@property(readonly, nonatomic) long long messageStatusType; +@property(readonly, nonatomic) NSString *errorText; +@property(readonly, nonatomic) BOOL isFromMe; +- (void)_setTimeAdded:(id)arg1; +- (id)_timeAdded; +- (id)_timeStale; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)description; + +@end + +@interface IMMessageEffectControlChatItem : IMMessageStatusChatItem +{ + NSString *_effectStyleID; +} + +@property(readonly, copy, nonatomic) NSString *effectStyleID; // @synthesize effectStyleID=_effectStyleID; + +- (id)_initWithItem:(id)arg1 effectStyleID:(id)arg2; + +@end + +@interface IMMessageAttributionChatItem : IMMessageStatusChatItem +{ + NSDictionary *_attributionInfo; + long long _attributionType; +} + +@property(readonly, nonatomic) long long attributionType; // @synthesize attributionType=_attributionType; +@property(readonly, copy, nonatomic) NSDictionary *attributionInfo; // @synthesize attributionInfo=_attributionInfo; + +@property(readonly, copy, nonatomic) NSString *bundleID; +- (id)_initWithItem:(id)arg1 attributionInfo:(id)arg2 attributionType:(long long)arg3; + +@end + +@interface IMTranscriptPluginStatusChatItem : IMMessageStatusChatItem +{ + IMBalloonPluginDataSource *_dataSource; +} + +@property(readonly, nonatomic) IMBalloonPluginDataSource *dataSource; // @synthesize dataSource=_dataSource; + +- (id)_initWithItem:(id)arg1 dataSource:(id)arg2; + +@end + +@interface IMGroupActionChatItem : IMTranscriptChatItem +{ + IMHandle *_sender; +} + +@property(readonly, nonatomic) IMHandle *sender; // @synthesize sender=_sender; + +- (id)_initWithItem:(id)arg1 sender:(id)arg2; +@property(readonly, nonatomic) long long actionType; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMGroupTitleChangeChatItem : IMTranscriptChatItem +{ + IMHandle *_sender; +} + +@property(readonly, nonatomic) IMHandle *sender; // @synthesize sender=_sender; + +- (id)_initWithItem:(id)arg1 sender:(id)arg2; +@property(readonly, copy, nonatomic) NSString *title; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMParticipantChangeChatItem : IMTranscriptChatItem +{ + IMHandle *_sender; + IMHandle *_otherHandle; +} + +@property(readonly, nonatomic) IMHandle *otherHandle; // @synthesize otherHandle=_otherHandle; +@property(readonly, nonatomic) IMHandle *sender; // @synthesize sender=_sender; + +- (id)_initWithItem:(id)arg1 sender:(id)arg2 otherHandle:(id)arg3; +@property(readonly, nonatomic) long long changeType; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMLocationShareActionChatItem : IMTranscriptChatItem +{ + IMHandle *_sender; + IMHandle *_otherHandle; +} + +@property(readonly, nonatomic) IMHandle *otherHandle; // @synthesize otherHandle=_otherHandle; +@property(readonly, nonatomic) IMHandle *sender; // @synthesize sender=_sender; + +- (id)_initWithItem:(id)arg1 sender:(id)arg2 otherHandle:(id)arg3; +@property(readonly, nonatomic) long long direction; +@property(readonly, nonatomic) long long actionType; +@property(readonly, nonatomic) BOOL isFromMe; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMTUConversationChatItem : IMTranscriptChatItem +{ + IMHandle *_conversationInitiator; +} + +@property(readonly, nonatomic) IMHandle *conversationInitiator; // @synthesize conversationInitiator=_conversationInitiator; + +- (BOOL)canDelete; +@property(readonly, nonatomic) NSDate *time; +@property(readonly, nonatomic) BOOL isFromMe; +// @property(readonly, nonatomic) __weak TUConversation *tuConversation; +@property(readonly, nonatomic) NSUUID *tuConversationUUID; +- (id)activeCall; +- (id)_initWithItem:(id)arg1 conversationInitiator:(id)arg2; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMMessageActionChatItem : IMTranscriptChatItem +{ + IMHandle *_sender; + IMHandle *_otherHandle; +} + +@property(readonly, nonatomic) IMHandle *otherHandle; // @synthesize otherHandle=_otherHandle; +@property(readonly, nonatomic) IMHandle *sender; // @synthesize sender=_sender; + +- (id)_initWithItem:(id)arg1 sender:(id)arg2 otherHandle:(id)arg3; +@property(readonly, nonatomic) long long actionType; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMAssociatedMessageChatItem : IMTranscriptChatItem +{ + struct IMAssociatedMessageGeometryDescriptor _geometryDescriptor; + BOOL _parentMessageIsFromMe; + IMHandle *_sender; +} + +@property(readonly, nonatomic) IMHandle *sender; // @synthesize sender=_sender; +@property(readonly, nonatomic) struct IMAssociatedMessageGeometryDescriptor geometryDescriptor; // @synthesize geometryDescriptor=_geometryDescriptor; + +@property(readonly, nonatomic) NSDictionary *messageSummaryInfo; +@property(readonly, nonatomic) BOOL failed; +- (void)_setParentMessageIsFromMe:(BOOL)arg1; +@property(readonly, nonatomic) BOOL parentMessageIsFromMe; +@property(readonly, nonatomic) struct _NSRange associatedMessageRange; +@property(readonly, nonatomic) long long associatedMessageType; +@property(readonly, nonatomic) NSString *associatedMessageGUID; +@property(readonly, nonatomic) BOOL isFromMe; +@property(readonly, nonatomic) NSDate *time; +- (id)message; +- (id)_imAssociatedMessageItem; +- (id)_initWithItem:(id)arg1 sender:(id)arg2; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMMessageEditChatItem : IMAssociatedMessageChatItem +{ + NSArray *_visibleAssociatedMessageChatItems; +} + +@property(retain, nonatomic, setter=_setVisibleAssociatedMessageChatItems:) NSArray *visibleAssociatedMessageChatItems; // @synthesize visibleAssociatedMessageChatItems=_visibleAssociatedMessageChatItems; + +@property(readonly, retain, nonatomic) NSAttributedString *editedBody; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly) Class superclass; + +@end + +@interface IMMessageAcknowledgmentChatItem : IMAssociatedMessageChatItem +{ + long long _messageAcknowledgmentType; +} + +@property(readonly, nonatomic) long long messageAcknowledgmentType; // @synthesize messageAcknowledgmentType=_messageAcknowledgmentType; +- (id)_initWithItem:(id)arg1 sender:(id)arg2 messageAcknowledgmentType:(long long)arg3; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface IMAssociatedStickerChatItem : IMAssociatedMessageChatItem +{ + NSString *_transferGUID; +} + +@property(readonly, copy, nonatomic) NSString *transferGUID; // @synthesize transferGUID=_transferGUID; + +- (id)_initWithItem:(id)arg1 sender:(id)arg2 transferGUID:(id)arg3; +- (BOOL)canDelete; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)description; + +@end + +@interface IMAggregateAcknowledgmentChatItem : IMAssociatedMessageChatItem +{ + BOOL _latestIsFromMe; + BOOL _includesMultiple; + NSArray *_acknowledgments; + IMMessageAcknowledgmentChatItem *_fromMeAcknowledgement; + long long _latestAcknowledgmentType; +} + +@property(readonly, nonatomic) long long latestAcknowledgmentType; // @synthesize latestAcknowledgmentType=_latestAcknowledgmentType; +@property(readonly, nonatomic) BOOL includesMultiple; // @synthesize includesMultiple=_includesMultiple; +@property(readonly, nonatomic) BOOL latestIsFromMe; // @synthesize latestIsFromMe=_latestIsFromMe; +@property(readonly, nonatomic) IMMessageAcknowledgmentChatItem *fromMeAcknowledgement; // @synthesize fromMeAcknowledgement=_fromMeAcknowledgement; +@property(readonly, copy, nonatomic) NSArray *acknowledgments; // @synthesize acknowledgments=_acknowledgments; + +- (id)copyWithZone:(struct _NSZone *)arg1; +- (BOOL)isEqual:(id)arg1; +- (unsigned long long)hash; +- (id)_initWithAcknowledgments:(id)arg1; +@property(readonly, nonatomic) BOOL includesFromMe; + +@end + +@interface IMExpressiveSendAsTextChatItem : IMTranscriptChatItem +{ + NSString *_text; +} + +@property(readonly, copy, nonatomic) NSString *text; // @synthesize text=_text; + +- (id)_initWithItem:(id)arg1 text:(id)arg2; + +@end + + +@interface IMDaemonListener : NSObject +{ + NSMutableDictionary *_properties; + NSMutableDictionary *_persistentProperties; + NSMutableArray *_deferredChatMessages; + NSMutableArray *_handlers; + NSProtocolChecker *_protocol; + NSMutableDictionary *_services; + NSDate *_myIdleSince; + NSData *_myPicture; + NSMutableDictionary *_contexts; + NSString *_myStatusMessage; + NSString *_myNowPlayingString; + unsigned long long _myStatus; + unsigned long long _vcCapabilities; + BOOL _setupComplete; + BOOL _postedSetupComplete; + BOOL _holdingChatMessages; + BOOL _hidingDisconnect; + BOOL _hasPendingProcessChange; +} + +@property(readonly, nonatomic) NSDictionary *persistentProperties; // @synthesize persistentProperties=_persistentProperties; +@property(readonly, nonatomic) NSDictionary *properties; // @synthesize properties=_properties; +@property(readonly, nonatomic) BOOL hasPostedSetupComplete; // @synthesize hasPostedSetupComplete=_postedSetupComplete; +@property(readonly, nonatomic) BOOL shouldHoldChatMessages; // @synthesize shouldHoldChatMessages=_holdingChatMessages; +@property(readonly, nonatomic) unsigned long long vcCapabilities; // @synthesize vcCapabilities=_vcCapabilities; +@property(readonly, nonatomic) NSString *myStatusMessage; // @synthesize myStatusMessage=_myStatusMessage; +@property(readonly, nonatomic) BOOL isSetupComplete; // @synthesize isSetupComplete=_setupComplete; +@property(readonly, nonatomic) NSArray *handlers; // @synthesize handlers=_handlers; +@property(nonatomic, setter=_setHidingDisconnect:) BOOL _hidingDisconnect; // @synthesize _hidingDisconnect; +@property(readonly, nonatomic) NSMutableDictionary *_contexts; // @synthesize _contexts; + +- (void)oneTimeCodesDidChange:(id)arg1; +- (void)receivedUrgentRequestForMessages:(id)arg1; +- (void)returnMOCEnabledState:(unsigned long long)arg1; +- (void)updateCloudKitStateWithDictionary:(id)arg1; +- (void)updateCloudKitState; +- (void)didAttemptToDisableAllDevicesResult:(BOOL)arg1; +- (void)didPerformAdditionalStorageRequiredCheckWithSuccess:(BOOL)arg1 additionalStorageRequired:(unsigned long long)arg2 forAccountId:(id)arg3 error:(id)arg4; +- (void)didAttemptToSetEnabledTo:(BOOL)arg1 result:(BOOL)arg2; +- (void)qosClassWhileServicingRequestsResponse:(unsigned int)arg1 identifier:(id)arg2; +- (void)forwardInvocation:(id)arg1; +- (id)methodSignatureForSelector:(SEL)arg1; +- (void)didFetchCloudKitSyncDebuggingInfo:(id)arg1; +- (void)didAttemptToDisableiCloudBackups:(long long)arg1 error:(id)arg2; +- (void)didFetchRampState:(id)arg1; +- (void)didFetchSyncStateStats:(id)arg1; +- (void)databaseChatSpamUpdated:(id)arg1; +- (void)databaseNoLongerFull; +- (void)databaseFull; +- (void)databaseUpdated:(id)arg1; +- (void)_deferredSetup:(id)arg1; +- (void)setupComplete:(BOOL)arg1 info:(id)arg2; +- (void)account:(id)arg1 defaults:(id)arg2 blockList:(id)arg3 allowList:(id)arg4 blockingMode:(unsigned int)arg5 blockIdleStatus:(BOOL)arg6 status:(id)arg7 capabilities:(unsigned long long)arg8 serviceLoginStatus:(unsigned int)arg9 loginStatusMessage:(id)arg10; +- (void)service:(id)arg1 properties:(id)arg2 defaults:(id)arg3 defaultAccountSettings:(id)arg4 allAccounts:(id)arg5 activeAccounts:(id)arg6; +- (void)services:(id)arg1 properties:(id)arg2 persistentProperties:(id)arg3; +- (void)account:(id)arg1 status:(id)arg2 capabilities:(unsigned long long)arg3 serviceLoginStatus:(unsigned int)arg4 loginStatusMessage:(id)arg5; +- (void)persistentProperty:(id)arg1 changedTo:(id)arg2 from:(id)arg3; +- (void)_cacheValue:(id)arg1 forPersistentProperty:(id)arg2; +- (id)valueOfPersistentProperty:(id)arg1; +- (void)property:(id)arg1 changedTo:(id)arg2 from:(id)arg3; +- (void)_cacheValue:(id)arg1 forProperty:(id)arg2; +- (id)valueOfProperty:(id)arg1; +- (id)_stampForContext:(id)arg1; +- (void)_setStamp:(id)arg1 forContext:(id)arg2; +- (void)account:(id)arg1 postedError:(id)arg2; +- (void)account:(id)arg1 blockIdleStatusChanged:(BOOL)arg2; +- (void)account:(id)arg1 blockingModeChanged:(unsigned int)arg2; +- (void)account:(id)arg1 allowListChanged:(id)arg2; +- (void)account:(id)arg1 blockListChanged:(id)arg2; +- (void)account:(id)arg1 handleSubscriptionRequestFrom:(id)arg2 withMessage:(id)arg3; +- (void)account:(id)arg1 groupsChanged:(id)arg2 error:(id)arg3; +- (void)fileTransferHighQualityDownloadFailed:(id)arg1; +- (void)fileTransfer:(id)arg1 highQualityDownloadSucceededWithPath:(id)arg2; +- (void)fileTransfer:(id)arg1 updatedWithCurrentBytes:(unsigned long long)arg2 totalBytes:(unsigned long long)arg3 averageTransferRate:(unsigned long long)arg4; +- (void)fileTransfer:(id)arg1 updatedWithProperties:(id)arg2; +- (void)fileTransfers:(id)arg1 createdWithLocalPaths:(id)arg2; +- (void)fileTransfer:(id)arg1 createdWithProperties:(id)arg2; +- (void)standaloneFileTransferRegistered:(id)arg1; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 messagesReceived:(id)arg5; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 messageReceived:(id)arg5; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 invitationReceived:(id)arg5; +- (void)account:(id)arg1 buddyInfo:(id)arg2 commandDelivered:(id)arg3 properties:(id)arg4; +- (void)account:(id)arg1 buddyInfo:(id)arg2 commandReceived:(id)arg3 properties:(id)arg4; +- (void)account:(id)arg1 buddyProperties:(id)arg2 buddyPictures:(id)arg3; +- (void)pinCodeAlertCompleted:(id)arg1 deviceName:(id)arg2 deviceType:(id)arg3 phoneNumber:(id)arg4 responseFromDevice:(BOOL)arg5 wasCancelled:(BOOL)arg6; +- (void)displayPinCodeForAccount:(id)arg1 pinCode:(id)arg2 deviceName:(id)arg3 deviceType:(id)arg4 phoneNumber:(id)arg5; +- (void)account:(id)arg1 buddyPictureChanged:(id)arg2 imageData:(id)arg3 imageHash:(id)arg4; +- (void)account:(id)arg1 buddyPropertiesChanged:(id)arg2; +- (void)vcCapabilitiesChanged:(unsigned long long)arg1; +- (void)account:(id)arg1 capabilitiesChanged:(unsigned long long)arg2; +- (void)account:(id)arg1 statusChanged:(id)arg2; +- (void)account:(id)arg1 loginStatusChanged:(unsigned int)arg2 message:(id)arg3 reason:(int)arg4 properties:(id)arg5; +- (void)accountRemoved:(id)arg1; +- (void)accountAdded:(id)arg1 defaults:(id)arg2 service:(id)arg3; +- (void)account:(id)arg1 defaultsChanged:(id)arg2; +- (void)activeAccountsChanged:(id)arg1 forService:(id)arg2; +- (void)defaultsChanged:(id)arg1 forService:(id)arg2; +- (void)releaseHeldChatMessages; +- (void)holdChatMessages; +@property(readonly, nonatomic) BOOL isHoldingChatMessages; +- (void)_deferNotification:(id)arg1; +- (void)_processDeferredInvitationDictionary:(id)arg1; +@property(readonly, nonatomic) unsigned int myIdleTime; +@property(readonly, nonatomic) unsigned long long myStatus; +- (void)_processMyStatusChanged; +- (void)_reallyProcessMyStatusChanged; +- (id)serviceWithName:(id)arg1; +@property(readonly, nonatomic) NSArray *allServices; +- (void)removeHandler:(id)arg1; +- (void)addHandler:(id)arg1; +- (void)_noteDisconnected; +- (id)init; + +@end + +@interface IMDaemonController : NSObject +{ + id _delegate; + // IMRemoteObject *_remoteObject; + NSMutableDictionary *_listenerMap; + // IMLocalObject *_localObject; + IMDaemonListener *_daemonListener; + NSMutableArray *_services; + NSProtocolChecker *_protocol; + NSString *_listenerID; + NSObject *_listenerLockQueue; + NSObject *_remoteDaemonLockQueue; + NSObject *_localObjectLockQueue; + NSObject *_remoteMessageQueue; + NSRecursiveLock *_connectionLock; + NSArray *_servicesToAllow; + NSArray *_servicesToDeny; + struct __CFRunLoopSource *_runLoopSource; + NSLock *_blockingLock; + BOOL _hasCheckedForDaemon; + BOOL _preventReconnect; + BOOL _inBlockingConnect; + BOOL _acquiringDaemonConnection; + BOOL _autoReconnect; + BOOL _blocksConnectionAtResume; + BOOL _hasBeenSuspended; + unsigned int _gMyFZListenerCapabilities; + unsigned int _cachedCapabilities; + unsigned int _lastUpdatedCapabilities; + BOOL _requestingConnection; + NSMutableDictionary *_requestQOSClassCompletionBlocks; + CDUnknownBlockType _prewarmingBlock; +} + ++ (void)_setApplicationWillTerminate; ++ (void)_blockUntilSendQueueIsEmpty; ++ (BOOL)_applicationWillTerminate; ++ (id)sharedController; ++ (id)sharedInstance; +@property(copy, nonatomic) CDUnknownBlockType prewarmingBlock; // @synthesize prewarmingBlock=_prewarmingBlock; +@property(retain, nonatomic) NSMutableDictionary *requestQOSClassCompletionBlocks; // @synthesize requestQOSClassCompletionBlocks=_requestQOSClassCompletionBlocks; +@property(readonly, nonatomic, getter=isRequestingConnection) BOOL requestingConnection; // @synthesize requestingConnection=_requestingConnection; +@property(readonly, nonatomic) NSObject *_remoteMessageQueue; // @synthesize _remoteMessageQueue; +@property(retain, setter=_setServicesToDeny:) NSArray *_servicesToDeny; // @synthesize _servicesToDeny; +@property(retain, setter=_setServicesToAllow:) NSArray *_servicesToAllow; // @synthesize _servicesToAllow; +@property(setter=__setCapabilities:) unsigned int _capabilities; // @synthesize _capabilities=_gMyFZListenerCapabilities; +@property(setter=_setAutoReconnect:) BOOL _autoReconnect; // @synthesize _autoReconnect; +@property(retain, nonatomic, setter=_setListenerID:) NSString *_listenerID; // @synthesize _listenerID; +@property(nonatomic) __weak id delegate; // @synthesize delegate=_delegate; +@property(nonatomic, setter=_setBlocksConnectionAtResume:) BOOL _blocksConnectionAtResume; // @synthesize _blocksConnectionAtResume; +@property(readonly, nonatomic) IMDaemonListener *listener; // @synthesize listener=_daemonListener; + +- (void)systemApplicationDidResume; +- (void)systemApplicationWillEnterForeground; +- (void)systemApplicationDidEnterBackground; +- (void)systemApplicationDidSuspend; +- (void)forwardInvocation:(id)arg1; +- (id)methodSignatureForSelector:(SEL)arg1; +- (void)setDaemonLogsOutWithoutStatusListeners:(BOOL)arg1; +- (void)setDaemonTerminatesWithoutListeners:(BOOL)arg1; +- (void)listener:(id)arg1 setValue:(id)arg2 ofPersistentProperty:(id)arg3; +- (void)listener:(id)arg1 setValue:(id)arg2 ofProperty:(id)arg3; +- (void)remoteObjectDiedNotification:(id)arg1; +- (void)localObjectDiedNotification:(id)arg1; +- (void)_setCapabilities:(unsigned int)arg1; +@property(readonly, nonatomic) unsigned int capabilities; +- (void)listener:(id)arg1 setListenerCapabilities:(unsigned int)arg2; +- (void)_remoteObjectCleanup; +- (void)_localObjectCleanup; +- (BOOL)localObjectExists; +- (BOOL)remoteObjectExists; +- (BOOL)__isRemoteObjectValidOnQueue:(id)arg1; +- (BOOL)__isLocalObjectValidOnQueue:(id)arg1; +- (void)_noteSetupComplete; +- (void)blockUntilConnected; +- (double)_connectionTimeout; +@property(readonly, nonatomic) BOOL isConnected; +@property(readonly, nonatomic) BOOL isConnecting; +- (BOOL)_acquiringDaemonConnection; +- (void)_addressBookChanged:(id)arg1; +- (void)setMyStatus:(unsigned long long)arg1 message:(id)arg2 forAccount:(id)arg3; +- (void)setMyStatus:(unsigned long long)arg1 message:(id)arg2; +- (void)setMyPicture:(id)arg1 smallPictureData:(id)arg2; +- (id)_remoteObject; +- (BOOL)setCapabilities:(unsigned int)arg1 forListenerID:(id)arg2; +- (unsigned int)capabilitiesForListenerID:(id)arg1; +- (BOOL)removeListenerID:(id)arg1; +- (BOOL)hasListenerForID:(id)arg1; +- (BOOL)addListenerID:(id)arg1 capabilities:(unsigned int)arg2; +- (void)_listenerSetUpdated; +- (void)sendABInformationToDaemon; +- (BOOL)connectToDaemonWithLaunch:(BOOL)arg1 capabilities:(unsigned int)arg2 blockUntilConnected:(BOOL)arg3; +- (BOOL)connectToDaemon; +- (BOOL)connectToDaemonWithLaunch:(BOOL)arg1; +- (void)_connectToDaemonWithLaunch:(BOOL)arg1 capabilities:(unsigned int)arg2; +- (void)disconnectFromDaemon; +- (void)_disconnectFromDaemonWithForce:(BOOL)arg1; +- (void)disconnectFromDaemonWithForce:(BOOL)arg1; +- (void)killDaemon; +- (void)_blockUntilSendQueueIsEmpty; +- (BOOL)_makeConnectionWithLaunch:(BOOL)arg1 completionBlock:(CDUnknownBlockType)arg2; +- (void)_handleDaemonException:(id)arg1; +- (void)_agentDidLaunchNotification:(id)arg1; +- (void)dealloc; +- (void)_handleReceivedQOSClassWhileServicingRequestsNotification:(id)arg1; +- (void)requestQOSClassOfAgentWhileServicingRequests:(CDUnknownBlockType)arg1; +- (id)init; + +@end + +@interface IMAutomation : NSObject +{ +} + +- (id)startConversationFrom:(id)arg1 andReceiveAt:(id)arg2; +- (id)IMCoreAutomationPerformOperationWithDictionary:(id)arg1; +- (id)callIMCoreMethodWithDictionary:(id)arg1; +- (_Bool)checkArgumentValidity:(id)arg1 forExpectedNumberOfArguments:(int)arg2; + +@end + + +@interface IMAccountController : NSObject +{ + NSMutableDictionary *_accountMap; + BOOL _isReadOnly; + BOOL _cachesEnabled; + NSArray *_operationalAccountsCache; + NSMutableDictionary *_serviceToActiveAccountsMap; + NSMutableDictionary *_serviceToAccountsMap; + NSMutableDictionary *_serviceToConnectedAccountsMap; + NSMutableDictionary *_serviceToOperationalAccountsMap; + NSArray *_accounts; +} + ++ (id)bestAccountFromAccounts:(id)arg1; ++ (id)sharedInstance; +@property(copy) NSArray *accounts; // @synthesize accounts=_accounts; + +- (void)_rebuildOperationalAccountsCache:(BOOL)arg1; +- (void)_disableCache; +- (void)_enableCache; +- (id)jabberAccount; +- (id)aimAccount; +- (id)mostLoggedInAccount; +- (id)bestAccountWithCapability:(unsigned long long)arg1; +- (id)bestConnectedAccountForService:(id)arg1; +- (id)bestActiveAccountForService:(id)arg1; +- (id)bestOperationalAccountForService:(id)arg1; +- (id)bestAccountForService:(id)arg1; +- (id)bestConnectedAccountForService:(id)arg1 withLogin:(id)arg2; +- (id)bestActiveAccountForService:(id)arg1 withLogin:(id)arg2; +- (id)bestOperationalAccountForService:(id)arg1 withLogin:(id)arg2; +- (id)bestAccountForService:(id)arg1 withLogin:(id)arg2; +- (id)bestAccountForService:(id)arg1 login:(id)arg2 guid:(id)arg3; +- (id)activeAccountsSupportingStatus; +@property(readonly, nonatomic) id bestAccountForStatus; +- (BOOL)canActivateAccounts:(id)arg1; +- (BOOL)canActivateAccount:(id)arg1; +- (BOOL)accountConnected:(id)arg1; +- (BOOL)accountConnecting:(id)arg1; +- (BOOL)activateAndHandleReconnectAccount:(id)arg1; +- (BOOL)activateAndHandleReconnectAccounts:(id)arg1; +- (BOOL)activateAccount:(id)arg1 force:(BOOL)arg2 locally:(BOOL)arg3; +- (BOOL)activateAccount:(id)arg1 force:(BOOL)arg2; +- (BOOL)activateAccount:(id)arg1; +- (BOOL)activateAccount:(id)arg1 locally:(BOOL)arg2; +- (BOOL)activateAccounts:(id)arg1; +- (BOOL)activateAccounts:(id)arg1 force:(BOOL)arg2 locally:(BOOL)arg3; +- (BOOL)deactivateAccount:(id)arg1 withDisable:(BOOL)arg2; +- (BOOL)deactivateAccounts:(id)arg1; +- (BOOL)_deactivateAccounts:(id)arg1; +- (BOOL)deactivateAccount:(id)arg1; +- (BOOL)_deactivateAccount:(id)arg1; +- (BOOL)deactivateAccounts:(id)arg1 withDisable:(BOOL)arg2; +- (BOOL)deleteAccount:(id)arg1 locally:(BOOL)arg2; +- (BOOL)deleteAccount:(id)arg1; +- (BOOL)addAccount:(id)arg1 locally:(BOOL)arg2; +- (BOOL)addAccount:(id)arg1 atIndex:(int)arg2 locally:(BOOL)arg3; +- (BOOL)addAccount:(id)arg1 atIndex:(int)arg2; +- (BOOL)addAccount:(id)arg1; +- (void)_accountRegistrationStatusChanged:(id)arg1; +- (void)_activeAccountChanged:(id)arg1; +- (void)setReadOnly:(BOOL)arg1; +- (BOOL)readOnly; +- (BOOL)accountActive:(id)arg1; +- (BOOL)canDeleteAccount:(id)arg1; +- (id)connectedAccountsWithCapability:(unsigned long long)arg1; +- (id)operationalAccountsWithCapability:(unsigned long long)arg1; +- (id)accountsWithCapability:(unsigned long long)arg1; +- (id)connectedAccountsForService:(id)arg1; +- (id)operationalAccountsForService:(id)arg1; +- (id)activeAccountsForService:(id)arg1; +- (id)accountsForService:(id)arg1; +@property(readonly, nonatomic) NSArray *operationalAccounts; +@property(readonly, nonatomic) NSArray *connectedAccounts; +@property(readonly, nonatomic) NSArray *activeAccounts; +@property(readonly, nonatomic) int numberOfAccounts; +- (id)accountAtIndex:(int)arg1; +- (id)accountForUniqueID:(id)arg1; +- (void)dealloc; +- (id)init; +- (void)autoLogin; +@property(readonly, nonatomic) IMAccount *activeSMSAccount; +@property(readonly, nonatomic) IMAccount *activeIMessageAccount; +- (id)_bestOperationalAccountForSendingForService:(id)arg1; +- (id)__iCloudSystemAccountForService:(id)arg1; +- (id)_bestAccountForAddresses:(id)arg1; +- (id)_operationalPhoneAccountForService:(id)arg1; + +@end + +@interface IMMessageAcknowledgmentStringHelper : NSObject +{ +} + ++ (id)generateBackwardCompatibilityStringForMessageAcknowledgmentType:(long long)arg1 messageSummaryInfo:(id)arg2; ++ (id)generateBackwardCompatibilityStringForMessageAcknowledgmentType:(long long)arg1 messageSummaryInfo:(id)arg2 isGroupMessage:(BOOL)arg3; ++ (id)generateBackwardCompatibilityFormatStringForMessageAcknowledgmentType:(long long)arg1 messageSummaryInfo:(id)arg2 format:(long long *)arg3; ++ (id)generatePreviewStringForMessageAcknowledgmentType:(long long)arg1 acknowledgmentSenderAddress:(id)arg2 messageSummaryInfo:(id)arg3; ++ (id)generatePreviewStringForMessageAcknowledgmentType:(long long)arg1 acknowledgmentSenderAddress:(id)arg2 messageSummaryInfo:(id)arg3 isGroupMessage:(BOOL)arg4; ++ (id)generateFormatStringForMessageAcknowledgmentType:(long long)arg1 acknowledgmentSenderAddress:(id)arg2 messageSummaryInfo:(id)arg3 format:(long long *)arg4; ++ (id)displayNameForAddress:(id)arg1; ++ (BOOL)isLoginAddress:(id)arg1; ++ (id)handleForAddress:(id)arg1; ++ (id)bestAccountForAddress:(id)arg1; ++ (id)longContentTypeStringForContentType:(id)arg1; ++ (id)longContentTypeStringForPluginBundleID:(id)arg1 pluginDisplayName:(id)arg2; ++ (BOOL)shouldQuoteContentString:(id)arg1; ++ (id)messageAcknowledgmentString:(long long)arg1 lowercase:(BOOL)arg2; + +@end + +@interface IMParentalControlsService : NSObject +{ + BOOL _disableService; + BOOL _forceWhiteList; + NSSet *_whitelist; + NSString *_name; +} + +@property(retain) NSString *name; // @synthesize name=_name; +@property(retain) NSSet *whitelist; // @synthesize whitelist=_whitelist; +@property BOOL forceWhiteList; // @synthesize forceWhiteList=_forceWhiteList; +@property BOOL disableService; // @synthesize disableService=_disableService; + +- (void)dealloc; + +@end + +@interface IMParentalControls : NSObject +{ + BOOL _shouldPostNotifications; + BOOL _active; + BOOL _disableAV; + BOOL _forceChatLogging; + NSMutableDictionary *_parentalControls; +} + ++ (id)standardControls; ++ (id)objectForKey:(id)arg1; +@property(readonly, nonatomic) BOOL _forceChatLogging; // @synthesize _forceChatLogging; +@property(readonly, nonatomic) BOOL _disableAV; // @synthesize _disableAV; +@property(readonly, nonatomic) NSMutableDictionary *_parentalControls; // @synthesize _parentalControls; +@property(readonly, nonatomic) BOOL active; // @synthesize active=_active; +@property(nonatomic) BOOL shouldPostNotifications; // @synthesize shouldPostNotifications=_shouldPostNotifications; + +- (BOOL)accountHasWhitelist:(id)arg1; +- (BOOL)accountIsEnabled:(id)arg1; +- (BOOL)okToConnectAccount:(id)arg1; +- (BOOL)forceWhitelistForAccount:(id)arg1; +- (id)whitelistForAccount:(id)arg1; +- (BOOL)forceWhitelistForService:(id)arg1; +- (id)whitelistForService:(id)arg1; +- (BOOL)disableAccount:(id)arg1; +- (BOOL)disableService:(id)arg1; +@property(readonly, nonatomic) BOOL forceChatLogging; +@property(readonly, nonatomic) BOOL disableAV; +- (void)_managedPrefsNotification:(id)arg1; +- (void)_updateParentalSettings; +- (id)_serviceWithName:(id)arg1; +- (void)dealloc; +- (id)init; + +@end + +@interface IMFileTransferCenter : NSObject +{ + NSMutableDictionary *_guidToTransferMap; + NSMutableDictionary *_guidToRemovedTransferMap; + NSMutableDictionary *_accountIDToTransferGUIDsMap; + NSMutableArray *_preauthorizedInfos; + NSMutableArray *_preauthorizedGUIDs; + NSMutableSet *_activeTransfers; + NSMutableSet *_pendingTransfers; + BOOL _disconnectionListenerSetUp; + NSMutableDictionary *_fetchHighQualityVariantCompletionHandlers; +} + ++ (Class)fileTransferClass; ++ (Class)transferCenterClass; ++ (void)setTransferCenterClass:(Class)arg1; ++ (id)sharedInstance; + +- (void)preWarmConnection; +- (void)_daemonRestarted:(id)arg1; +- (void)_initiateHighQualityVariantDownloadWithDaemonForGUID:(id)arg1; +- (void)_fetchHighQualityVariantForTransferGUID:(id)arg1 completion:(CDUnknownBlockType)arg2; +- (void)fetchHighQualityVariantForTransfer:(id)arg1 completion:(CDUnknownBlockType)arg2; +- (id)guidsForStoredAttachmentPayloadData:(id)arg1 messageGUID:(id)arg2; +- (void)setAuxVideoForTransfer:(id)arg1 value:(BOOL)arg2; +- (void)setAuxImageForTransfer:(id)arg1 value:(BOOL)arg2; +- (void)_handleFileTransferHighQualityDownloadFailed:(id)arg1; +- (void)_handleFileTransfer:(id)arg1 highQualityDownloadSucceededWithPath:(id)arg2; +- (void)_handleFileTransfer:(id)arg1 updatedWithCurrentBytes:(unsigned long long)arg2 totalBytes:(unsigned long long)arg3 averageTransferRate:(unsigned long long)arg4; +- (void)_handleFileTransfer:(id)arg1 updatedWithProperties:(id)arg2; +- (void)_handleFileTransfers:(id)arg1 createdWithLocalPaths:(id)arg2; +- (void)_handleFileTransfer:(id)arg1 createdWithProperties:(id)arg2; +- (void)_handleAllFileTransfers:(id)arg1; +- (void)_handleStandaloneFileTransferRegistered:(id)arg1; +- (void)acceptFileTransferIfPreauthorzed:(id)arg1; +- (BOOL)wasFileTransferPreauthorized:(id)arg1; +- (void)preauthorizeFileTransferFromOtherPerson:(id)arg1 account:(id)arg2 filename:(id)arg3 saveToPath:(id)arg4; +- (BOOL)isFileTransfer:(id)arg1 preauthorizedWithDictionary:(id)arg2; +- (void)clearFinishedTransfers; +@property(readonly, nonatomic) NSArray *orderedTransfersGUIDs; +@property(readonly, nonatomic) __weak NSArray *orderedTransfers; +@property(readonly, nonatomic) NSArray *activeTransferGUIDs; +@property(readonly, nonatomic) __weak NSArray *activeTransfers; +@property(readonly, nonatomic) NSDictionary *transfers; +- (id)transfersForAccount:(id)arg1; +- (void)retargetTransfer:(id)arg1 toPath:(id)arg2; +- (void)deleteTransfer:(id)arg1; +- (void)removeTransfer:(id)arg1; +- (void)stopTransfer:(id)arg1; +- (void)acceptTransfer:(id)arg1; +- (void)acceptTransfer:(id)arg1 withPath:(id)arg2 autoRename:(BOOL)arg3 overwrite:(BOOL)arg4; +- (void)sendTransfer:(id)arg1; +- (id)transferForGUID:(id)arg1 includeRemoved:(BOOL)arg2; +- (id)transferForGUID:(id)arg1; +- (id)chatForTransfer:(id)arg1; +- (void)registerTransferWithDaemon:(id)arg1; +- (void)assignTransfer:(id)arg1 toHandle:(id)arg2; +- (void)assignTransfer:(id)arg1 toMessage:(id)arg2 account:(id)arg3; +- (void)_addSpotlightProperties:(id)arg1 sender:(id)arg2 recipients:(id)arg3 incoming:(BOOL)arg4; +- (BOOL)registerGUID:(id)arg1 forNewOutgoingTransferWithLocalURL:(id)arg2; +- (id)guidForNewOutgoingTransferWithLocalURL:(id)arg1; +- (BOOL)doesLocalURLRequireArchiving:(id)arg1 toHandle:(id)arg2; +- (void)_addTransfer:(id)arg1; +- (void)_addTransfer:(id)arg1 toAccount:(id)arg2; +- (void)_clearTransfers; +- (void)_removeAllActiveTransfers; +- (void)_removeActiveTransfer:(id)arg1; +- (void)_addActiveTransfer:(id)arg1; +@property(readonly, nonatomic) BOOL hasActiveFileTransfers; +- (void)acknowledgeAllPendingTransfers; +- (void)acknowledgePendingTransfer:(id)arg1; +- (void)_removePendingTransfer:(id)arg1; +- (void)_addPendingTransfer:(id)arg1; +@property(readonly, nonatomic) BOOL hasPendingFileTransfers; +- (void)dealloc; + +@end + +@interface IMServiceAgent : NSObject +{ + NSDictionary *_currentAVChatInfo; +} + ++ (id)notificationCenter; ++ (void)forgetStatusImageAppearance; ++ (id)imageNameForStatus:(unsigned long long)arg1; ++ (id)imageURLForStatus:(unsigned long long)arg1; ++ (id)sharedAgent; ++ (long long)serviceAgentCapabilities; ++ (void)setServiceAgentCapabilities:(long long)arg1; + +- (id)myPictureData; +- (void)launchIfNecessary; +@property(readonly, nonatomic) unsigned long long vcCapabilities; +- (unsigned long long)requestVideoStillForPerson:(id)arg1; +@property(readonly, nonatomic) unsigned long long requestAudioReflectorStop; +@property(readonly, nonatomic) unsigned long long requestAudioReflectorStart; +@property(readonly, nonatomic) __weak NSDictionary *currentAVChatInfo; +@property(retain, nonatomic) NSArray *myAwayMessages; +@property(retain, nonatomic) NSArray *myAvailableMessages; +- (void)setMyStatus:(unsigned long long)arg1 message:(id)arg2; +- (id)notificationCenter; +- (id)serviceWithNameNonBlocking:(id)arg1; +- (id)serviceWithName:(id)arg1; + +@end + + + +@interface IMServiceAgentImpl : IMServiceAgent +{ +} + ++ (id)imageURLForStatus:(unsigned long long)arg1; ++ (id)imageNameForStatus:(unsigned long long)arg1; ++ (void)_determineStatusImageAppearance; ++ (void)_statusImageAppearanceChanged:(id)arg1; ++ (void)forgetStatusImageAppearance; ++ (id)notificationCenter; ++ (void)initialize; ++ (id)sharedAgent; +- (unsigned long long)vcCapabilities; +- (void)vcCapabilitiesChanged:(unsigned long long)arg1; +- (void)setupComplete; +- (void)setMyAwayMessages:(id)arg1; +- (void)setMyAvailableMessages:(id)arg1; +- (id)myAwayMessages; +- (id)myAvailableMessages; +- (void)_customMessagesChanged:(id)arg1; +- (void)setMyStatus:(unsigned long long)arg1 message:(id)arg2; +- (void)_statusImageAppearanceChanged:(id)arg1; +- (id)notificationCenter; +- (id)serviceWithName:(id)arg1; +- (void)launchIfNecessary; +- (void)_daemonDisconnected:(id)arg1; +- (void)_daemonConnected:(id)arg1; +- (void)dealloc; +- (id)init; + +@end + + + +@interface IMAppExtensionContext : NSExtensionContext +{ +} + +@end + + +@interface IMHandleRegistrar : NSObject +{ + NSMutableDictionary *_siblingsMap; + NSHashTable *_allIMHandles; + BOOL _addressBookIsEmpty; + // IMBusinessNameManager *_businessNameManager; +} + ++ (id)sharedInstance; + +- (id)businessNameForUID:(id)arg1 updateHandler:(CDUnknownBlockType)arg2; +- (id)_existingChatSiblingsForHandle:(id)arg1; +- (BOOL)_addressBookIsEmpty; +- (id)_chatSiblingsForHandle:(id)arg1; +- (id)_existingAccountSiblingsForHandle:(id)arg1; +- (id)_accountSiblingsForHandle:(id)arg1; +- (void)_dumpOutAllIMHandlesForAccount:(id)arg1; +- (void)_dumpOutAllIMHandles; +- (id)allIMHandles; +- (id)siblingsForIMHandle:(id)arg1; +- (void)clearSiblingCacheForIMHandle:(id)arg1; +- (void)unregisterIMHandle:(id)arg1; +- (void)registerIMHandle:(id)arg1; +- (void)_clearSiblingsCacheForIMHandle:(id)arg1 rebuildAfter:(BOOL)arg2; +- (void)_buildSiblingsForIMHandle:(id)arg1; +- (void)_emptySiblingCacheForIMHandleGUID:(id)arg1; +- (id)init; +- (void)_addressBookChanged:(id)arg1; + +@end + +@interface IMPeople : NSObject +{ + NSMutableArray *_people; + int _coalesceCount; + BOOL _hidePeople; +} + +@property(nonatomic, setter=setShouldHidePeople:) BOOL hidePeople; // @synthesize hidePeople=_hidePeople; + +- (void)imHandle:(id)arg1 buddyStatusChanged:(BOOL)arg2; +- (BOOL)addPeopleFromArray:(id)arg1; +- (BOOL)addPeopleFromArray:(id)arg1 skipMe:(BOOL)arg2; +- (BOOL)removePeopleFromArray:(id)arg1; +- (BOOL)removeIMHandle:(id)arg1; +- (BOOL)addIMHandle:(id)arg1; +@property(readonly, nonatomic) BOOL coalescingChanges; +- (void)endCoalescedChanges; +- (void)beginCoalescedChanges; +- (void)removedIMHandle:(id)arg1; +- (void)_addedPeople:(id)arg1; +- (void)addedIMHandle:(id)arg1; +@property(readonly, nonatomic) NSArray *people; +@property(readonly, nonatomic) NSArray *groups; +- (BOOL)containsIMHandle:(id)arg1; +@property(readonly, nonatomic) unsigned long long count; +- (void)addNotificationObserver:(id)arg1 selector:(SEL)arg2; +- (void)removeNotificationObserver:(id)arg1; +- (void)dealloc; + +@end + +@interface IMPeopleCollection : IMPeople +{ + NSMutableArray *_collectedPeople; +} + +@property(retain, nonatomic) NSMutableArray *_collectedPeople; // @synthesize _collectedPeople; + +- (BOOL)containsPerson:(id)arg1; +- (id)groups; +- (id)people; +- (void)_collectionNotification:(id)arg1; +- (void)removeIMPeople:(id)arg1; +- (void)addIMPeople:(id)arg1; +- (BOOL)collectsIMPeople:(id)arg1; +@property(readonly, nonatomic) NSArray *collectedIMPeople; +- (id)init; + +@end + + +@interface IMCloudKitMockSyncState : NSObject +{ + BOOL _IMCloudKitSyncingEnabled; + BOOL _IMCloudKitIsSyncing; + BOOL _IMCloudKitSyncPaused; + BOOL _IMCloudKitIsEligibleForTruthZone; + BOOL _IMCloudKitIsInExitState; + BOOL _IMCloudKitIsRemovedFromBackup; + BOOL _IMCloudKitStartingPeriodicSync; + BOOL _IMCloudKitStartingInitialSync; + BOOL _IMCloudKitStartingDisableDevices; + NSDate *_IMCloudKitSyncDate; + long long _IMCloudKitStartingEnabledSettingChange; + unsigned long long _IMCloudKitSyncControllerSyncState; + long long _IMCloudKitSyncControllerSyncType; + long long _IMCloudKitSyncControllerSyncRecordType; + NSArray *_IMCloudKitSyncErrors; +} + +@property(retain) NSArray *IMCloudKitSyncErrors; // @synthesize IMCloudKitSyncErrors=_IMCloudKitSyncErrors; +@property long long IMCloudKitSyncControllerSyncRecordType; // @synthesize IMCloudKitSyncControllerSyncRecordType=_IMCloudKitSyncControllerSyncRecordType; +@property long long IMCloudKitSyncControllerSyncType; // @synthesize IMCloudKitSyncControllerSyncType=_IMCloudKitSyncControllerSyncType; +@property unsigned long long IMCloudKitSyncControllerSyncState; // @synthesize IMCloudKitSyncControllerSyncState=_IMCloudKitSyncControllerSyncState; +@property BOOL IMCloudKitStartingDisableDevices; // @synthesize IMCloudKitStartingDisableDevices=_IMCloudKitStartingDisableDevices; +@property long long IMCloudKitStartingEnabledSettingChange; // @synthesize IMCloudKitStartingEnabledSettingChange=_IMCloudKitStartingEnabledSettingChange; +@property BOOL IMCloudKitStartingInitialSync; // @synthesize IMCloudKitStartingInitialSync=_IMCloudKitStartingInitialSync; +@property BOOL IMCloudKitStartingPeriodicSync; // @synthesize IMCloudKitStartingPeriodicSync=_IMCloudKitStartingPeriodicSync; +@property(retain) NSDate *IMCloudKitSyncDate; // @synthesize IMCloudKitSyncDate=_IMCloudKitSyncDate; +@property BOOL IMCloudKitIsRemovedFromBackup; // @synthesize IMCloudKitIsRemovedFromBackup=_IMCloudKitIsRemovedFromBackup; +@property BOOL IMCloudKitIsInExitState; // @synthesize IMCloudKitIsInExitState=_IMCloudKitIsInExitState; +@property BOOL IMCloudKitIsEligibleForTruthZone; // @synthesize IMCloudKitIsEligibleForTruthZone=_IMCloudKitIsEligibleForTruthZone; +@property BOOL IMCloudKitSyncPaused; // @synthesize IMCloudKitSyncPaused=_IMCloudKitSyncPaused; +@property BOOL IMCloudKitIsSyncing; // @synthesize IMCloudKitIsSyncing=_IMCloudKitIsSyncing; +@property BOOL IMCloudKitSyncingEnabled; // @synthesize IMCloudKitSyncingEnabled=_IMCloudKitSyncingEnabled; + +- (id)convertToDictionary; + +@end + +@interface IMMe : NSObject +{ + IMPerson *_person; + NSString *_abNickname; + NSString *_abFirstName; + NSString *_abFullName; + NSString *_abLastName; + NSArray *_abEmails; + NSMutableArray *_abIMHandles; + NSMutableArray *_loginIMHandles; +} + ++ (id)imHandleForService:(id)arg1; ++ (id)me; ++ (id)fallbackUserName; + +- (id)description; +- (void)myPictureChanged; +@property(readonly, nonatomic) NSArray *imHandles; +@property(readonly, nonatomic) IMHandle *bestIMHandle; +@property(readonly, nonatomic) NSString *fullName; +@property(readonly, nonatomic) NSString *lastName; +@property(readonly, nonatomic) NSString *email; +@property(readonly, nonatomic) NSArray *emails; +@property(readonly, nonatomic) NSString *firstName; +@property(readonly, nonatomic) NSString *nickname; +- (void)setFirstName:(id)arg1 lastName:(id)arg2; +- (BOOL)removeIMHandle:(id)arg1; +- (BOOL)isIMHandleLoginIMHandle:(id)arg1; +- (BOOL)addIMHandle:(id)arg1; +- (id)loginIMHandles; +- (BOOL)removeLoginIMHandle:(id)arg1; +- (BOOL)addLoginIMHandle:(id)arg1; +@property(readonly, nonatomic) IMPerson *person; +- (void)setIMPerson:(id)arg1; +- (void)resetABPerson; +- (void)rebuildIMHandles; +- (id)_imHandlesWithIDs:(id)arg1 onAccount:(id)arg2; +@property(readonly, nonatomic) NSString *guid; +- (id)init; + +@end + +@interface IMSendProgress : NSObject +{ + id _delegate; + id _context; + NSTimer *_sendProgressTimer; + NSDictionary *_sendingItems; + float _cachedSendProgress; + BOOL _wasShowing; + BOOL _startSendProgressImmediately; + id _timeDataSource; +} + ++ (Class)_timeDataSourceClass; +@property(retain, nonatomic) id timeDataSource; // @synthesize timeDataSource=_timeDataSource; +@property(nonatomic) BOOL startSendProgressImmediately; // @synthesize startSendProgressImmediately=_startSendProgressImmediately; +@property(copy, nonatomic) NSDictionary *sendingItems; // @synthesize sendingItems=_sendingItems; +@property(nonatomic) __weak id context; // @synthesize context=_context; +@property(nonatomic) __weak id delegate; // @synthesize delegate=_delegate; + +- (void)_sendProgressTimerFired:(id)arg1; +- (void)_scheduleSendProgressTimerIfNeeded; +- (void)_updateSendProgress; +- (void)_resetSendProgress; +- (BOOL)_hasSendingMessages; +- (void)invalidate; +- (void)updateForItems:(id)arg1 forced:(BOOL)arg2; +- (id)initWithDelegate:(id)arg1 context:(id)arg2; +- (id)description; +- (void)dealloc; + +@end + +@interface IMSendProgressRealTimeDataSource : NSObject +{ +} + +@property(readonly) double timeIntervalSinceReferenceDate; + +@end + +@interface IMSimulatedDaemonController : IMDaemonController +{ + NSArray *_listeners; +} + ++ (id)dictionaryForChat:(id)arg1; ++ (void)beginSimulatingDaemon; ++ (id)sharedInstance; +@property(retain, nonatomic) NSArray *listeners; // @synthesize listeners=_listeners; + +- (unsigned int)capabilitiesForListenerID:(id)arg1; +- (BOOL)isConnected; +- (BOOL)connectToDaemonWithLaunch:(BOOL)arg1; +- (BOOL)connectToDaemonWithLaunch:(BOOL)arg1 capabilities:(unsigned int)arg2 blockUntilConnected:(BOOL)arg3; +- (void)sendBalloonPayload:(id)arg1 attachments:(id)arg2 withMessageGUID:(id)arg3 bundleID:(id)arg4; + +@end + +/* +@interface IMLocationManager : NSObject +{ + CLLocationManager *_locationManager; + NSMutableArray *_handlers; + NSTimer *_timeoutHandler; + CLLocation *_location; + NSError *_error; + NSDate *_locateStartTime; + NSTimer *_locationUpdateTimer; +} + ++ (Class)__CLLocationManagerClass; ++ (id)sharedInstance; +@property(retain, nonatomic) CLLocation *location; // @synthesize location=_location; +@property(retain, nonatomic) NSTimer *locationUpdateTimer; // @synthesize locationUpdateTimer=_locationUpdateTimer; +@property(retain, nonatomic) NSDate *locateStartTime; // @synthesize locateStartTime=_locateStartTime; +@property(retain, nonatomic) NSError *error; // @synthesize error=_error; +@property(retain, nonatomic) CLLocationManager *locationManager; // @synthesize locationManager=_locationManager; +@property(retain, nonatomic) NSMutableArray *handlers; // @synthesize handlers=_handlers; + +- (void)_fireCompletionHandlers; +- (void)_locationManagerTimedOut; +- (void)_locationUpdateTimerFired:(id)arg1; +- (BOOL)_shouldSendLocation:(id)arg1 timeIntervalSinceStart:(double)arg2; +- (void)locationManager:(id)arg1 didFailWithError:(id)arg2; +- (void)locationManager:(id)arg1 didUpdateLocations:(id)arg2; +@property(readonly, nonatomic) BOOL locationAuthorizationDenied; +- (void)startUpdatingCurrentLocationWithHandler:(CDUnknownBlockType)arg1; +- (id)init; +- (void)dealloc; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly) unsigned long long hash; +@property(readonly) Class superclass; + +@end + + */ + +@interface IMAutomationBatchMessageOperations : NSObject +{ +} + +- (id)stopRecordingDatabaseError:(id *)arg1; +- (id)beginRecordingMessagesToReplayDatabase:(id)arg1 error:(id *)arg2; +- (id)sendMessagesfromReplayDatabase:(id)arg1 userInfo:(id)arg2 error:(id *)arg3; + +@end + +@interface IMAttachment : NSObject +{ + NSString *_guid; + NSString *_path; + BOOL _isSticker; + BOOL _isTransferComplete; + NSDate *_createdDate; +} + + +- (id)fileTransfer; +- (BOOL)isTransferComplete; +- (BOOL)isSticker; +- (id)createdDate; +- (id)path; +- (id)guid; +- (id)description; +- (id)initWithPath:(id)arg1 guid:(id)arg2 createdDate:(id)arg3 isSticker:(BOOL)arg4 isTransferComplete:(BOOL)arg5; +- (id)initWithPath:(id)arg1 guid:(id)arg2; + +@end + +@interface IMPerson : NSObject +{ + BOOL _registered; +// ABPerson *_abPerson; +// ABAddressBook *_customBook; + NSString *_uniqueID; + NSString *_cachedFirstName; + NSString *_cachedLastName; + NSString *_cachedFullName; + NSString *_cachedCompanyName; + NSString *_cachedNickName; +// CNContact *_cnContact; +} + ++ (void)_setCachedQueriesEnabled:(BOOL)arg1; ++ (id)_initialABPropertyLabelForProperty:(id)arg1; ++ (id)personWithABPerson:(id)arg1; ++ (BOOL)shouldPurgeCacheForIMPerson:(id)arg1; ++ (id)existingABPeopleWithInstantMessageAddress:(id)arg1 onServices:(id)arg2 allowSubstringMatch:(BOOL)arg3; ++ (id)existingABPersonWithInstantMessageAddress:(id)arg1 onServices:(id)arg2 allowSubstringMatch:(BOOL)arg3; ++ (id)existingABPersonWithFirstName:(id)arg1 andLastName:(id)arg2 andNickName:(id)arg3 orEmail:(id)arg4 orNumber:(id)arg5; ++ (id)existingABPersonWithFirstName:(id)arg1 andLastName:(id)arg2 andNickName:(id)arg3 orEmail:(id)arg4 orNumber:(id)arg5 countryCode:(id)arg6 identifier:(int *)arg7; ++ (id)existingABPersonWithFirstName:(id)arg1 andLastName:(id)arg2 andNickName:(id)arg3 orEmail:(id)arg4 orNumber:(id)arg5 identifier:(int *)arg6; ++ (id)existingABPersonWithFirstName:(id)arg1 andLastName:(id)arg2 orEmail:(id)arg3 orNumber:(id)arg4; ++ (id)existingABPersonForPerson:(id)arg1; ++ (id)existingABPersonWithFirstName:(id)arg1 andLastName:(id)arg2 orEmail:(id)arg3; ++ (id)existingABPersonWithFirstName:(id)arg1 lastName:(id)arg2; ++ (id)allPeople; +//@property(retain, nonatomic) CNContact *cnContact; // @synthesize cnContact=_cnContact; +@property(readonly, nonatomic) BOOL _registered; // @synthesize _registered; +@property(retain, nonatomic) NSString *cachedNickName; // @synthesize cachedNickName=_cachedNickName; +@property(retain, nonatomic) NSString *cachedCompanyName; // @synthesize cachedCompanyName=_cachedCompanyName; +@property(retain, nonatomic) NSString *cachedFullName; // @synthesize cachedFullName=_cachedFullName; +@property(retain, nonatomic) NSString *cachedLastName; // @synthesize cachedLastName=_cachedLastName; +@property(retain, nonatomic) NSString *cachedFirstName; // @synthesize cachedFirstName=_cachedFirstName; +@property(retain, nonatomic, setter=_setUniqueID:) NSString *uniqueID; // @synthesize uniqueID=_uniqueID; +//@property(retain, nonatomic, setter=_setCustomBook:) ABAddressBook *_customBook; // @synthesize _customBook; +//@property(readonly, nonatomic) ABPerson *_abPerson; // @synthesize _abPerson; + +- (unsigned long long)hash; +@property(readonly, nonatomic) unsigned long long status; +@property(readonly, nonatomic) NSData *imageDataWithoutLoading; +@property(retain, nonatomic) NSData *imageData; +- (void)_abPersonChanged:(id)arg1; +@property(readonly, nonatomic) NSArray *groups; +- (id)description; +- (BOOL)isEqual:(id)arg1; +- (BOOL)isEqualToIMPerson:(id)arg1; +- (BOOL)containsHandle:(id)arg1 forServiceProperty:(id)arg2; +- (void)appendID:(id)arg1 toProperty:(id)arg2; +- (void)save; +@property(readonly, nonatomic) NSArray *mobileNumbers; +@property(retain, nonatomic) NSArray *phoneNumbers; +- (id)allHandlesForProperty:(id)arg1; +- (void)setValues:(id)arg1 forProperty:(id)arg2; +- (void)setValues:(id)arg1 forIMProperty:(id)arg2; +- (id)valuesForProperty:(id)arg1; +- (id)_valuesAndLabelsForProperty:(id)arg1; +- (id)valuesForIMProperty:(id)arg1; +@property(readonly, nonatomic) BOOL isInAddressBook; +@property(copy, nonatomic) NSArray *emails; +@property(readonly, nonatomic) NSArray *allEmails; +- (id)emailHandlesForService:(id)arg1; +- (id)emailHandlesForService:(id)arg1 includeBaseEmail:(BOOL)arg2; +- (void)setFirstName:(id)arg1 lastName:(id)arg2; +@property(copy, nonatomic) NSString *lastName; +@property(copy, nonatomic) NSString *firstName; +@property(readonly, nonatomic) NSString *fullName; +@property(copy, nonatomic) NSString *nickname; +@property(readonly, nonatomic) NSString *name; +@property(readonly, nonatomic) NSString *displayName; +@property(readonly, nonatomic) NSString *abbreviatedName; +@property(readonly, nonatomic) NSString *companyName; +@property(readonly, nonatomic) BOOL isCompany; +- (void)dealloc; +@property(readonly, copy, nonatomic) NSString *cnContactID; +//@property(readonly, nonatomic) ABPerson *abPerson; +- (id)initWithABPerson:(id)arg1; +- (id)init; +- (id)idsAddresses; + +@end + +@interface IMSimulatedAccount : IMAccount +{ + IMHandle *_loginHandle; +} + +@property(retain, nonatomic) IMHandle *loginHandle; // @synthesize loginHandle=_loginHandle; + +- (BOOL)isConnected; +- (BOOL)isOperational; +- (BOOL)supportsRegistration; +- (id)loginIMHandle; + +@end + +@class IMChatRegistry; +@interface IMChat : IMItemsController +{ + NSString *_guid; + NSString *_typingGUID; + NSString *_localUserIsComposing; + NSString *_currentLocationGUID; + NSString *_identifier; + IMAccount *_account; + NSString *_displayName; + NSString *_roomName; + NSString *_roomNameWithoutSuffix; + NSString *_lastAddressedHandleID; + NSString *_lastAddressedSIMID; + NSString *_groupID; + NSData *_engramID; + NSArray *_participants; + NSMutableDictionary *_participantStates; + IMMessage *_invitationForPendingParticipants; + NSMutableArray *_messagesPendingJoin; + NSMutableSet *_guids; + NSMutableDictionary *_chatProperties; + NSMutableDictionary *_participantProperties; + NSArray *_frequentReplies; + NSArray *_attachments; + NSNumber *_countOfAttachmentsNotCachedLocally; + NSNumber *_countOfMessagesMarkedAsSpam; +// IMTimingCollection *_timingCollection; + NSDate *_dateCreated; + NSDate *_dateModified; + unsigned long long _overallChatStatus; + double _joinedTimeInterval; +// id _chatItemRules; +// IMScheduledUpdater *_chatItemsUpdater; + IMSendProgress *_sendProgress; + BOOL _downgradeState; +// IMScheduledUpdater *_downgradeStateUpdater; + long long _joinState; + unsigned char _style; + unsigned long long _dbFailedCount; + unsigned long long _dbUnreadCount; + void *_context; + unsigned int _hasBeenConfigured:1; + unsigned int _isFirstMessageInvitation:1; + unsigned int _wasInvitationHandled:1; + unsigned int _didSendAFinishedMessage:1; + unsigned int _hasPendingMarkRead:1; + unsigned int _isUpdatingChatItems:1; + unsigned int _ignoreDowngradeStatusUpdates:1; + unsigned int _isFiltered:1; + unsigned int _forceMMS:1; + BOOL _hasRefreshedServiceForSending; + BOOL _hasHadSuccessfulQuery; + long long _lastMessageTimeStampOnLoad; + unsigned int _shouldAnnouncePeopleJoin:1; + NSString *_currentUnreadHistoryQuery; + BOOL _hasEarlierMessagesToLoad; + BOOL _hasMoreRecentMessagesToLoad; + BOOL _isCurrentlyDownloadingPurgedAssets; + BOOL _hasSurfRequest; + NSString *_personCentricID; + NSDictionary *_bizIntent; + double _latestTypingIndicatorTimeInterval; +// TUConversation *_conversation; +} + ++ (Class)chatItemRulesClass; ++ (void)setChatItemRulesClass:(Class)arg1; ++ (void)_initializeFMF; ++ (void)moveVIPChatAtIndex:(long long)arg1 toIndex:(long long)arg2; ++ (void)updateVIPChatIdentifiers:(CDUnknownBlockType)arg1; ++ (CDUnknownBlockType)watermarkComparator; ++ (void)cleanWatermarkCache; ++ (void)removeGUIDInAttemptingListInScrutinyMode:(id)arg1; ++ (BOOL)isGUIDInAttemptingListInScrutinyMode:(id)arg1; ++ (void)storeGUIDInAttemptingListInScrutinyMode:(id)arg1; ++ (void)_removeGUID:(id)arg1 fromList:(id)arg2; ++ (void)_storeGUID:(id)arg1 forKey:(id)arg2; ++ (id)_GUIDsForKey:(id)arg1; ++ (id)__im_adjustMessageSummaryInfoForSending:(id)arg1; +//@property(readonly, nonatomic) TUConversation *conversation; // @synthesize conversation=_conversation; +@property(retain, nonatomic) NSString *lastAddressedSIMID; // @synthesize lastAddressedSIMID=_lastAddressedSIMID; +@property(nonatomic) double latestTypingIndicatorTimeInterval; // @synthesize latestTypingIndicatorTimeInterval=_latestTypingIndicatorTimeInterval; +@property(copy, nonatomic) NSDictionary *bizIntent; // @synthesize bizIntent=_bizIntent; +@property(readonly, nonatomic) long long lastMessageTimeStampOnLoad; // @synthesize lastMessageTimeStampOnLoad=_lastMessageTimeStampOnLoad; +@property(nonatomic) BOOL hasSurfRequest; // @synthesize hasSurfRequest=_hasSurfRequest; +@property(readonly, nonatomic) NSData *engramID; // @synthesize engramID=_engramID; +@property(retain, nonatomic) NSString *personCentricID; // @synthesize personCentricID=_personCentricID; +@property(retain, nonatomic) IMMessage *invitationForPendingParticipants; // @synthesize invitationForPendingParticipants=_invitationForPendingParticipants; +@property(readonly, nonatomic) long long joinState; // @synthesize joinState=_joinState; +@property(readonly, nonatomic) NSDate *dateModified; // @synthesize dateModified=_dateModified; +@property(readonly, nonatomic) NSDate *dateCreated; // @synthesize dateCreated=_dateCreated; +@property(retain, nonatomic) NSString *displayName; // @synthesize displayName=_displayName; +@property(readonly, nonatomic) NSString *roomName; // @synthesize roomName=_roomName; +@property(nonatomic) void *contextInfo; // @synthesize contextInfo=_context; +@property(readonly, nonatomic) unsigned char chatStyle; // @synthesize chatStyle=_style; +@property(readonly, nonatomic) NSArray *participants; // @synthesize participants=_participants; +@property(readonly, nonatomic) IMAccount *account; // @synthesize account=_account; +@property(readonly, nonatomic) NSString *guid; // @synthesize guid=_guid; +@property(retain, nonatomic, setter=_setGUIDs:) NSMutableSet *_guids; // @synthesize _guids; +@property(retain, nonatomic) NSString *groupID; // @synthesize groupID=_groupID; +@property(retain, nonatomic) NSString *lastAddressedHandleID; // @synthesize lastAddressedHandleID=_lastAddressedHandleID; +@property(retain, nonatomic) NSArray *frequentReplies; // @synthesize frequentReplies=_frequentReplies; + +- (void)downloadPurgedAttachments; +- (void)sendProgress:(id)arg1 progressDidChange:(float)arg2 sendingMessages:(id)arg3 sendCount:(unsigned long long)arg4 totalCount:(unsigned long long)arg5 finished:(BOOL)arg6; +- (id)sendProgressDelegate; +- (void)setSendProgressDelegate:(id)arg1; +- (id)_initWithDictionaryRepresentation:(id)arg1 items:(id)arg2 participantsHint:(id)arg3 accountHint:(id)arg4; +- (BOOL)hasStoredMessageWithGUID:(id)arg1; +@property(readonly, copy) NSString *description; +- (void)_daemonDied:(id)arg1; +- (void)_daemonAlive:(id)arg1; +- (void)_accountControllerUpdated:(id)arg1; +- (BOOL)_sanityCheckAccounts; +- (void)_handleAddressBookChangeForRecipientUID:(id)arg1; +- (void)addPendingParticipants:(id)arg1; +- (void)_removeParticipantsFromChat:(id)arg1 reason:(id)arg2 fromiMessageChat:(BOOL)arg3; +- (void)removeParticipantsFromiMessageChat:(id)arg1 reason:(id)arg2; +- (void)removeParticipants:(id)arg1 reason:(id)arg2; +- (void)_inviteParticipantsToChat:(id)arg1 reason:(id)arg2 toiMessageChat:(BOOL)arg3; +- (void)inviteParticipantsToiMessageChat:(id)arg1 reason:(id)arg2; +- (void)inviteParticipants:(id)arg1 reason:(id)arg2; +- (void)_invitePendingParticipants; +- (void)_inviteParticipants:(id)arg1 reason:(id)arg2 toiMessageChat:(BOOL)arg3; +- (id)_pendingParticipants; +- (BOOL)canAddParticipants:(id)arg1; +- (BOOL)canAddParticipant:(id)arg1; +@property(readonly, nonatomic) BOOL canLeaveChat; +- (void)_addParticipants:(id)arg1 withState:(unsigned long long)arg2; +- (void)archive; +- (void)remove; +- (void)_leaveChat:(BOOL)arg1; +- (void)leave; +- (void)leaveiMessageGroup; +- (void)join; +@property(retain, nonatomic) IMHandle *recipient; +- (void)setRecipient:(id)arg1 locally:(BOOL)arg2; +- (void)_setAccount:(id)arg1 locally:(BOOL)arg2; +- (void)_setAccount:(id)arg1; +- (BOOL)_hasCommunicatedOnService:(id)arg1; +- (void)setValue:(id)arg1 forProperty:(id)arg2 ofParticipant:(id)arg3; +- (id)valueForProperty:(id)arg1 ofParticipant:(id)arg2; +- (id)allPropertiesOfParticipant:(id)arg1; +- (void)userToggledReadReceiptSwitch:(BOOL)arg1; +- (void)setValue:(id)arg1 forChatProperty:(id)arg2; +- (id)valueForChatProperty:(id)arg1; +- (id)allChatProperties; +- (void)_setChatProperties:(id)arg1; +- (BOOL)_isDuplicate:(id)arg1; +- (void)markAllMessagesAsRead; +- (void)markMessagesAsRead:(id)arg1; +- (void)markMessageAsRead:(id)arg1; +- (void)_setTimerForReadMessageCache; +- (void)__clearReadMessageCache; +- (void)updateMessage:(id)arg1 flags:(unsigned long long)arg2; +- (void)updateMessage:(id)arg1; +- (BOOL)authorizedToSendCurrentLocationMessage; +- (BOOL)canSendCurrentLocationMessage; +- (BOOL)canSendTransfer:(id)arg1; +- (BOOL)canSendMessage:(id)arg1; +@property(nonatomic) BOOL localUserIsRecording; +@property(nonatomic) BOOL localUserIsTyping; +@property(retain, nonatomic) NSString *localUserIsComposing; +- (void)setLocalUserIsComposing:(id)arg1 typingIndicatorData:(id)arg2; +- (void)_setLocalUserIsComposing:(id)arg1 suppliedGUID:(id)arg2 typingIndicatorData:(id)arg3; +- (void)_setLocalUserIsComposing:(id)arg1 suppliedGUID:(id)arg2; +- (BOOL)_shouldSendCancelTypingIndicator; +@property(readonly, nonatomic) NSString *localTypingMessageGUID; +- (void)_sendCurrentLocationMessageUsingLocationManager:(id)arg1; +- (void)sendCurrentLocationMessage; +- (void)sendMessage:(id)arg1; +- (void)_fixItemForSendingMessageTime:(id)arg1; +- (void)_sendMessage:(id)arg1 adjustingSender:(BOOL)arg2 shouldQueue:(BOOL)arg3; +- (void)cancelMessage:(id)arg1; +- (void)declineInvitation; +- (void)acceptInvitation; +@property(readonly, nonatomic) BOOL hasUnhandledInvitation; +@property(readonly, nonatomic) NSString *roomNameWithoutSuffix; +@property(readonly, nonatomic) NSString *deviceIndependentID; +@property(readonly, nonatomic) NSString *persistentID; +- (void)_updateLastAddressedSIMID:(id)arg1; +- (void)_updateLastAddressedHandleID:(id)arg1; +- (void)_updateEngramID:(id)arg1; +- (void)_updateDisplayName:(id)arg1; +- (void)_setDisplayName:(id)arg1; +- (void)setRoomName:(id)arg1; +@property(readonly, nonatomic, getter=isGroupChat) BOOL groupChat; +@property(readonly, nonatomic) unsigned long long overallChatStatus; +@property(readonly, nonatomic) BOOL canHaveMultipleParticipants; +@property(readonly, nonatomic) NSString *chatIdentifier; +- (void)_clearCachedIdentifier; +- (unsigned long long)stateForParticipant:(id)arg1; +- (id)participantsWithState:(unsigned long long)arg1; +- (void)_engroupParticipantsUpdated; +- (void)_handleAttributionChanged; +- (void)beginListeningToAttributionChanges; +- (void)endListeningToAttributionChanges; +- (id)_performQueryWithKey:(id)arg1 loadImmediately:(BOOL)arg2 block:(CDUnknownBlockType)arg3; +- (id)_performQueryWithKey:(id)arg1 loadImmediately:(BOOL)arg2 block:(CDUnknownBlockType)arg3 completion:(CDUnknownBlockType)arg4; +- (void)_showErrorMessage:(id)arg1; +- (void)_participant:(id)arg1 statusChanged:(int)arg2; +- (void)_setJoinState:(long long)arg1 quietly:(BOOL)arg2; +- (void)_setJoinState:(long long)arg1; +- (BOOL)_handleIncomingItem:(id)arg1; +- (void)_fixSendingItemDateAndSortID:(id)arg1; +- (BOOL)hasSurfRequestNotFromMe:(id)arg1; +- (BOOL)hasSurfRequestForPaymentType:(unsigned long long)arg1; +- (unsigned long long)paymentTypeForMessage:(id)arg1; +- (void)_resetChatIdToLastMessageItemMap; +- (void)_handleMessageGUIDDeletions:(id)arg1; +- (void)_setParticipantState:(unsigned long long)arg1 forHandles:(id)arg2 quietly:(BOOL)arg3; +- (void)_setParticipantState:(unsigned long long)arg1 forHandle:(id)arg2 quietly:(BOOL)arg3; +- (void)_postIMChatItemsDidChangeNotificationWithInserted:(id)arg1 removed:(id)arg2 reload:(id)arg3 regenerate:(id)arg4 oldChatItems:(id)arg5 shouldLog:(BOOL)arg6; +- (void)_postNotification:(id)arg1 userInfo:(id)arg2 shouldLog:(BOOL)arg3; +- (void)_postNotification:(id)arg1 userInfo:(id)arg2; +- (void)_endTiming; +- (void)_startTiming:(id)arg1; +- (id)_timingCollection; +- (void)_accountLoggedOut:(id)arg1; +- (void)_unwatchHandleStatusChangedForHandle:(id)arg1; +- (void)_watchHandleStatusChangedForHandle:(id)arg1; +- (void)_handleHandleStatusChanged:(id)arg1; +- (void)_recomputeOverallChatStatusQuietly:(BOOL)arg1; +- (void)didUnregisterFromRegistry:(id)arg1; +- (void)clear; +@property(nonatomic) BOOL hasHadSuccessfulQuery; +- (long long)numberOfTimesRespondedToThread; +- (BOOL)containsMessageFromContactOrMe; +- (void)verifyChatShouldBeSMSSpam; +- (void)updateWasDetectedAsSMSSpam:(BOOL)arg1; +- (void)updateShouldForceToSMS:(BOOL)arg1; +- (BOOL)shouldForceToSMS; +- (BOOL)isSMS; +- (BOOL)hasKnownParticipants; +- (void)updateIsFiltered:(BOOL)arg1; +@property(nonatomic) BOOL isFiltered; // @dynamic isFiltered; +- (void)autoReportSpam; +- (void)markAsAutoSpamReported; +- (unsigned long long)markAsSpam; +- (BOOL)deleteAllHistory; +@property(readonly, nonatomic) unsigned long long messageFailureCount; +@property(readonly, nonatomic) unsigned long long unreadMessageCount; +@property(readonly, nonatomic) unsigned long long messageCount; +@property(readonly, nonatomic) long long lastFinishedMessageID; +@property(readonly, nonatomic) NSDate *lastSentMessageDate; +@property(readonly, nonatomic) IMMessage *lastSentMessage; +@property(readonly, nonatomic) NSDate *lastTUConversationCreatedDate; +@property(readonly, nonatomic) NSDate *lastFinishedMessageDate; +@property(readonly, nonatomic) BOOL lastMessageExists; +@property(readonly, nonatomic) IMMessage *lastMessage; +- (id)lastRelatedIncomingFinishedMessageTextContentWithLimit:(long long)arg1; +@property(readonly, nonatomic) IMMessage *lastIncomingFinishedMessageWithTextContent; +@property(readonly, nonatomic) IMMessage *lastIncomingFinishedMessage; +@property(readonly, nonatomic) IMMessage *lastIncomingMessage; +@property(readonly, nonatomic) IMMessageItem *lastFinishedMessageItem; +@property(readonly, nonatomic) IMMessage *lastFinishedMessage; +@property(readonly, nonatomic) IMMessage *firstMessage; +- (id)messageForGUID:(id)arg1; +- (id)_lastFinishedMessage; +- (id)_appendArchivedItemsToItemsArray:(id)arg1; +- (id)_archivedItemsToReplace:(id)arg1 numberOfMessagesBeforeGUID:(unsigned long long)arg2 numberOfMessagesAfterGUID:(unsigned long long)arg3; +- (void)_insertHistoricalMessages:(id)arg1 queryID:(id)arg2 isRefresh:(BOOL)arg3 isHistoryQuery:(BOOL)arg4 limit:(unsigned long long)arg5 numberOfMessagesBeforeGUID:(unsigned long long)arg6 numberOfMessagesAfterGUID:(unsigned long long)arg7; +- (void)_insertHistoricalMessages:(id)arg1 queryID:(id)arg2 isRefresh:(BOOL)arg3 isHistoryQuery:(BOOL)arg4 limit:(unsigned long long)arg5; +- (void)_insertHistoricalMessages:(id)arg1 queryID:(id)arg2 isRefresh:(BOOL)arg3 isHistoryQuery:(BOOL)arg4; +- (BOOL)_shouldAnnouncePeopleJoin; +- (void)_setDBFailedCount:(unsigned long long)arg1; +- (void)_setDBUnreadCount:(unsigned long long)arg1 postNotification:(BOOL)arg2; +- (void)_setDBUnreadCount:(unsigned long long)arg1; +- (void)_clearUnreadCount; +@property(readonly, nonatomic) BOOL _shouldRegisterChat; +- (void)_itemsDidChange:(id)arg1; +- (id)_initWithItems:(id)arg1; +- (void)dealloc; +- (id)init; +- (void)_initialize; +- (id)_initWithGUID:(id)arg1 account:(id)arg2 style:(unsigned char)arg3 roomName:(id)arg4 displayName:(id)arg5 lastAddressedHandle:(id)arg6 lastAddressedSIMID:(id)arg7 items:(id)arg8 participants:(id)arg9 isFiltered:(BOOL)arg10 hasHadSuccessfulQuery:(BOOL)arg11; +- (void)_setupObservation; +@property(readonly) NSArray *alternativeSpeakableMatches; +@property(readonly) NSString *vocabularyIdentifier; +@property(readonly) NSString *pronunciationHint; +@property(readonly) NSString *spokenPhrase; +- (long long)_compareChat:(id)arg1 withDate:(id)arg2 withDate:(id)arg3; +- (id)_tuDateForChat:(id)arg1; +- (long long)compareChatByTUDateAndLastFinishedMessageDate:(id)arg1; +- (long long)compareChatByDate:(id)arg1; +- (BOOL)_hasJustSentAMessage; +- (void)verifyFiltering; +- (void)saveWatermark; +- (void)updateWatermarks; +@property(getter=isVIP) BOOL VIP; +@property(readonly, copy) NSDate *watermarkDate; +@property(readonly) long long watermarkMessageID; +- (id)_storedWatermarkMessageID; +- (id)_privateInitWithAccount:(id)arg1 style:(unsigned char)arg2 roomName:(id)arg3 messages:(id)arg4 participants:(id)arg5 isFiltered:(BOOL)arg6 hasHadSuccessfulQuery:(BOOL)arg7; +- (void)deleteTransfers:(id)arg1; +@property(readonly, copy, nonatomic) NSArray *attachments; +@property(readonly, nonatomic) BOOL isCurrentlyDownloadingPurgedAttachments; +@property(readonly, copy, nonatomic) NSNumber *countOfAttachmentsNotCachedLocally; +- (void)loadAttachments:(CDUnknownBlockType)arg1; +- (void)_setIsDownloadingPurgedAssets:(BOOL)arg1; +- (void)_setCountOfAttachmentsNotCachedLocally:(id)arg1; +- (void)_setCountOfMessagesMarkedAsSpam:(id)arg1; +- (void)_setAttachments:(id)arg1; +- (id)loadUnreadMessagesWithLimit:(unsigned long long)arg1 fallbackToMessagesUpToGUID:(id)arg2; +- (id)loadFrequentRepliesLimit:(unsigned long long)arg1 loadImmediately:(BOOL)arg2; +- (id)loadMessagesBeforeAndAfterGUID:(id)arg1 numberOfMessagesToLoadBeforeGUID:(unsigned long long)arg2 numberOfMessagesToLoadAfterGUID:(unsigned long long)arg3 loadImmediately:(BOOL)arg4; +- (id)loadMessagesUpToGUID:(id)arg1 date:(id)arg2 limit:(unsigned long long)arg3 loadImmediately:(BOOL)arg4; +- (id)loadMessagesBeforeDate:(id)arg1 limit:(unsigned long long)arg2 loadImmediately:(BOOL)arg3; +- (id)loadMessagesBeforeDate:(id)arg1 limit:(unsigned long long)arg2; +- (id)loadMessagesUpToGUID:(id)arg1 limit:(unsigned long long)arg2; +@property(readonly, nonatomic) BOOL hasMoreRecentMessagesToLoad; +@property(readonly, nonatomic) BOOL hasMoreMessagesToLoad; +@property(nonatomic) unsigned long long numberOfMessagesToKeepLoaded; +- (id)messagesToReportAsSpamFromChatItems:(id)arg1; +- (id)allMessagesToReportAsSpam; +- (id)chatItemsForItems:(id)arg1; +- (id)chatItemsForMessages:(id)arg1; +- (void)clearScrutinyMode; +- (void)watermarkOutForScrutinyMode; +- (BOOL)isInScrutinyMode; +- (BOOL)_serverBagPreventsScrutinyMode; +- (unsigned long long)scrutinyModeAttemptCount; +- (void)watermarkInForScrutinyMode; +- (void)_setRenderingDataDictionary:(id)arg1; +- (id)_renderingDataDictionary; +- (void)markChatItemAsPlayedExpressiveSend:(id)arg1; +- (void)_markItemAsPlayed:(id)arg1; +- (void)markChatItemAsPlayed:(id)arg1; +- (void)markChatItemAsSaved:(id)arg1; +- (void)deleteChatItems:(id)arg1; +- (id)_getMessageChatItemMap:(id)arg1 withDeleteMap:(id)arg2 andAllChatItems:(id)arg3; +- (id)_getDeleteChatItemMap:(id)arg1; +- (void)_replaceStaleChatItems; +- (void)_updateChatItemsWithReason:(id)arg1 block:(CDUnknownBlockType)arg2 shouldPost:(BOOL)arg3; +- (void)_updateChatItemsWithReason:(id)arg1 block:(CDUnknownBlockType)arg2; +- (void)_updateChatItems; +- (void)updateChatItemsIfNeeded; +- (void)endHoldingUpdatesForAllKeys; +- (BOOL)isHoldingUpdatesForKey:(id)arg1; +- (void)endHoldingUpdatesForKey:(id)arg1; +- (void)beginHoldingUpdatesForKey:(id)arg1; +- (id)chatItems; +- (void)_updateLocationShareItemsForSender:(id)arg1; +- (void)_configureLocationShareItem:(id)arg1; +- (void)stopTrackingParticipantLocations; +- (void)startTrackingParticipantLocations; +- (void)stopSharingLocation; +- (void)shareLocationUntilDate:(id)arg1; +@property(readonly, nonatomic) BOOL allRecipientsSharingLocation; +@property(readonly, nonatomic) BOOL hasSiblingRecipientsSharingLocation; +@property(readonly, nonatomic) BOOL hasRecipientsSharingLocation; +@property(readonly, nonatomic) BOOL allRecipientsFollowingLocation; +@property(readonly, nonatomic) BOOL hasRecipientsFollowingLocation; +@property(readonly, nonatomic) NSSet *allSiblingFMFHandles; +- (void)markAllLocationShareItemsAsUnactionable; +@property(readonly, nonatomic) NSSet *fmfHandles; +@property(readonly, nonatomic) IMChatRegistry *chatRegistry; +- (id)testChatItems; +- (BOOL)canEditChatItem:(id)arg1; +- (void)initiateTUConversationWithVideoEnabled:(BOOL)arg1; +- (void)joinExistingTUConversationWithVideoEnabled:(BOOL)arg1; +- (void)_launchAppForJoinRequest:(id)arg1; +- (BOOL)mapsToTUConversation:(id)arg1; +- (id)messageAcknowledgmentSummaryForConversationListWithMessage:(id)arg1; +- (void)sendMessageAcknowledgment:(long long)arg1 forChatItem:(id)arg2 withAssociatedMessageInfo:(id)arg3; +- (void)sendMessageAcknowledgment:(long long)arg1 forChatItem:(id)arg2 withMessageSummaryInfo:(id)arg3; +- (void)deleteExtensionPayloadData; +- (void)closeSession; +@property(readonly, nonatomic) BOOL isAppleChat; +@property(readonly, nonatomic) BOOL isMakoChat; +@property(readonly, nonatomic) BOOL isBusinessChat; +@property(readonly, nonatomic) BOOL isReplyEnabled; +//@property(readonly, nonatomic) MKMapItem *mapItem; +@property(nonatomic) BOOL forceMMS; +@property(readonly, nonatomic) BOOL suppressAccountRetargetingForNamedGroupConversation; +- (void)_calculateDowngradeState; +- (void)_setAndIncrementDowngradeMarkersForManual:(BOOL)arg1; +- (void)_clearDowngradeMarkers; +- (id)_consecutiveDowngradeAttemptsViaManualDowngrades:(BOOL)arg1; +- (void)_calculateDowngradeStateTimerFired; +- (void)_updateDowngradeState:(BOOL)arg1 checkAgainInterval:(double)arg2; +- (void)_invalidateDowngradeState; +- (BOOL)isDowngraded; +- (void)_targetToService:(id)arg1 newComposition:(BOOL)arg2; +- (void)_setPreviousAccount:(id)arg1 forService:(id)arg2; +- (id)_previousAccountForService:(id)arg1; +- (BOOL)_chatHasValidAccount:(id)arg1 forService:(id)arg2; +- (BOOL)_accountIsOperational:(id)arg1 forService:(id)arg2; +- (void)_delayedInvalidateDowngradeState; +- (void)_handleIncomingCommand:(id)arg1; +- (void)_handleDeliveredCommand:(id)arg1; +- (BOOL)sendDowngradeNotificationTo:(id)arg1; +- (void)sendDowngradePingForMessage:(id)arg1 manualDowngrade:(BOOL)arg2; +- (void)refreshServiceForSending; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly) NSString *identifier; +@property(readonly) Class superclass; + +@end + +@interface IMItemChatContext : NSObject +{ + IMHandle *_senderHandle; + IMHandle *_otherHandle; +} + + +- (void)dealloc; + +@end + +@interface IMMessageItemChatContext : IMItemChatContext +{ + IMMessage *_message; + BOOL _invitation; +} + + +- (void)dealloc; + +@end + +@interface IMCloudKitHooks : NSObject +{ +} + ++ (id)logHandle; ++ (id)sharedInstance; ++ (void)__setSingleton__im:(id)arg1; ++ (id)__singleton__im; +- (BOOL)mocAccountsMatch; +- (void)reportMetricToCK:(id)arg1 withDict:(id)arg2; +- (void)reportMetricToCK:(id)arg1 withSuccess:(BOOL)arg2; +- (void)reportMetricToCK:(id)arg1; +- (void)broadcastCloudKitStateAfterClearingErrors; +- (void)broadcastCloudKitStateAfterFetchingAccountStatus; +- (void)broadcastCloudKitState; +- (void)tryToAutoCollectLogsWithErrorString:(id)arg1 sendLogsTo:(id)arg2; +- (void)fetchCloudKitSyncStateDebuggingInfo:(id)arg1; +- (id)syncStateDictionary; +- (void)syncDeletesToCloudKit; +- (void)printCachedRampState; +- (void)fetchLatestRampState; +- (void)writeCloudKitSyncCounts:(id)arg1; +- (void)fetchSyncStateStatistics; +- (void)updateAttachmentFileSizes; +- (void)purgeAttachments:(long long)arg1; +- (void)metricAttachments:(long long)arg1; +- (void)deleteSalt; +- (void)printCachedSalt; +- (void)fetchLatestSalt; +- (void)clearTombStoneMessagesTable; +- (void)loadDeletedMessagesWithLimit:(long long)arg1; +- (void)_updateCloudKitState; +- (void)_updateCloudKitStateWithDictionary:(id)arg1; +- (id)exitDate; +- (BOOL)isInExitState; +- (void)_didAttemptToDisableAllDevicesResult:(BOOL)arg1; +- (BOOL)isDisablingDevices; +- (void)_didPerformAdditionalStorageRequiredCheckWithSuccess:(BOOL)arg1 additionalStorageRequired:(unsigned long long)arg2 forAccountId:(id)arg3 error:(id)arg4; +- (long long)isChangingEnabledState; +- (void)_didAttemptToSetEnabledTo:(BOOL)arg1 result:(BOOL)arg2; +- (id)lastSyncDate; +- (BOOL)isSyncing; +- (BOOL)isStartingSync; +- (void)initiateSync; +- (void)_requestMOCEnabledReturned:(unsigned long long)arg1; +- (void)requestMOCEnabledState; +- (void)setShouldOptimizeAttachmentStorage:(BOOL)arg1; +- (BOOL)shouldOptimizeAttachmentStorage; +- (BOOL)eligibleForTruthZone; +- (BOOL)rampedIntoTruthZone; +- (BOOL)removedFromiCloudBackup; +- (void)tryToDisableAllDevices; +- (void)fetchSecurityLevelAndUpdateMiCSwitchEligibility; +- (void)performAdditionalStorageRequiredCheck; +- (void)setEnabled:(BOOL)arg1; +- (BOOL)isEnabled; +- (BOOL)shouldShowCloudKitUI; +- (void)sendRestoreFailuresLogDumps; +- (void)clearDataFromCloudKit; +- (void)clearLocalSyncState; +- (void)loadDirtyMessagesWithLimit:(long long)arg1; +- (void)initiatePeriodicSync; +- (void)downloadAttachmentAssets; +- (void)syncMessages; +- (void)deleteExitRecord; +- (void)fetchExitRecord; +- (void)writeExitRecord; +- (void)deleteMessagesZone; +- (void)writeDirtyMessages; +- (void)deleteAttachmentZone; +- (void)syncAttachments; +- (void)writeAttachments; +- (void)createAttachmentZone; +- (void)clearChatZoneSyncToken; +- (void)markAllChatsAsDirty; +- (void)syncChats; +- (void)deleteChatZone; +- (void)writeDirtyChats; +- (void)createChatZone; +- (void)setupIMCloudKitHooks; +- (void)clearAnalyticDefaultsAndLocalSyncState; +- (void)uploadDailyAnalyticstoCloudKit; +- (id)init; +- (id)logHandle; + +@end + +@interface IMBusinessNameManager : NSObject +{ + NSLock *_lock; + NSMutableDictionary *_cache; + NSMutableDictionary *_pendingRequests; +} + ++ (id)sharedInstance; +@property(retain) NSMutableDictionary *pendingRequests; // @synthesize pendingRequests=_pendingRequests; +@property(retain) NSMutableDictionary *cache; // @synthesize cache=_cache; +@property(retain) NSLock *lock; // @synthesize lock=_lock; + +- (id)businessNameForUID:(id)arg1 updateHandler:(CDUnknownBlockType)arg2; +- (id)init; + +@end + +@interface IMMessage : NSObject +{ + IMHandle *_sender; + IMHandle *_subject; + NSAttributedString *_text; + NSString *_plainBody; + NSDate *_time; + NSDate *_timeDelivered; + NSDate *_timeRead; + NSDate *_timePlayed; + NSString *_guid; + NSAttributedString *_messageSubject; + NSArray *_fileTransferGUIDs; + NSError *_error; + NSString *_balloonBundleID; + NSData *_payloadData; + NSString *_expressiveSendStyleID; + NSDate *_timeExpressiveSendPlayed; + unsigned long long _flags; + BOOL _isInvitationMessage; + long long _messageID; + NSDictionary *_bizIntent; + NSString *_locale; + BOOL _isSOS; + NSString *_associatedMessageGUID; + long long _associatedMessageType; + NSDictionary *_messageSummaryInfo; + NSString *_associatedBalloonBundleID; + NSData *_customTypingIndicatorIcon; + NSString *_notificationIDSTokenURI; + unsigned long long _sortID; + struct _NSRange _associatedMessageRange; +} + ++ (id)determineRichLinksInMessage:(id)arg1 additionalSupportedSchemes:(id)arg2; ++ (id)determineRichLinksInMessage:(id)arg1; ++ (BOOL)supportedRichLinkURL:(id)arg1 additionalSupportedSchemes:(id)arg2; ++ (BOOL)hasKnownSchemesForRichLinkURL:(id)arg1 additionalSupportedSchemes:(id)arg2; ++ (BOOL)hasKnownSchemesForRichLinkURL:(id)arg1; ++ (Class)richLinksDataSourceClass; ++ (id)messageFromIMMessageItemDictionary:(id)arg1 body:(id)arg2 sender:(id)arg3 subject:(id)arg4; ++ (id)messageFromIMMessageItem:(id)arg1 sender:(id)arg2 subject:(id)arg3; ++ (id)fromMeIMHandle:(id)arg1 withText:(id)arg2 fileTransferGUIDs:(id)arg3 flags:(unsigned long long)arg4; ++ (id)instantMessageWithText:(id)arg1 messageSubject:(id)arg2 fileTransferGUIDs:(id)arg3 flags:(unsigned long long)arg4 balloonBundleID:(id)arg5 payloadData:(id)arg6 expressiveSendStyleID:(id)arg7; ++ (id)instantMessageWithText:(id)arg1 messageSubject:(id)arg2 fileTransferGUIDs:(id)arg3 flags:(unsigned long long)arg4; ++ (id)instantMessageWithText:(id)arg1 messageSubject:(id)arg2 flags:(unsigned long long)arg3 expressiveSendStyleID:(id)arg4; ++ (id)instantMessageWithText:(id)arg1 messageSubject:(id)arg2 flags:(unsigned long long)arg3; ++ (id)instantMessageWithText:(id)arg1 flags:(unsigned long long)arg2; ++ (id)defaultInvitationMessageFromSender:(id)arg1 flags:(unsigned long long)arg2; ++ (id)locatingMessageWithGuid:(id)arg1 error:(id)arg2; ++ (id)messageWithLocation:(id)arg1 flags:(unsigned long long)arg2 error:(id)arg3 guid:(id)arg4; ++ (id)_vCardDataWithCLLocation:(id)arg1; ++ (id)breadcrumbMessageWithText:(id)arg1 associatedMessageGUID:(id)arg2 balloonBundleID:(id)arg3 fileTransferGUIDs:(id)arg4 payloadData:(id)arg5; ++ (id)editedMessageWithOriginalMessage:(id)arg1 originalPrefixedGUID:(id)arg2 newBody:(id)arg3; ++ (id)instantMessageWithAssociatedMessageContent:(id)arg1 flags:(unsigned long long)arg2 associatedMessageGUID:(id)arg3 associatedMessageType:(long long)arg4 associatedMessageRange:(struct _NSRange)arg5 messageSummaryInfo:(id)arg6; +@property(nonatomic) unsigned long long sortID; // @synthesize sortID=_sortID; +@property(nonatomic) BOOL isSOS; // @synthesize isSOS=_isSOS; +@property(retain, nonatomic) NSString *notificationIDSTokenURI; // @synthesize notificationIDSTokenURI=_notificationIDSTokenURI; +@property(retain, nonatomic) NSData *customTypingIndicatorIcon; // @synthesize customTypingIndicatorIcon=_customTypingIndicatorIcon; +@property(retain, nonatomic) NSDate *timeExpressiveSendPlayed; // @synthesize timeExpressiveSendPlayed=_timeExpressiveSendPlayed; +@property(retain, nonatomic) NSString *expressiveSendStyleID; // @synthesize expressiveSendStyleID=_expressiveSendStyleID; +@property(retain, nonatomic) NSString *associatedBalloonBundleID; // @synthesize associatedBalloonBundleID=_associatedBalloonBundleID; +@property(retain, nonatomic) NSData *payloadData; // @synthesize payloadData=_payloadData; +@property(retain, nonatomic) NSString *balloonBundleID; // @synthesize balloonBundleID=_balloonBundleID; +@property(retain, nonatomic, setter=_updateLocale:) NSString *locale; // @synthesize locale=_locale; +@property(retain, nonatomic, setter=_updateBizIntent:) NSDictionary *bizIntent; // @synthesize bizIntent=_bizIntent; +@property(copy, nonatomic, setter=_messageSummaryInfo:) NSDictionary *messageSummaryInfo; // @synthesize messageSummaryInfo=_messageSummaryInfo; +@property(nonatomic, setter=_associatedMessageRange:) struct _NSRange associatedMessageRange; // @synthesize associatedMessageRange=_associatedMessageRange; +@property(nonatomic, setter=_associatedMessageType:) long long associatedMessageType; // @synthesize associatedMessageType=_associatedMessageType; +@property(copy, nonatomic, setter=_associatedMessageGUID:) NSString *associatedMessageGUID; // @synthesize associatedMessageGUID=_associatedMessageGUID; +@property(retain, nonatomic, setter=_updateTimePlayed:) NSDate *timePlayed; // @synthesize timePlayed=_timePlayed; +@property(retain, nonatomic, setter=_updateTimeRead:) NSDate *timeRead; // @synthesize timeRead=_timeRead; +@property(retain, nonatomic, setter=_updateTimeDelivered:) NSDate *timeDelivered; // @synthesize timeDelivered=_timeDelivered; +@property(copy, nonatomic, setter=_updateFileTransferGUIDs:) NSArray *fileTransferGUIDs; // @synthesize fileTransferGUIDs=_fileTransferGUIDs; +@property(nonatomic) BOOL isInvitationMessage; // @synthesize isInvitationMessage=_isInvitationMessage; +@property(retain, nonatomic, setter=_updateError:) NSError *error; // @synthesize error=_error; +@property(nonatomic, setter=_updateFlags:) unsigned long long flags; // @synthesize flags=_flags; +@property(nonatomic, setter=_updateMessageID:) long long messageID; // @synthesize messageID=_messageID; +@property(retain, nonatomic, setter=_updateGUID:) NSString *guid; // @synthesize guid=_guid; +@property(retain, nonatomic, setter=_updateText:) NSAttributedString *text; // @synthesize text=_text; +@property(retain, nonatomic, setter=_updateTime:) NSDate *time; // @synthesize time=_time; +@property(readonly, nonatomic) NSAttributedString *messageSubject; // @synthesize messageSubject=_messageSubject; +@property(readonly, nonatomic) IMHandle *subject; // @synthesize subject=_subject; +@property(retain, nonatomic, setter=_updateSender:) IMHandle *sender; // @synthesize sender=_sender; + +- (id)description; +- (BOOL)isEqual:(id)arg1; +- (id)messagesBySeparatingRichLinks; +@property(readonly, nonatomic) IMMessageItem *_imMessageItem; +- (long long)compare:(id)arg1 comparisonType:(long long)arg2; +- (long long)compare:(id)arg1; +@property(readonly, nonatomic) BOOL wasDataDetected; +@property(readonly, nonatomic) BOOL wasDowngraded; +@property(readonly, nonatomic) BOOL isAlert; +@property(readonly, nonatomic) BOOL isAddressedToMe; +- (void)setIsAddressedToMe:(BOOL)arg1; +@property(readonly, nonatomic) BOOL isSystemMessage; +@property(readonly, nonatomic) BOOL isPlayed; +@property(readonly, nonatomic) BOOL isAudioMessage; +@property(readonly, nonatomic) BOOL isRead; +@property(readonly, nonatomic) BOOL isDelivered; +@property(readonly, nonatomic) BOOL isAutoReply; +@property(readonly, nonatomic) BOOL isDelayed; +@property(readonly, nonatomic) BOOL isEmpty; +@property(readonly, nonatomic) BOOL isFromMe; +@property(readonly, nonatomic) BOOL isEmote; +@property(readonly, nonatomic) NSArray *inlineAttachmentAttributesArray; +@property(readonly, nonatomic) BOOL hasInlineAttachments; +@property(readonly, nonatomic) BOOL isSent; +@property(readonly, nonatomic) BOOL isLocatingMessage; +@property(readonly, nonatomic) BOOL isTypingMessage; +@property(readonly, nonatomic) BOOL isFinished; +@property(readonly, nonatomic) BOOL hasDataDetectorResults; +@property(readonly, nonatomic) NSString *summaryString; +@property(readonly, nonatomic) NSString *senderName; +@property(readonly, nonatomic) NSString *plainBody; +- (id)initWithSender:(id)arg1 fileTransfer:(id)arg2; +- (id)initWithSender:(id)arg1 time:(id)arg2 text:(id)arg3 messageSubject:(id)arg4 fileTransferGUIDs:(id)arg5 flags:(unsigned long long)arg6 error:(id)arg7 guid:(id)arg8 subject:(id)arg9 associatedMessageGUID:(id)arg10 associatedMessageType:(long long)arg11 associatedMessageRange:(struct _NSRange)arg12 messageSummaryInfo:(id)arg13; +- (id)initWithSender:(id)arg1 time:(id)arg2 text:(id)arg3 messageSubject:(id)arg4 fileTransferGUIDs:(id)arg5 flags:(unsigned long long)arg6 error:(id)arg7 guid:(id)arg8 subject:(id)arg9 balloonBundleID:(id)arg10 payloadData:(id)arg11 expressiveSendStyleID:(id)arg12; +- (id)initWithSender:(id)arg1 time:(id)arg2 text:(id)arg3 fileTransferGUIDs:(id)arg4 flags:(unsigned long long)arg5 error:(id)arg6 guid:(id)arg7 subject:(id)arg8; +- (id)initWithSender:(id)arg1 time:(id)arg2 text:(id)arg3 messageSubject:(id)arg4 fileTransferGUIDs:(id)arg5 flags:(unsigned long long)arg6 error:(id)arg7 guid:(id)arg8 subject:(id)arg9; +- (id)_initWithSender:(id)arg1 time:(id)arg2 timeRead:(id)arg3 timeDelivered:(id)arg4 timePlayed:(id)arg5 plainText:(id)arg6 text:(id)arg7 messageSubject:(id)arg8 fileTransferGUIDs:(id)arg9 flags:(unsigned long long)arg10 error:(id)arg11 guid:(id)arg12 messageID:(long long)arg13 subject:(id)arg14 balloonBundleID:(id)arg15 payloadData:(id)arg16 expressiveSendStyleID:(id)arg17 timeExpressiveSendPlayed:(id)arg18 associatedMessageGUID:(id)arg19 associatedMessageType:(long long)arg20 associatedMessageRange:(struct _NSRange)arg21 messageSummaryInfo:(id)arg22; +- (id)_copyWithFlags:(unsigned long long)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)descriptionForPurpose:(long long)arg1 inChat:(id)arg2; +- (id)descriptionForPurpose:(long long)arg1; +- (void)_ovverrideGUIDForTest:(id)arg1; +@property(readonly, nonatomic) BOOL isAssociatedMessage; +- (id)initWithSender:(id)arg1 time:(id)arg2 text:(id)arg3 messageSubject:(id)arg4 fileTransferGUIDs:(id)arg5 flags:(unsigned long long)arg6 error:(id)arg7 guid:(id)arg8 subject:(id)arg9 associatedMessageGUID:(id)arg10 associatedMessageType:(long long)arg11 associatedMessageRange:(struct _NSRange)arg12 associatedMessageInfo:(id)arg13; + +@end + +@interface IMChatRegistry : NSObject +{ + NSMutableArray *_allChats; + NSMutableDictionary *_chatGUIDToCurrentThreadMap; + NSMutableDictionary *_chatGUIDToInfoMap; + NSMutableDictionary *_chatGUIDToChatMap; + NSMutableDictionary *_threadNameToChatMap; + NSMutableDictionary *_chatGUIDToiMessageSentOrReceivedMap; + NSMutableArray *_allChatsInThreadNameMap; + NSMutableArray *_pendingQueries; + NSMutableArray *_waitingForQueries; + NSString *_historyModificationStamp; + + NSMutableDictionary *_queryCompletionBlocks; + double _timerStartTimeInterval; + BOOL _firstLoad; + BOOL _loading; + BOOL _daemonHadTerminated; + BOOL _wantsHistoryReload; + BOOL _postMessageSentNotifications; + BOOL _isInternalInstall; + unsigned long long _defaultNumberOfMessagesToLoad; + unsigned long long _daemonUnreadCount; + long long _daemonLastFailedMessageDate; + NSUserActivity *_userActivity; + NSMutableDictionary *_chatsBeingLoadedMap; + NSMutableDictionary *_chatPersonIDToChatMap; + NSMutableDictionary *_groupIDToChatMap; + NSMutableDictionary *_groupParticipantToChatsMap; + + NSSet *_registryChangeHistoryChatsToObserve; + NSSet *_registryChangeHistoryChatsToUnregister; + BOOL _personaKitRetriveAPITimedOut; + NSArray *_simulatedChats; + IMChatRegistry *_batchProcessingRegistry; + NSObject *_batchProcessingQueue; + NSMutableArray *_updateBlocks; + NSArray *_preExistingAllChats; +// TUConversationManager *_conversationManager; + NSDictionary *_chatIdToLastMessageItemMap; +} + ++ (Class)messageClass; ++ (void)setMessageClass:(Class)arg1; ++ (id)sharedInstance; ++ (id)performanceLogHandle; ++ (void)setHasInitializedChatFiltering:(BOOL)arg1; ++ (BOOL)hasInitializedChatFiltering; +@property(retain, nonatomic) NSDictionary *chatIdToLastMessageItemMap; // @synthesize chatIdToLastMessageItemMap=_chatIdToLastMessageItemMap; +//@property(readonly, nonatomic) TUConversationManager *conversationManager; // @synthesize conversationManager=_conversationManager; +@property(retain, nonatomic) NSArray *preExistingAllChats; // @synthesize preExistingAllChats=_preExistingAllChats; +@property(retain, nonatomic) NSMutableArray *updateBlocks; // @synthesize updateBlocks=_updateBlocks; +@property(retain, nonatomic) NSObject *batchProcessingQueue; // @synthesize batchProcessingQueue=_batchProcessingQueue; +@property(retain, nonatomic) IMChatRegistry *batchProcessingRegistry; // @synthesize batchProcessingRegistry=_batchProcessingRegistry; +@property(retain, nonatomic, setter=_setSimulatedChats:) NSArray *simulatedChats; // @synthesize simulatedChats=_simulatedChats; +@property(nonatomic) BOOL personaKitRetriveAPITimedOut; // @synthesize personaKitRetriveAPITimedOut=_personaKitRetriveAPITimedOut; +@property(nonatomic, setter=_setPostMessageSentNotifications:) BOOL _postMessageSentNotifications; // @synthesize _postMessageSentNotifications; +@property(readonly, nonatomic) BOOL _isLoading; // @synthesize _isLoading=_loading; +@property(nonatomic, setter=_setDefaultNumberOfMessagesToLoad:) unsigned long long _defaultNumberOfMessagesToLoad; // @synthesize _defaultNumberOfMessagesToLoad; + +@property(readonly, nonatomic) BOOL isBatchProcessing; +- (void)_setMetaDictionary:(id)arg1 forKey:(id)arg2; +- (id)_transcriptRenderingMetaDictionaryForKey:(id)arg1; +- (double)_maxDurationForScrutinyMode; +- (BOOL)_firstLoad; +- (void)systemApplicationDidResume; +- (void)_clearMarkAsReadTimerIfNecessary; +- (void)_startMarkAsReadTimerIfNecessary; +- (void)_registerCompletion:(CDUnknownBlockType)arg1 forQueryID:(id)arg2; +- (void)_chat:(id)arg1 handleCompletionOfQuery:(id)arg2 withUserInfo:(id)arg3 success:(BOOL)arg4 error:(id)arg5; +- (void)_blockUntilQueriesComplete:(id)arg1; +- (void)__blockUntilQueriesComplete; +- (id)_chatGUIDToChatMap; +- (id)_chatsWithMessageGUID:(id)arg1; +- (id)_chatsWithMessage:(id)arg1; +- (id)_allGUIDsForChat:(id)arg1; +- (void)_handleAddressBookChange:(id)arg1; +- (void)handleIMChatParticipantsDidChange:(id)arg1; +- (id)loadChatFromDaemonWithChatIdentifier:(id)arg1; +- (id)_sortedParticipantIDHashForParticipants:(id)arg1; +- (void)_addChat:(id)arg1 participantSet:(id)arg2; +- (void)_removeFromGroupParticipantToChatsMap:(id)arg1; +- (void)_resetChatReconstructionGroupMaps; +- (id)_chatForChatDictionary:(id)arg1 items:(id)arg2 allowCreate:(BOOL)arg3 createdChat:(char *)arg4 outGUID:(id *)arg5; +- (id)existingChatForRoom:(id)arg1 onAccount:(id)arg2 allowRetargeting:(BOOL)arg3; +- (id)existingChatForIMHandles:(id)arg1 allowRetargeting:(BOOL)arg2; +- (id)existingChatForIMHandles:(id)arg1 allowRetargeting:(BOOL)arg2 groupID:(id)arg3 displayName:(id)arg4 joinedChatsOnly:(BOOL)arg5; +- (id)existingChatForIMHandles:(id)arg1 allowRetargeting:(BOOL)arg2 groupID:(id)arg3 displayName:(id)arg4 ignoresDisplayName:(BOOL)arg5 joinedChatsOnly:(BOOL)arg6; +- (id)existingChatForAddresses:(id)arg1 allowRetargeting:(BOOL)arg2 bestHandles:(id *)arg3; +- (id)existingChatForIMHandles:(id)arg1 allowRetargeting:(BOOL)arg2 groupID:(id)arg3; +- (id)existingChatForIMHandle:(id)arg1 allowRetargeting:(BOOL)arg2; +- (id)existingConversationForTUConversationUUID:(id)arg1; +- (id)existingChatForEngramID:(id)arg1; +- (id)exisitingChatForGroupID:(id)arg1; +- (id)existingChatForRoom:(id)arg1 onAccount:(id)arg2; +- (id)existingChatForIMHandles:(id)arg1; +- (id)existingChatForIMHandle:(id)arg1; +- (id)existingChatWithGUID:(id)arg1; +- (id)existingChatForPersonID:(id)arg1; +- (id)existingChatWithChatIdentifier:(id)arg1; +- (id)existingChatWithGroupID:(id)arg1; +- (id)_lookupExistingChatWithIMHandle:(id)arg1; +- (id)_existingChatWithIdentifier:(id)arg1 style:(unsigned char)arg2 account:(id)arg3; +- (id)_existingChatWithIdentifier:(id)arg1 style:(unsigned char)arg2 service:(id)arg3; +@property(readonly, nonatomic) NSArray *allExistingChats; +@property(readonly, nonatomic) unsigned long long numberOfExistingChats; +- (void)_setChatHasCommunicatedOveriMessage:(id)arg1; +- (BOOL)_hasChat:(id)arg1 forService:(id)arg2; +- (void)markMessageAsNotCorrupt:(id)arg1; +- (void)markMessageAsCorrupt:(id)arg1; +// - (unsigned long long)countByEnumeratingWithState:(CDStruct_70511ce9 *)arg1 objects:(id *)arg2 count:(unsigned long long)arg3; +- (long long)lastFailedMessageDate; +- (unsigned long long)unreadCount; +- (id)registryChangeHistoryChatsToObserveSet; +- (id)registryChangeHistoryChatsToUnregisterSet; +- (id)_createdChatForRoom:(id)arg1 onAccount:(id)arg2; +- (id)_createdChatForIMHandles:(id)arg1 style:(unsigned char)arg2 groupID:(id)arg3 displayName:(id)arg4 joinedChatsOnly:(BOOL)arg5; +- (id)_createdChatForIMHandle:(id)arg1; +- (id)_createdChatWithIdentifier:(id)arg1 style:(unsigned char)arg2 account:(id)arg3; +- (id)_allCreatedChats; +- (void)setUserActivityForChat:(id)arg1 message:(id)arg2 orHandles:(id)arg3 title:(id)arg4; +- (id)_inPersonFromIMHandle:(id)arg1; +- (id)_inPersonNameForContact:(id)arg1 imHandle:(id)arg2; +- (id)_inPersonHandleFromIMHandle:(id)arg1 contact:(id)arg2; +- (void)setUserActivityForChat:(id)arg1 orHandles:(id)arg2 title:(id)arg3; +- (void)setActiveChatURL:(id)arg1; +- (id)chatForURL:(id)arg1 outMessageText:(id *)arg2 outRecipientIDs:(id *)arg3 outService:(id *)arg4 outMessageGUID:(id *)arg5; +- (id)messagesURLWithChat:(id)arg1 orHandles:(id)arg2 withMessageText:(id)arg3; +- (id)chatForRoom:(id)arg1 onAccount:(id)arg2; +- (id)chatForIMHandles:(id)arg1 chatName:(id)arg2 lastAddressedHandle:(id)arg3 lastAddressedSIMID:(id)arg4; +- (id)chatForIMHandles:(id)arg1 chatName:(id)arg2; +- (id)chatForIMHandles:(id)arg1 displayName:(id)arg2 joinedChatsOnly:(BOOL)arg3 lastAddressedHandle:(id)arg4 lastAddressedSIMID:(id)arg5; +- (id)chatForIMHandles:(id)arg1 displayName:(id)arg2 joinedChatsOnly:(BOOL)arg3; +- (id)chatForIMHandles:(id)arg1 lastAddressedHandle:(id)arg2 lastAddressedSIMID:(id)arg3; +- (id)chatForIMHandles:(id)arg1; +- (id)chatForIMHandle:(id)arg1 lastAddressedHandle:(id)arg2 lastAddressedSIMID:(id)arg3; +- (id)chatForIMHandle:(id)arg1; +- (void)_unregisterChatWithGUID:(id)arg1; +- (void)_unregisterChat:(id)arg1; +- (void)unregisterChatWithGUID:(id)arg1; +- (void)unregisterChat:(id)arg1; +- (void)_registerChat:(id)arg1 isIncoming:(BOOL)arg2 guid:(id)arg3; +- (void)_registerChatDictionary:(id)arg1 forChat:(id)arg2 isIncoming:(BOOL)arg3 newGUID:(id)arg4; +- (void)_registerChatDictionary:(id)arg1 forChat:(id)arg2 isIncoming:(BOOL)arg3 newGUID:(id)arg4 shouldPostNotification:(BOOL)arg5; +- (void)dealloc; +- (id)init; +- (id)_chatInstanceForGUID:(id)arg1; +- (void)_noteChatDealloc:(id)arg1; +- (void)_noteChatInit:(id)arg1; +- (id)performanceLogHandle; +- (void)_postMultiWayStateChangedNotification:(id)arg1; +- (void)conversationManager:(id)arg1 removedActiveConversation:(id)arg2; +- (void)conversationManager:(id)arg1 activeRemoteParticipantsChangedForConversation:(id)arg2; +- (void)conversationManager:(id)arg1 stateChangedForConversation:(id)arg2; +- (id)_existingChatForTUConversation:(id)arg1; +- (id)_activeTUConversations; +- (id)activeCallForConversationUUID:(id)arg1; +- (void)setUpInitialCallState; +- (void)verifyFilteringForAllChats; +- (void)_IMChatGetIdentifiersAndServicesTestHook:(id)arg1 identifiers:(id *)arg2 services:(id *)arg3 personCentricEnabled:(BOOL)arg4; +- (void)_chat_closeSession:(id)arg1; +- (void)_chat_isDownloadingPurgedAssetsForChat:(id)arg1 queryID:(id)arg2; +- (void)_chat_downloadPurgedAttachmentsForChat:(id)arg1; +- (void)_chat_loadUncachedAttachmentsCount:(id)arg1 queryID:(id)arg2; +- (void)_chat_loadAttachments:(id)arg1 queryID:(id)arg2; +- (void)_chat_loadUnreadMessages:(id)arg1 limit:(unsigned long long)arg2 fallbackGUID:(id)arg3 queryId:(id)arg4; +- (void)_chat_loadFrequentReplies:(id)arg1 limit:(unsigned long long)arg2 queryID:(id)arg3; +- (void)_chat_markAsSpam:(id)arg1 queryID:(id)arg2 autoReport:(BOOL)arg3; +- (void)_chat_markAsSpamAutomatically:(id)arg1; +- (void)_chat_markAsSpam:(id)arg1 queryID:(id)arg2; +- (void)_chat_clearHistory:(id)arg1 beforeGUID:(id)arg2 afterGUID:(id)arg3 queryID:(id)arg4; +- (void)_chat_loadPagedHistory:(id)arg1 numberOfMessagesBefore:(unsigned long long)arg2 numberOfMessagesAfter:(unsigned long long)arg3 messageGUID:(id)arg4 queryID:(id)arg5; +- (void)_chat_loadHistory:(id)arg1 limit:(unsigned long long)arg2 beforeGUID:(id)arg3 afterGUID:(id)arg4 queryID:(id)arg5; +- (void)_chat:(id)arg1 updateIsFiltered:(BOOL)arg2; +- (void)_chat:(id)arg1 updateLastAddressedSIMID:(id)arg2; +- (void)_chat:(id)arg1 updateLastAddressedHandle:(id)arg2; +- (void)_chat:(id)arg1 updateDisplayName:(id)arg2; +- (void)_chat:(id)arg1 setValue:(id)arg2 forChatProperty:(id)arg3; +- (void)_chat:(id)arg1 setProperties:(id)arg2 ofParticipant:(id)arg3; +- (void)_chat_declineInvitation:(id)arg1; +- (void)_chat_archive:(id)arg1; +- (void)_chat_remove:(id)arg1; +- (void)_chat_leave:(id)arg1 leavingiMessageChat:(BOOL)arg2; +- (void)_chat:(id)arg1 joinWithProperties:(id)arg2; +- (void)_chat:(id)arg1 removeParticipants:(id)arg2 reason:(id)arg3 fromiMessageChat:(BOOL)arg4; +- (void)_chat:(id)arg1 inviteParticipants:(id)arg2 reason:(id)arg3 toiMessageChat:(BOOL)arg4; +- (void)_chat:(id)arg1 sendMessage:(id)arg2; +- (void)_trackUsageForMessage:(id)arg1; +- (id)_eventForMessage:(id)arg1; +- (void)_markHasHadSuccessfulQueryForChat:(id)arg1; +- (void)_chat:(id)arg1 sendSavedReceiptForMessage:(id)arg2; +- (void)_chat:(id)arg1 setPlayedExpressiveSendForMessage:(id)arg2; +- (void)_chat:(id)arg1 sendPlayedReceiptForMessage:(id)arg2; +- (void)_chat_storeItem:(id)arg1 inChat:(id)arg2; +- (void)_chat_sendReadReceiptForAllMessages:(id)arg1; +- (void)_chat:(id)arg1 sendReadReceiptForMessages:(id)arg2; +- (void)_removeChatIdFromChatIdToLastMessageItemMap:(id)arg1; +- (void)lastMessageForAllChats:(id)arg1; +- (void)chatLoadedWithChatIdentifier:(id)arg1 chats:(id)arg2; +- (void)_chatLoadedWithChatIdentifier:(id)arg1 chats:(id)arg2; +- (void)setupComplete; +- (void)_daemonReallyDied:(id)arg1; +- (void)setupComplete:(BOOL)arg1 info:(id)arg2; +- (void)__handleChatReconstructions:(id)arg1; +- (void)_handleChatReconstructions:(id)arg1; +- (void)__handleMergedChatReconstructions:(id)arg1 fullReload:(BOOL)arg2; +- (void)updateChatDictionaryArray:(id)arg1 createdChat:(id)arg2 joinstate:(long long)arg3 setHasCommunicatedOveriMessage:(char *)arg4; +- (void)__handleMergedChatReconstructions:(id)arg1; +- (void)_resetChatRegistry; +- (id)chatPersonIDToChatMap; +- (void)_handleMergedChatReconstructions:(id)arg1; +- (id)_copyMergedChatsPairedArrayFromMergedChatsArray:(id)arg1; +- (void)chatsNeedRemerging:(id)arg1 groupedChats:(id)arg2; +- (void)frequentRepliesQuery:(id)arg1 finishedWithResult:(id)arg2 limit:(unsigned long long)arg3; +- (void)frequentRepliesQuery:(id)arg1 chatID:(id)arg2 services:(id)arg3 finishedWithResult:(id)arg4 limit:(unsigned long long)arg5; +- (void)markAsSpamQuery:(id)arg1 chatID:(id)arg2 services:(id)arg3 finishedWithResult:(id)arg4; +- (void)isDownloadingQuery:(id)arg1 chatID:(id)arg2 services:(id)arg3 finishedWithResult:(BOOL)arg4; +- (void)downloadedPurgedAssetBatchForChatIDs:(id)arg1 completedTransferGUIDs:(id)arg2; +- (void)finishedDownloadingPurgedAssetsForChatIDs:(id)arg1; +- (id)_chatForIdentifiers:(id)arg1; +- (void)uncachedAttachmentCountQuery:(id)arg1 chatID:(id)arg2 services:(id)arg3 finishedWithResult:(id)arg4; +- (void)attachmentQuery:(id)arg1 chatID:(id)arg2 services:(id)arg3 finishedWithResult:(id)arg4; +- (void)pagedHistoryQuery:(id)arg1 chatID:(id)arg2 services:(id)arg3 numberOfMessagesBefore:(unsigned long long)arg4 numberOfMessagesAfter:(unsigned long long)arg5 finishedWithResult:(id)arg6; +- (void)historyQuery:(id)arg1 chatID:(id)arg2 services:(id)arg3 finishedWithResult:(id)arg4 limit:(unsigned long long)arg5; +- (void)_checkIfItemIsCorrupt:(id)arg1; +- (void)_checkLimitAndSetMessagesToKeepLoadedIfNeeded:(unsigned long long)arg1 chat:(id)arg2; +- (void)historicalMessageGUIDsDeleted:(id)arg1 chatGUIDs:(id)arg2 queryID:(id)arg3; +- (void)lastFailedMessageDateChanged:(long long)arg1; +- (void)unreadCountChanged:(long long)arg1; +- (void)chat:(id)arg1 updated:(id)arg2; +- (void)_updateInfo:(id)arg1 forGUID:(id)arg2 updatingUnreadCount:(BOOL)arg3 shouldPostUnreadNotification:(BOOL)arg4; +- (void)_updateInfo:(id)arg1 forGUID:(id)arg2 updatingUnreadCount:(BOOL)arg3; +- (void)_updateUnreadCountForChat:(id)arg1 shouldPostNotification:(BOOL)arg2; +- (void)_updateUnreadCountForChat:(id)arg1; +- (void)engroupParticipantsUpdatedForChat:(id)arg1; +- (void)chat:(id)arg1 engramIDUpdated:(id)arg2; +- (void)chat:(id)arg1 isFilteredUpdated:(BOOL)arg2; +- (void)chat:(id)arg1 lastAddressedSIMIDUpdated:(id)arg2; +- (void)chat:(id)arg1 lastAddressedHandleUpdated:(id)arg2; +- (void)chat:(id)arg1 displayNameUpdated:(id)arg2; +- (void)chat:(id)arg1 propertiesUpdated:(id)arg2; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 member:(id)arg5 statusChanged:(int)arg6; +- (void)leftChat:(id)arg1; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 groupID:(id)arg5 chatPersonCentricID:(id)arg6 statusChanged:(int)arg7 handleInfo:(id)arg8; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 error:(id)arg5; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 updateProperties:(id)arg5; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 invitationReceived:(id)arg5; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 groupID:(id)arg5 chatPersonCentricID:(id)arg6 messagesReceived:(id)arg7; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 groupID:(id)arg5 chatPersonCentricID:(id)arg6 messageReceived:(id)arg7; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 notifySentMessage:(id)arg5 sendTime:(id)arg6; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 groupID:(id)arg5 chatPersonCentricID:(id)arg6 messageSent:(id)arg7; +- (void)_processMessageForAccount:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 groupID:(id)arg5 chatPersonCentricID:(id)arg6 message:(id)arg7; +- (id)_existingChatForChatStyle:(unsigned char)arg1 groupID:(id)arg2 chatIdentifier:(id)arg3 accountID:(id)arg4; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 messageUpdated:(id)arg5; +- (void)account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 messagesUpdated:(id)arg5; +- (void)_account:(id)arg1 chat:(id)arg2 style:(unsigned char)arg3 chatProperties:(id)arg4 messagesUpdated:(id)arg5; +- (void)loadedChats:(id)arg1; +- (void)_startBackgroundProcessingChats:(id)arg1 completion:(CDUnknownBlockType)arg2; +- (void)mergeWithCopyRegistry:(id)arg1; +- (id)copyForBatchProcessing; +- (void)enumerateAllChatsAndIncludingSyncedAttachmentSizes:(BOOL)arg1 usingBlock:(CDUnknownBlockType)arg2; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly) unsigned long long hash; +@property(readonly) Class superclass; + +@end + +@interface IMSimulatedChat : IMChat // +{ +// id _delegate; + IMSimulatedAccount *_simulatedAccount; + unsigned long long _currentMessageID; + NSString *_simulatedChatIdentifier; + NSMutableArray *_simulatedAttachments; + NSString *_simulatedDisplayName; +} + +@property(copy, nonatomic) NSString *simulatedDisplayName; // @synthesize simulatedDisplayName=_simulatedDisplayName; +@property(readonly, nonatomic) NSMutableArray *simulatedAttachments; // @synthesize simulatedAttachments=_simulatedAttachments; +@property(copy, nonatomic) NSString *simulatedChatIdentifier; // @synthesize simulatedChatIdentifier=_simulatedChatIdentifier; +@property(readonly, nonatomic) unsigned long long currentMessageID; // @synthesize currentMessageID=_currentMessageID; +@property(readonly, nonatomic) IMSimulatedAccount *simulatedAccount; // @synthesize simulatedAccount=_simulatedAccount; +//@property(nonatomic) __weak id delegate; // @synthesize delegate=_delegate; + +- (id)_messageWithGUID:(id)arg1; +- (void)simulatedDaemon:(id)arg1 willSendBalloonPayload:(id)arg2 attachments:(id)arg3 messageGUID:(id)arg4 bundleID:(id)arg5; +- (void)chat:(id)arg1 didSendMessage:(id)arg2; +- (void)markAsAutoSpamReported; +- (id)attachments; +- (id)loadMessagesBeforeDate:(id)arg1 limit:(unsigned long long)arg2 loadImmediately:(BOOL)arg3; +- (long long)joinState; +- (void)setDisplayName:(id)arg1; +- (id)displayName; +- (id)account; +- (id)chatIdentifier; +- (BOOL)_handleIncomingItem:(id)arg1; +- (void)sendMessage:(id)arg1; +- (id)initWithIncomingIDs:(id)arg1 messageIDOffset:(unsigned long long)arg2 account:(id)arg3; + +@end + +@interface IMOneTimeCodeAccelerator : NSObject +{ + BOOL _requestedOneTimeCodeStatusForConnection; + IMDaemonController *_daemon; + CDUnknownBlockType _updateBlock; +} + +@property(nonatomic) BOOL requestedOneTimeCodeStatusForConnection; // @synthesize requestedOneTimeCodeStatusForConnection=_requestedOneTimeCodeStatusForConnection; +@property(copy, nonatomic) CDUnknownBlockType updateBlock; // @synthesize updateBlock=_updateBlock; +@property(retain, nonatomic) IMDaemonController *daemon; // @synthesize daemon=_daemon; + +- (void)daemonConnectionLost; +- (void)daemonControllerDidDisconnect; +- (void)daemonControllerDidConnect; +- (void)daemonControllerWillConnect; +- (void)_incomingCodeUpdateFromDaemon:(id)arg1; +- (void)setUpConnectionToDaemaon; +- (void)dealloc; +- (id)initWithDaemon:(id)arg1 andBlock:(CDUnknownBlockType)arg2; +- (void)consumeCodeWithGuid:(id)arg1; +- (id)initWithBlockForUpdates:(CDUnknownBlockType)arg1; + +@end + +@interface IMPersonRegistrar : NSObject +{ + NSMutableDictionary *_personMap; +} + ++ (id)sharedInstance; +@property(retain) NSMutableDictionary *_personMap; // @synthesize _personMap; + +- (void)_dumpAllPersons; +- (id)personForUniqueID:(id)arg1; +- (void)unregisterPerson:(id)arg1; +- (void)registerPerson:(id)arg1; + +@end + +@interface IMCloudKitSyncProgress : NSObject +{ + BOOL _shouldShowProgressBar; + BOOL _shouldShowIndeterminateProgress; + BOOL _shouldShowUserActionLabel; + BOOL _shouldShowUserMessageLabel; + NSString *_progressLabel; + double _progressBarValue; + double _progressBarMax; + NSString *_userMessageLabel; + NSString *_actionLabel; + long long _actionType; + IMCloudKitSyncState *_syncState; +// IMCloudKitSyncStatistics *_syncStatistics; + double _broadcastDeferralOverride; +} + +@property(nonatomic) double broadcastDeferralOverride; // @synthesize broadcastDeferralOverride=_broadcastDeferralOverride; +//@property(readonly, nonatomic) IMCloudKitSyncStatistics *syncStatistics; // @synthesize syncStatistics=_syncStatistics; +@property(readonly, nonatomic) IMCloudKitSyncState *syncState; // @synthesize syncState=_syncState; +@property(nonatomic) long long actionType; // @synthesize actionType=_actionType; +@property(retain, nonatomic) NSString *actionLabel; // @synthesize actionLabel=_actionLabel; +@property(retain, nonatomic) NSString *userMessageLabel; // @synthesize userMessageLabel=_userMessageLabel; +@property(nonatomic) BOOL shouldShowUserMessageLabel; // @synthesize shouldShowUserMessageLabel=_shouldShowUserMessageLabel; +@property(nonatomic) BOOL shouldShowUserActionLabel; // @synthesize shouldShowUserActionLabel=_shouldShowUserActionLabel; +@property(nonatomic) double progressBarMax; // @synthesize progressBarMax=_progressBarMax; +@property(nonatomic) double progressBarValue; // @synthesize progressBarValue=_progressBarValue; +@property(nonatomic) BOOL shouldShowIndeterminateProgress; // @synthesize shouldShowIndeterminateProgress=_shouldShowIndeterminateProgress; +@property(nonatomic) BOOL shouldShowProgressBar; // @synthesize shouldShowProgressBar=_shouldShowProgressBar; +@property(retain, nonatomic) NSString *progressLabel; // @synthesize progressLabel=_progressLabel; + +@property(readonly, nonatomic, getter=isHidden) BOOL hidden; // @dynamic hidden; +@property(readonly, nonatomic) NSArray *errors; // @dynamic errors; +@property(readonly, nonatomic) double remainingItems; // @dynamic remainingItems; +@property(readonly, nonatomic) double percentComplete; // @dynamic percentComplete; +- (id)description; +- (void)configureSelf; +@property(readonly, nonatomic) NSString *percentCompleteString; // @dynamic percentCompleteString; +- (id)initWithSyncState:(id)arg1 syncStatistics:(id)arg2; +- (id)init; + +@end + +@interface IMCloudKitSyncProgressIsSyncing : IMCloudKitSyncProgress +{ +} + +- (void)configureSelf; + +@end + +@interface IMCloudKitPausedSyncProgress : IMCloudKitSyncProgress +{ +} + +- (void)configureSelf; + +@end + +@interface IMCloudKitAccountNeedsRepairSyncProgress : IMCloudKitSyncProgress +{ +} + +- (void)configureSelf; + +@end + +@interface IMCloudKitDeviceStorageIsFullSyncProgress : IMCloudKitSyncProgress +{ +} + +- (void)configureSelf; + +@end + +@interface IMCloudKitCloudKitStorageIsFullSyncProgress : IMCloudKitSyncProgress +{ +} + +- (void)configureSelf; + +@end + +@interface IMCloudKitHiddenSyncProgress : IMCloudKitSyncProgress +{ +} + +- (id)description; +- (BOOL)isHidden; + +@end + +@interface IMCloudKitKeyRollPendingErrorProgress : IMCloudKitSyncProgress +{ +} + +- (void)configureSelf; + +@end + +@interface IMAddressBook : NSObject +{ +} + ++ (BOOL)addressBookEnabled; ++ (void)setAddressBookEnabled:(BOOL)arg1; ++ (id)abAddressBook; ++ (void)_watchLocaleChanges; ++ (void)_localeChanged:(id)arg1; + +@end + + +@interface IMBalloonApp : NSObject +{ + BOOL _isBetaPlugin; + BOOL _isLaunchProhibited; + BOOL _isStickerPackOnly; + BOOL _showInBrowser; + BOOL _shouldBalloonHideAppIcon; + BOOL _shouldHideAppSwitcher; + BOOL _canSendDataPayloads; + BOOL _pluginLoaded; + Class _browserClass; + Class _dataSourceClass; + Class _customTypingIndicatorLayerClass; + Class _bubbleClass; + Class _entryClass; + NSBundle *_appBundle; + NSBundle *_pluginBundle; + NSNumber *_itemID; + NSString *_browserDisplayName; + NSString *_identifier; + NSString *_version; +// id _plugin; + unsigned long long _presentationContexts; +} + ++ (unsigned long long)presentationContextsForInfoPlistArray:(id)arg1 isStickerPackOnly:(BOOL)arg2; ++ (void)_setUnremovableDisabledApps:(id)arg1; ++ (id)_unremovableDisabledApps; ++ (id)appWithPluginBundle:(id)arg1 appBundle:(id)arg2; ++ (id)appWithPluginBundle:(id)arg1; ++ (id)appWithPluginBundle:(id)arg1 extension:(id)arg2; ++ (id)appWithPluginBundle:(id)arg1 pluginKitProxy:(id)arg2 extension:(id)arg3; +@property(nonatomic) BOOL pluginLoaded; // @synthesize pluginLoaded=_pluginLoaded; +@property(nonatomic) unsigned long long presentationContexts; // @synthesize presentationContexts=_presentationContexts; +//@property(retain, nonatomic) id plugin; // @synthesize plugin=_plugin; +@property(readonly, nonatomic) NSString *version; // @synthesize version=_version; +@property(retain, nonatomic) NSString *identifier; // @synthesize identifier=_identifier; +@property(retain, nonatomic) NSString *browserDisplayName; // @synthesize browserDisplayName=_browserDisplayName; +@property(retain, nonatomic) NSNumber *itemID; // @synthesize itemID=_itemID; +@property(retain, nonatomic) NSBundle *pluginBundle; // @synthesize pluginBundle=_pluginBundle; +@property(retain, nonatomic) NSBundle *appBundle; // @synthesize appBundle=_appBundle; +@property(nonatomic) BOOL canSendDataPayloads; // @synthesize canSendDataPayloads=_canSendDataPayloads; +@property(nonatomic) BOOL shouldHideAppSwitcher; // @synthesize shouldHideAppSwitcher=_shouldHideAppSwitcher; +@property(nonatomic) BOOL shouldBalloonHideAppIcon; // @synthesize shouldBalloonHideAppIcon=_shouldBalloonHideAppIcon; +@property(nonatomic) BOOL showInBrowser; // @synthesize showInBrowser=_showInBrowser; +@property(readonly, nonatomic) BOOL isStickerPackOnly; // @synthesize isStickerPackOnly=_isStickerPackOnly; +@property(nonatomic) BOOL isLaunchProhibited; // @synthesize isLaunchProhibited=_isLaunchProhibited; +@property(readonly, nonatomic) BOOL isBetaPlugin; // @synthesize isBetaPlugin=_isBetaPlugin; +@property(retain, nonatomic) Class entryClass; // @synthesize entryClass=_entryClass; +@property(retain, nonatomic) Class bubbleClass; // @synthesize bubbleClass=_bubbleClass; +@property(retain, nonatomic) Class customTypingIndicatorLayerClass; // @synthesize customTypingIndicatorLayerClass=_customTypingIndicatorLayerClass; +@property(retain, nonatomic) Class dataSourceClass; // @synthesize dataSourceClass=_dataSourceClass; +@property(retain, nonatomic) Class browserClass; // @synthesize browserClass=_browserClass; + +@property(nonatomic) BOOL isEnabled; +- (id)proxyWithErrorHandle:(CDUnknownBlockType)arg1; +- (id)extensionConnection; +- (void)_loadBundle; +- (id)initWithPluginBundle:(id)arg1 appBundle:(id)arg2; + +@end + +@interface IMActionsController : NSObject +{ +} + ++ (id)actionsController; + +@end + +@interface IMIDStatusController : NSObject +{ + NSRecursiveLock *_servicesLock; + NSMutableSet *_servicesRegistered; +} + ++ (id)sharedInstance; +@property(retain, nonatomic) NSMutableSet *_servicesRegistered; // @synthesize _servicesRegistered; +@property(retain, nonatomic) NSRecursiveLock *_servicesLock; // @synthesize _servicesLock; + +- (long long)statusForID:(id)arg1 onService:(id)arg2; +- (void)requestStatusForID:(id)arg1 onAccount:(id)arg2; +- (void)requestStatusForID:(id)arg1 onService:(id)arg2; +- (void)_requestStatusForID:(id)arg1 onService:(id)arg2 onAccount:(id)arg3; +- (long long)_idStatusForID:(id)arg1 onAccount:(id)arg2; +- (long long)_statusForCanonicalizedID:(id)arg1 onService:(id)arg2; +- (long long)_idStatusForID:(id)arg1 onService:(id)arg2; +- (long long)__statusForID:(id)arg1 onService:(id)arg2 isCanonicalized:(BOOL)arg3; +- (void)_processIDStatusResponseForURI:(id)arg1 resultStatus:(long long)arg2 forService:(id)arg3; +- (id)init; + +@end + +@interface IMBalloonPlugin : NSObject +{ + BOOL _pluginLoaded; + NSString *_browserImageName; + NSString *_browserImagePath; + long long _browserGroup; + NSBundle *_bundle; +// id _plugin; + IMBalloonApp *_app; + NSMutableDictionary *_messageToDatasourceMap; + NSMutableDictionary *_messageToBalloonControllerMap; + Class _bubbleClass; + Class _browserClass; + Class _dataSourceClass; + Class _customTypingIndicatorLayerClass; + Class _entryClass; + NSMutableArray *_balloonControllerPool; +} + +@property(retain, nonatomic) NSMutableArray *balloonControllerPool; // @synthesize balloonControllerPool=_balloonControllerPool; +@property(retain, nonatomic) Class entryClass; // @synthesize entryClass=_entryClass; +@property(retain, nonatomic) Class customTypingIndicatorLayerClass; // @synthesize customTypingIndicatorLayerClass=_customTypingIndicatorLayerClass; +@property(retain, nonatomic) Class dataSourceClass; // @synthesize dataSourceClass=_dataSourceClass; +@property(retain, nonatomic) Class browserClass; // @synthesize browserClass=_browserClass; +@property(retain, nonatomic) Class bubbleClass; // @synthesize bubbleClass=_bubbleClass; +@property(retain, nonatomic) NSMutableDictionary *messageToBalloonControllerMap; // @synthesize messageToBalloonControllerMap=_messageToBalloonControllerMap; +@property(retain, nonatomic) NSMutableDictionary *messageToDatasourceMap; // @synthesize messageToDatasourceMap=_messageToDatasourceMap; +@property(retain, nonatomic) IMBalloonApp *app; // @synthesize app=_app; +@property(nonatomic) BOOL pluginLoaded; // @synthesize pluginLoaded=_pluginLoaded; +//@property(retain, nonatomic) id plugin; // @synthesize plugin=_plugin; +@property(retain, nonatomic) NSBundle *bundle; // @synthesize bundle=_bundle; +@property(nonatomic) long long browserGroup; // @synthesize browserGroup=_browserGroup; +@property(retain, nonatomic) NSString *browserImagePath; // @synthesize browserImagePath=_browserImagePath; +@property(retain, nonatomic) NSString *browserImageName; // @synthesize browserImageName=_browserImageName; + +@property(readonly, nonatomic) unsigned long long presentationContexts; +- (void)setIdentifier:(id)arg1; +@property(readonly, retain, nonatomic) NSBundle *pluginBundle; +@property(readonly, retain, nonatomic) NSBundle *appBundle; +@property(readonly, retain, nonatomic) NSString *browserDisplayName; +- (BOOL)isStickerPackOnly; +@property(readonly, nonatomic) BOOL shouldHideAppSwitcher; +@property(readonly, nonatomic) BOOL isEnabled; +@property(readonly, nonatomic) BOOL showInBrowser; +@property(readonly, nonatomic, getter=isBetaPlugin) BOOL betaPlugin; +@property(readonly, nonatomic) NSString *version; +@property(readonly, retain, nonatomic) NSString *identifier; +- (id)dataSourceForPluginPayload:(id)arg1; +- (void)insertDataSource:(id)arg1 forGUID:(id)arg2; +- (id)existingDataSourceForMessageGUID:(id)arg1; +- (BOOL)supportsControllerReuse; +- (void)removeController:(id)arg1 forChatItem:(id)arg2; +- (void)moveController:(id)arg1 toReusePoolFromChatItem:(id)arg2; +- (id)balloonControllerForChatItem:(id)arg1; +- (id)existingBalloonControllerWithMessageGUID:(id)arg1; +- (id)_getControllerFromReusePoolForChatItem:(id)arg1; +- (void)unloadBundle; +- (void)dealloc; +- (id)initWithBundle:(id)arg1 app:(id)arg2; +- (id)initWithBundle:(id)arg1; +- (id)init; + +@end + +@interface IMBalloonBrowserPlugin : IMBalloonPlugin +{ +} + +- (BOOL)isBetaPlugin; +- (id)version; +- (id)initWithIdentifier:(id)arg1 browserDisplayName:(id)arg2 browserImageName:(id)arg3 browserClass:(Class)arg4 presentationContext:(unsigned long long)arg5; +- (id)initWithIdentifier:(id)arg1 browserDisplayName:(id)arg2 browserImageName:(id)arg3; + +@end + +@interface IMBalloonAppExtension : IMBalloonPlugin +{ + BOOL _canSendDataPayloads; + BOOL _shouldBalloonHideAppIcon; +// NSExtension *_extension; +// LSPlugInKitProxy *_proxy; + NSUUID *_requestIdentifier; +} + +@property(nonatomic) BOOL shouldBalloonHideAppIcon; // @synthesize shouldBalloonHideAppIcon=_shouldBalloonHideAppIcon; +@property(nonatomic) BOOL canSendDataPayloads; // @synthesize canSendDataPayloads=_canSendDataPayloads; +@property NSUUID *requestIdentifier; // @synthesize requestIdentifier=_requestIdentifier; +//@property(retain, nonatomic) LSPlugInKitProxy *proxy; // @synthesize proxy=_proxy; +//@property(readonly, retain, nonatomic) NSExtension *extension; // @synthesize extension=_extension; + +@property(readonly, retain, nonatomic) NSNumber *itemID; +@property(readonly, nonatomic) BOOL isLaunchProhibited; +//@property(readonly, retain, nonatomic) id plugin; +- (BOOL)isBetaPlugin; +- (id)version; +- (id)proxyWithErrorHandle:(CDUnknownBlockType)arg1; +- (id)extensionConnection; +- (id)initWithPluginBundle:(id)arg1 appBundle:(id)arg2; +- (id)_initWithPluginBundle:(id)arg1 extension:(id)arg2 pluginKitProxyClass:(Class)arg3; +- (id)initWithPluginBundle:(id)arg1 extension:(id)arg2; +- (id)initWithPluginBundle:(id)arg1 pluginKitProxy:(id)arg2 extension:(id)arg3; + +@end + +@interface IMBalloonPluginManager : NSObject +{ + NSMutableDictionary *_pluginsMap; + id _extensionMatchingContext; + NSString *_pluginMetaDataFolder; + NSMutableDictionary *_pluginIDToMetadataCache; + NSMutableSet *_pluginsToRemoveAfterExtensionsUpdate; +} + ++ (BOOL)isRunningPPT; ++ (void)setIsRunningPPT:(BOOL)arg1; ++ (id)_extensionBlacklist; ++ (id)sharedInstance; +@property(retain, nonatomic) NSMutableSet *pluginsToRemoveAfterExtensionsUpdate; // @synthesize pluginsToRemoveAfterExtensionsUpdate=_pluginsToRemoveAfterExtensionsUpdate; +@property(retain, nonatomic) NSMutableDictionary *pluginIDToMetadataCache; // @synthesize pluginIDToMetadataCache=_pluginIDToMetadataCache; +@property(retain, nonatomic) NSString *pluginMetaDataFolder; // @synthesize pluginMetaDataFolder=_pluginMetaDataFolder; +@property(retain, nonatomic) id extensionMatchingContext; // @synthesize extensionMatchingContext=_extensionMatchingContext; +@property(retain, nonatomic) NSMutableDictionary *pluginsMap; // @synthesize pluginsMap=_pluginsMap; + +- (id)balloonPluginForBundleID:(id)arg1; +- (id)allPlugins; +- (void)insertDataSource:(id)arg1 forGUID:(id)arg2; +- (id)existingDataSourceForMessageGUID:(id)arg1 bundleID:(id)arg2; +- (id)dataSourceForPluginPayload:(id)arg1; +- (id)_fallBackMessagesExtensionPluginForBundleID:(id)arg1; +- (Class)dataSourceClassForBundleID:(id)arg1; +- (void)_loadAllDataSources; +- (void)_findPluginsInPathInternal:(id)arg1; +- (void)_findPluginsInPaths:(id)arg1; +- (void)_moveExtensionDataSourcesFromMessagesExtensionPluginToAppExtensions; +- (BOOL)_isExtensionBlackListed:(id)arg1; +- (BOOL)_isServerBlackListedBundle:(id)arg1 serverBag:(id)arg2; +- (void)setPluginEnabled:(BOOL)arg1 identifier:(id)arg2; +- (void)_removePluginsForIdentifiers:(id)arg1; +- (void)_removePluginsWithDelay; +- (void)removePluginWithBundleID:(id)arg1; +- (id)_insertPluginForExtension:(id)arg1 balloonProviderBundle:(id)arg2 andTimingCollection:(id)arg3; +- (id)_insertPluginForAppBundle:(id)arg1 balloonProviderBundle:(id)arg2; +- (void)_updatePluginsForExtensions:(id)arg1; +- (void)_updatePluginsForBundles:(id)arg1; +- (void)_setPluginsToRemoveAndCallSelectorWithDelay:(id)arg1; +- (id)_appProxyBundleIdentifiersForAppPlugins; +- (void)_loadAppBundleDataSources; +- (void)_loadAppExtensionDataSources; +- (void)_clearPluginMetadataForUninstalledApps; +- (void)_deleteMetaDataForPlugins:(id)arg1; +- (id)_pluginsForWhichWeHaveMetadata; +- (id)_proxyIdentifiersForPlugins; +- (id)_identifiersForAppPlugins; +- (id)conversationID:(id)arg1 appID:(id)arg2; +- (id)recipientIDForRecipient:(id)arg1 appID:(id)arg2; +- (id)localParticipantIdentifierForAppID:(id)arg1 conversationID:(id)arg2; +- (void)_storeMetadata:(id)arg1 _forPlugin:(id)arg2; +- (id)_metadataForPluginIdentifier:(id)arg1; +- (id)_infoPlistPathForPluginCreatingFolderIfNeeded:(id)arg1; +- (id)_pluginPlistPath:(id)arg1; +- (void)dealloc; +- (void)pluginChatItem:(id)arg1 didRelenquishNonResuableController:(id)arg2; +- (void)pluginChatItem:(id)arg1 didRelinquishReusableController:(id)arg2; +- (id)init; + +@end + +@interface IMChatHistoryController : NSObject +{ + NSMutableDictionary *_runningQueries; +} + ++ (id)sharedInstance; +@property(retain) NSMutableDictionary *_runningQueries; // @synthesize _runningQueries; + +- (void)databaseNoLongerFull; +- (void)databaseFull; +- (void)messageQuery:(id)arg1 finishedWithResult:(id)arg2 chatGUIDs:(id)arg3; +- (void)loadMessageWithGUID:(id)arg1 completionBlock:(CDUnknownBlockType)arg2; +- (void)dealloc; +- (id)init; + +@end + +@interface IMCoreAutomationHook : NSObject +{ + IMAccount *_imessageAccount; +} + ++ (id)stringFromAutomationErrorCode:(long long)arg1; + +- (id)existingChatForGroupID:(id)arg1 error:(id *)arg2 results:(id)arg3; +- (id)handlesFromStrings:(id)arg1 error:(id *)arg2 results:(id)arg3; +- (id)chatForHandles:(id)arg1 error:(id *)arg2 results:(id)arg3; +@property(readonly) IMAccount *bestiMessageAccount; + +@end + +@interface IMDDController : NSObject +{ + NSObject *_scannerQueue; +} + ++ (id)sharedInstance; + +- (void)scanMessage:(id)arg1 waitUntilDone:(BOOL)arg2 completionBlock:(CDUnknownBlockType)arg3; +- (BOOL)_scanMessageUsingScanner:(id)arg1 attributedString:(id)arg2; +- (void)scanMessage:(id)arg1 completionBlock:(CDUnknownBlockType)arg2; +- (id)scannerQueue; +- (struct __DDScanner *)sharedScanner; +- (id)init; + +@end + +@interface IMAutomationMessageSend : NSObject +{ + NSMutableSet *_pendingSendGUIDs; + NSMutableDictionary *_sentMessageInfo; +} + +@property(retain, nonatomic) NSMutableDictionary *sentMessageInfo; // @synthesize sentMessageInfo=_sentMessageInfo; +@property(retain, nonatomic) NSMutableSet *pendingSendGUIDs; // @synthesize pendingSendGUIDs=_pendingSendGUIDs; + +- (id)dictionaryFromGUID:(id)arg1; +- (id)fileSizeForMessageGUID:(id)arg1 withFilePathIndex:(long long)arg2; +- (id)uploadAttachmentToCloudkitWithMessageGUID:(id)arg1 andFilePathIndex:(long long)arg2; +- (id)clearAttachmentsUploadedToCloudkit; +- (id)deleteAttachmentWithMessageGUID:(id)arg1 andFilePathIndex:(long long)arg2; +- (id)loadHighResolutionFileForMessageGUID:(id)arg1 withFilePathIndex:(long long)arg2; +- (id)sendIMMessage:(id)arg1 chat:(id)arg2 timeOut:(double)arg3 resultDict:(id)arg4 error:(id *)arg5; +- (id)sendMessage:(id)arg1 destinationID:(id)arg2 filePaths:(id)arg3 groupID:(id)arg4 bundleID:(id)arg5 attributionInfoName:(id)arg6 service:(id)arg7 timeOut:(double)arg8 error:(id *)arg9; +- (id)sendMessage:(id)arg1 destinationID:(id)arg2 filePaths:(id)arg3 groupID:(id)arg4 service:(id)arg5 timeOut:(double)arg6 error:(id *)arg7; +- (id)createIMMessageToSendWithMessage:(id)arg1 filePaths:(id)arg2 bundleID:(id)arg3 attributionInfoName:(id)arg4; +- (id)init; +- (id)appendFilePathsWithGUIDs:(id)arg1 withText:(id)arg2; +- (void)deleteTmpFilePath:(id)arg1; +- (id)copyFilePathsToTmpLocation:(id)arg1; + +@end + +@interface IMSimulatedAccountController : IMAccountController +{ + NSMutableDictionary *_simulatedAccountsPerService; +} + + +- (id)init; +- (id)activeSMSAccount; +- (id)activeIMessageAccount; +- (id)activeAccounts; +- (void)setSimulatedAccounts:(id)arg1 forServiceNamed:(id)arg2; + +@end + +@interface IMSPIHandle : NSObject +{ + NSString *_address; + NSString *_countryCode; + BOOL _isMe; + IMPerson *_imPerson; + BOOL _haveFetchedIMPerson; +} + +@property(readonly) BOOL isMe; // @synthesize isMe=_isMe; +@property(readonly) NSString *countryCode; // @synthesize countryCode=_countryCode; +@property(readonly) NSString *address; // @synthesize address=_address; + +- (unsigned long long)hash; +- (BOOL)isEqual:(id)arg1; +@property(readonly) NSString *cnContactID; +@property(readonly) NSString *displayName; +- (id)person; +@property(readonly) NSString *businessName; +@property(readonly) BOOL isBusiness; +- (id)description; +- (id)initWithAddress:(id)arg1 countryCode:(id)arg2 isMe:(BOOL)arg3; + +@end + +@interface IMSPIRecentEvent : NSObject +{ + NSString *_handle; + NSDate *_date; + NSString *_labelID; +} + +@property(retain) NSString *labelID; // @synthesize labelID=_labelID; +@property(retain) NSDate *date; // @synthesize date=_date; +@property(retain) NSString *handle; // @synthesize handle=_handle; + +- (id)description; +- (id)initWithLabelID:(id)arg1 date:(id)arg2; +- (id)initWithHandle:(id)arg1 date:(id)arg2; + +@end + +@interface IMSPIAttachment : NSObject +{ + NSString *_guid; + NSURL *_fileUrl; + long long _fileTransferState; + NSString *_uti; + BOOL _isSticker; + BOOL _isOutgoing; + NSDictionary *_attributionInfo; +} + +@property(retain) NSDictionary *attributionInfo; // @synthesize attributionInfo=_attributionInfo; +@property BOOL isOutgoing; // @synthesize isOutgoing=_isOutgoing; +@property BOOL isSticker; // @synthesize isSticker=_isSticker; +@property(retain) NSString *uti; // @synthesize uti=_uti; +@property(retain) NSString *guid; // @synthesize guid=_guid; +@property long long fileTransferState; // @synthesize fileTransferState=_fileTransferState; +@property(retain) NSURL *fileUrl; // @synthesize fileUrl=_fileUrl; + +- (id)description; +- (id)bundleID; +- (id)initWithGuid:(id)arg1 fileUrl:(id)arg2 transferState:(long long)arg3 uti:(id)arg4 isSticker:(BOOL)arg5 isOutgoing:(BOOL)arg6 attributionInfo:(id)arg7; + +@end + +@interface IMSPIMessage : NSObject +{ + NSString *_guid; + NSArray *_chatGuids; + NSString *_text; + NSAttributedString *_attributedText; + NSString *_subject; + NSString *_effect; + NSArray *_recipients; + NSDate *_date; + NSDate *_dateRead; + NSDate *_lastReadDate; + IMSPIHandle *_sender; + long long _messageID; + NSArray *_attachments; + BOOL _isOutgoing; + BOOL _isRead; + BOOL _isAudioMessage; + BOOL _isGroupChat; + long long _itemType; + NSString *_groupID; + NSString *_chatIdentifier; + NSString *_displayName; + NSString *_service; + IMSPIMessage *_referencedMessage; + NSString *_bundleId; + long long _messageType; + NSString *_displayAppName; +// LPLinkMetadata *_richLinkMetadata; +// PKCurrencyAmount *_peerPaymentAmount; +} + +//@property(retain) PKCurrencyAmount *peerPaymentAmount; // @synthesize peerPaymentAmount=_peerPaymentAmount; +//@property(retain) LPLinkMetadata *richLinkMetadata; // @synthesize richLinkMetadata=_richLinkMetadata; +@property(retain) NSString *displayAppName; // @synthesize displayAppName=_displayAppName; +@property long long messageType; // @synthesize messageType=_messageType; +@property(retain) NSString *bundleId; // @synthesize bundleId=_bundleId; +@property(retain) IMSPIMessage *referencedMessage; // @synthesize referencedMessage=_referencedMessage; +@property(retain) NSDate *lastReadDate; // @synthesize lastReadDate=_lastReadDate; +@property(retain) NSDate *dateRead; // @synthesize dateRead=_dateRead; +@property(retain) NSString *service; // @synthesize service=_service; +@property(retain) NSString *displayName; // @synthesize displayName=_displayName; +@property(retain) NSString *effect; // @synthesize effect=_effect; +@property BOOL isGroupChat; // @synthesize isGroupChat=_isGroupChat; +@property(retain) NSString *chatIdentifier; // @synthesize chatIdentifier=_chatIdentifier; +@property(retain) NSString *groupID; // @synthesize groupID=_groupID; +@property long long itemType; // @synthesize itemType=_itemType; +@property(retain) NSArray *attachments; // @synthesize attachments=_attachments; +@property(retain) NSArray *chatGuids; // @synthesize chatGuids=_chatGuids; +@property BOOL isAudioMessage; // @synthesize isAudioMessage=_isAudioMessage; +@property(retain) NSDate *date; // @synthesize date=_date; +@property(retain) NSString *subject; // @synthesize subject=_subject; +@property(retain) NSArray *recipients; // @synthesize recipients=_recipients; +@property(retain) IMSPIHandle *sender; // @synthesize sender=_sender; +@property(retain) NSString *text; // @synthesize text=_text; +@property BOOL isOutgoing; // @synthesize isOutgoing=_isOutgoing; +@property BOOL isRead; // @synthesize isRead=_isRead; +@property(retain) NSAttributedString *attributedText; // @synthesize attributedText=_attributedText; +@property long long messageID; // @synthesize messageID=_messageID; +@property(retain) NSString *guid; // @synthesize guid=_guid; + +@property(readonly) NSURL *url; +- (id)description; +- (void)dealloc; + +@end + +@interface IMPluginPayload : NSObject +{ + BOOL _update; + BOOL _sticker; + BOOL _shouldExpire; + BOOL _isPlayed; + BOOL _isFromMe; + NSAttributedString *_text; + NSData *_data; + NSURL *_url; + NSString *_breadcrumbText; + NSString *_statusText; + NSDictionary *_userInfo; + NSString *_messageGUID; + NSDate *_time; + NSString *_associatedMessageGUID; + NSString *_pluginBundleID; + NSArray *_consumedSessionPayloads; + NSString *_pluginSessionGUID; +// DDScannerResult *_dataDetectedResult; + NSArray *_attachments; + IMBalloonPluginDataSource *_datasource; + NSString *_sender; +} + ++ (BOOL)supportsSecureCoding; +@property(copy, nonatomic) NSString *sender; // @synthesize sender=_sender; +@property(nonatomic) BOOL isFromMe; // @synthesize isFromMe=_isFromMe; +@property(nonatomic) __weak IMBalloonPluginDataSource *datasource; // @synthesize datasource=_datasource; +@property(retain, nonatomic) NSArray *attachments; // @synthesize attachments=_attachments; +//@property(retain, nonatomic) DDScannerResult *dataDetectedResult; // @synthesize dataDetectedResult=_dataDetectedResult; +@property(retain, nonatomic) NSString *pluginSessionGUID; // @synthesize pluginSessionGUID=_pluginSessionGUID; +@property(nonatomic) BOOL isPlayed; // @synthesize isPlayed=_isPlayed; +@property(retain, nonatomic) NSArray *consumedSessionPayloads; // @synthesize consumedSessionPayloads=_consumedSessionPayloads; +@property(retain, nonatomic) NSString *pluginBundleID; // @synthesize pluginBundleID=_pluginBundleID; +@property(retain, nonatomic) NSString *associatedMessageGUID; // @synthesize associatedMessageGUID=_associatedMessageGUID; +@property(retain, nonatomic) NSDate *time; // @synthesize time=_time; +@property(retain, nonatomic) NSString *messageGUID; // @synthesize messageGUID=_messageGUID; +@property(retain, nonatomic) NSDictionary *userInfo; // @synthesize userInfo=_userInfo; +@property(nonatomic) BOOL shouldExpire; // @synthesize shouldExpire=_shouldExpire; +@property(nonatomic, getter=isSticker) BOOL sticker; // @synthesize sticker=_sticker; +@property(nonatomic, getter=isUpdate) BOOL update; // @synthesize update=_update; +@property(retain, nonatomic) NSString *statusText; // @synthesize statusText=_statusText; +@property(retain, nonatomic) NSString *breadcrumbText; // @synthesize breadcrumbText=_breadcrumbText; +@property(retain, nonatomic) NSURL *url; // @synthesize url=_url; +@property(retain, nonatomic) NSData *data; // @synthesize data=_data; +@property(retain, nonatomic) NSAttributedString *text; // @synthesize text=_text; + +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)initWithCoder:(id)arg1; +- (void)encodeWithCoder:(id)arg1; +- (BOOL)isEqual:(id)arg1; +- (unsigned long long)hash; +- (BOOL)isEqualToPluginPayload:(id)arg1; +@property(readonly, nonatomic) BOOL shouldHideAttachments; +- (void)addAttachmentsFromFileTransferGUIDs:(id)arg1; +- (id)initWithMessageItem:(id)arg1; +- (id)initWithMessage:(id)arg1; + +@end + + +@interface IMBalloonPluginAttributionController : NSObject +{ + BOOL _hasPerformedFirstAppExtensionLoad; + NSMutableDictionary *_expiredBundleIDToTimestampMap; + NSMutableDictionary *_bundleIDsDisplayingAttribution; +} + ++ (id)sharedInstance; +@property(nonatomic) BOOL hasPerformedFirstAppExtensionLoad; // @synthesize hasPerformedFirstAppExtensionLoad=_hasPerformedFirstAppExtensionLoad; +@property(retain, nonatomic) NSMutableDictionary *bundleIDsDisplayingAttribution; // @synthesize bundleIDsDisplayingAttribution=_bundleIDsDisplayingAttribution; +@property(retain, nonatomic) NSMutableDictionary *expiredBundleIDToTimestampMap; // @synthesize expiredBundleIDToTimestampMap=_expiredBundleIDToTimestampMap; + +- (void)_handleInstalledPluginsChanged; +- (void)_purgeLeastRecentlySeenAppBundleIDsIfNecessary; +- (void)_saveToFile; +- (double)_expiryTimeout; +- (id)_currentTimestamp; +- (BOOL)shouldShowAttributionForBundleID:(id)arg1; +- (void)didShowAttributionForBundleIDs:(id)arg1; +- (void)startExpiryTimer; +- (void)dealloc; +- (id)init; + +@end + +@interface NSArray (IMItems) +@property(readonly, nonatomic) IMMessageItem *lastMessageItem; +@property(readonly, nonatomic) IMMessageItem *firstMessageItem; +@end + +@interface NSArray (IMTranscriptChatItems) +- (id)indexesOfPartsOfMessageItem:(id)arg1; +- (id)indexesOfPartsOfMessage:(id)arg1; +@end + +@interface IMRecentItemsList (FetchUtilities) +- (void)loadRecentHandwritingsAndStickersWithThumbnailSize:(struct CGSize)arg1 completion:(CDUnknownBlockType)arg2; +- (void)loadRecentHandwritingsWithThumbnailSize:(struct CGSize)arg1 completion:(CDUnknownBlockType)arg2; +- (void)loadRecentStickers:(CDUnknownBlockType)arg1; +@end + +@interface NSArray (IMChatItems) +- (id)__imItems; +- (void)__enumerateItemsWithOptions:(unsigned long long)arg1 usingBlock:(CDUnknownBlockType)arg2; +- (id)__itemForChatItemAtIndex:(unsigned long long)arg1; +@property(readonly, nonatomic) IMMessageItem *__imLastMessageItem; +- (id)messages; +- (void)enumerateMessagesWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(IMMessage *message, BOOL *stop))block; +- (id)messageForChatItemAtIndex:(unsigned long long)arg1; +@property(readonly, nonatomic) IMMessage *lastIncomingFinishedMessage; +@property(readonly, nonatomic) IMMessage *lastIncomingMessage; +@property(readonly, nonatomic) IMMessage *lastFinishedMessage; +@property(readonly, nonatomic) IMMessage *lastMessage; +@property(readonly, nonatomic) IMMessage *firstMessage; +@end + +@interface NSString (IMAdditions) ++ (id)__im_handleIdentifierRegex; +- (id)__im_handleIdentifiers; +- (id)__im_IDForHandleIdentifierString; +- (id)__im_rangesOfHandleIdentifierStrings; +@end + +@interface IMItem (IMChat_Internal) ++ (Class)contextClass; +- (id)_copy; +- (BOOL)_isInvitation; +- (void)_setInvitation:(BOOL)arg1; +- (id)_otherHandle; +- (id)_senderHandle; +- (void)_updateContextWithSenderHandle:(id)arg1 otherHandle:(id)arg2; +- (id)message; +@end + +@interface IMMessageItem (IMChat_Internal) ++ (Class)contextClass; +- (id)_copyWithFlags:(unsigned long long)arg1; +- (id)_copy; +- (BOOL)_isInvitation; +- (void)_setInivtation:(BOOL)arg1; +- (id)message; +@end + +@interface IMMessageItem (IMCoreDescription) +- (id)descriptionForPurpose:(long long)arg1 isGroupMessage:(BOOL)arg2 messageDataSource:(CDUnknownBlockType)arg3 attachmentDataSource:(CDUnknownBlockType)arg4; +@end + +@interface IMItem (IMItemsController) +- (BOOL)isIncomingTypingOrCancelTypingMessage; +- (BOOL)isTypingOrCancelTypingMessage; +@end + +@interface IMMessageItem (IMItemsController) +- (BOOL)isIncomingTypingOrCancelTypingMessage; +- (BOOL)isTypingOrCancelTypingMessage; +- (BOOL)isCancelTypingMessage; +- (BOOL)isIncomingTypingMessage; +- (BOOL)isSystemMessage; +@end + +@interface IMAssociatedMessageItem (IMItemsController) +- (BOOL)isIncomingTypingOrCancelTypingMessage; +- (BOOL)isTypingOrCancelTypingMessage; +- (BOOL)isCancelTypingMessage; +- (BOOL)isIncomingTypingMessage; +@end + +@interface NSString (IMCoreIDSLookupAdditions) +- (id)idsFormat; +@end + + +@interface IMItem (IMTranscriptChatItemRules) +- (BOOL)shouldGenerateTopLevelChatItem; +- (id)_serviceHandle; +- (id)_service; +- (id)_newChatItems; +- (BOOL)_hasMessageChatItem; +@end + +@interface IMMessageItem (IMTranscriptChatItemRules) +- (BOOL)isExtensibleMessageWithPluginPayload:(id *)arg1; +- (id)_service; +- (id)_newChatItemsWithFilteredChat:(BOOL)arg1 isBusiness:(BOOL)arg2 parentChatIsSpam:(BOOL)arg3 hasKnownParticipants:(BOOL)arg4; +- (id)_newChatItems; +- (BOOL)_hasMessageChatItem; +@end + +@interface IMParticipantChangeItem (IMTranscriptChatItemRules) +- (id)_newChatItems; +@end + +@interface IMGroupTitleChangeItem (IMTranscriptChatItemRules) +- (id)_newChatItems; +@end + +@interface IMLocationShareStatusChangeItem (IMTranscriptChatItemRules) +- (id)_newChatItems; +- (BOOL)_hasMessageChatItem; +@end + +@interface IMTUConversationItem (IMTranscriptChatItemRules) +- (BOOL)_hasMessageChatItem; +- (id)_newChatItems; +@end + +@interface IMMessageActionItem (IMTranscriptChatItemRules) +- (id)_newChatItems; +@end + +@interface IMAssociatedMessageItem (IMTranscriptChatItemRules) +- (BOOL)shouldGenerateTopLevelChatItem; +- (id)_newChatItemsWithFilteredChat:(BOOL)arg1 isBusiness:(BOOL)arg2 parentChatIsSpam:(BOOL)arg3 hasKnownParticipants:(BOOL)arg4; +- (id)_newChatItems; +@end + +@interface NSArray (IMHandleUtilities) +- (BOOL)equivalentToRecipients:(id)arg1; +@end + +@interface NSString (IMDDUtilities) +- (struct __CFArray *)copyDDResultArrayByScanningStringForURLs; +@end + diff --git a/Dumped Classes/IMFoundation_ClassDump.h b/Dumped Classes/IMFoundation_ClassDump.h new file mode 100644 index 0000000..18e8613 --- /dev/null +++ b/Dumped Classes/IMFoundation_ClassDump.h @@ -0,0 +1,1900 @@ +// +// Generated by class-dump 3.5 (64 bit). +// +// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard. +// + +#pragma mark Blocks + +typedef void (^CDUnknownBlockType)(void); // return type and parameters are unknown + +#pragma mark Named Structures + + +#pragma mark - + +// +// File: Versions/A/IMFoundation +// UUID: 098F3A98-2184-32EF-8EC9-87B892CD85CA +// +// Arch: x86_64 +// Current version: 800.0.0 +// Compatibility version: 1.0.0 +// Source version: 725.37.0.0.0 +// +// Objective-C Garbage Collection: Unsupported +// + +@protocol IMAVDaemonProtocol +- (void)stopPreview; +- (void)startPreview; +@end + +@class IMConnectionMonitor; +@protocol IMConnectionMonitorDelegate +- (void)connectionMonitorDidUpdate:(IMConnectionMonitor *)arg1; +@end + +@class IMFileCopier; +@protocol IMFileCopierDelegate +- (void)fileCopierDidFinish:(IMFileCopier *)arg1; +- (void)fileCopierDidStart:(IMFileCopier *)arg1; +@end + +@class IMReachability; +@protocol IMReachabilityDelegate +- (void)reachabilityDidChange:(IMReachability *)arg1; +@end + +@protocol IMUserDefaults +- (id)copyValueForKey:(NSString *)arg1 applicationID:(struct __CFString *)arg2 userName:(struct __CFString *)arg3 hostName:(struct __CFString *)arg4; +- (NSDictionary *)copyMultipleForCurrentKeys:(NSArray *)arg1 applicationID:(struct __CFString *)arg2 userName:(struct __CFString *)arg3 hostName:(struct __CFString *)arg4; +- (NSArray *)copyKeyListForApplicationID:(struct __CFString *)arg1 userName:(struct __CFString *)arg2 hostName:(struct __CFString *)arg3; +- (void)synchronizeApplicationID:(struct __CFString *)arg1 userName:(struct __CFString *)arg2 hostName:(struct __CFString *)arg3; +- (void)setMultiple:(NSDictionary *)arg1 remove:(NSArray *)arg2 applicationID:(struct __CFString *)arg3 userName:(struct __CFString *)arg4 hostName:(struct __CFString *)arg5; +- (void)setValue:(void *)arg1 forKey:(NSString *)arg2 applicationID:(struct __CFString *)arg3 userName:(struct __CFString *)arg4 hostName:(struct __CFString *)arg5; +- (id)copyValueForKey:(NSString *)arg1 appID:(NSString *)arg2; +- (NSDictionary *)copyMultipleForCurrentKeys:(NSArray *)arg1 appID:(NSString *)arg2; +- (NSArray *)copyKeyListForAppID:(NSString *)arg1; +- (void)synchronizeAppID:(NSString *)arg1; +- (void)setMultiple:(NSDictionary *)arg1 remove:(NSArray *)arg2 appID:(NSString *)arg3; +- (void)setValue:(void *)arg1 forKey:(NSString *)arg2 appID:(NSString *)arg3; +- (void)setAppBool:(BOOL)arg1 forKey:(NSString *)arg2; +- (BOOL)appBoolForKey:(NSString *)arg1; +- (void)removeAppValueForKey:(NSString *)arg1; +- (void)setAppValue:(id)arg1 forKey:(NSString *)arg2; +- (id)appValueForKey:(NSString *)arg1; +- (void)setAppBool:(BOOL)arg1 byHostForKey:(NSString *)arg2; +- (BOOL)appBoolByHostForKey:(NSString *)arg1; +@end + +@interface IMPair : NSObject +{ + id _first; + id _second; +} + ++ (id)pairWithFirst:(id)arg1 second:(id)arg2; +@property(retain) id second; // @synthesize second=_second; +@property(retain) id first; // @synthesize first=_first; +- (BOOL)isEqual:(id)arg1; +- (unsigned long long)hash; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (void)dealloc; +- (id)initWithFirst:(id)arg1 second:(id)arg2; + +@end + +@interface IMSystemProxySettingsFetcher : NSObject +{ + unsigned short _port; + unsigned short _proxyPort; + id _delegate; + NSString *_host; + long long _proxyProtocol; + NSString *_proxyHost; + NSString *_proxyAccount; + NSString *_proxyPassword; +} + +@property(copy, nonatomic) NSString *_proxyPassword; // @synthesize _proxyPassword; +@property(copy, nonatomic) NSString *_proxyAccount; // @synthesize _proxyAccount; +@property(nonatomic) unsigned short _proxyPort; // @synthesize _proxyPort; +@property(copy, nonatomic) NSString *_proxyHost; // @synthesize _proxyHost; +@property(nonatomic) long long _proxyProtocol; // @synthesize _proxyProtocol; +@property(nonatomic) unsigned short _port; // @synthesize _port; +@property(copy, nonatomic) NSString *_host; // @synthesize _host; +@property id delegate; // @synthesize delegate=_delegate; +- (void)dealloc; +- (void)retrieveProxyAccountSettings; +- (void)retrieveProxySettings; +- (id)initWithProxyProtocol:(long long)arg1 proxyHost:(id)arg2 proxyPort:(unsigned short)arg3 delegate:(id)arg4; +- (id)initWithHost:(id)arg1 port:(unsigned short)arg2 delegate:(id)arg3; +- (void)_takeProxySettingsFromDictionary:(struct __CFDictionary *)arg1; +- (void)_getProxyAccountAndPasswordFromKeychain; +- (void)_callAccountSettingsDelegateMethod; +- (void)_callProxySettingsDelegateMethod; + +@end + +@interface IMInvocationTrampoline : NSObject +{ + id _target; +} + +@property(retain) id target; // @synthesize target=_target; +- (void)forwardInvocation:(id)arg1; +- (BOOL)respondsToSelector:(SEL)arg1; +- (id)methodSignatureForSelector:(SEL)arg1; +- (void)performInvocation:(id)arg1; +- (void)dealloc; + +@end + +@interface IMThreadedInvocationTrampoline : IMInvocationTrampoline +{ + NSThread *_thread; + BOOL _immediateForMatchingThread; +} + +- (void)forwardInvocation:(id)arg1; +- (void)dealloc; +- (id)initWithTarget:(id)arg1 thread:(id)arg2 immediateForMatchingThread:(BOOL)arg3; + +@end + +@interface IMDelayedInvocationTrampoline : IMInvocationTrampoline +{ + NSArray *_modes; + double _delay; +} + +- (void)forwardInvocation:(id)arg1; +- (void)dealloc; +- (id)initWithTarget:(id)arg1 delay:(double)arg2 modes:(id)arg3; + +@end + +@interface IMCapturedInvocationTrampoline : IMInvocationTrampoline +{ +// id *_outInvocation; +} + +- (void)forwardInvocation:(id)arg1; +- (id)initWithTarget:(id)arg1 outInvocation:(id *)arg2; + +@end + +@interface IMFileManager : NSFileManager +{ +} + ++ (id)defaultHFSFileManager; ++ (id)defaultManager; +- (id)UTITypeOfPathExtension:(id)arg1; +- (id)UTITypeOfPath:(id)arg1; +- (id)pathExtensionForUTIType:(id)arg1; +- (id)MIMETypeOfPath:(id)arg1; +- (id)MIMETypeOfPathExtension:(id)arg1; +- (id)UTITypeOfMimeType:(id)arg1; +- (id)pathExtensionForMIMEType:(id)arg1; +- (id)displayNameOfFileWithName:(id)arg1 hfsFlags:(unsigned short)arg2; +- (id)kindStringForFileWithName:(id)arg1 hfsType:(unsigned int)arg2 hfsCreator:(unsigned int)arg3 hfsFlags:(unsigned short)arg4; +- (id)kindStringForFile:(id)arg1; +- (BOOL)setAttributes:(id)arg1 ofItemAtPath:(id)arg2 error:(id *)arg3; +- (id)attributesOfItemAtPath:(id)arg1 error:(id *)arg2; +- (BOOL)existingPath:(id)arg1 toFSSpec:(void *)arg2; +- (BOOL)existingPath:(id)arg1 toFSRef:(void *)arg2; +- (id)createTempFileBasedOnName:(id)arg1 hfsType:(unsigned int)arg2 hfsCreator:(unsigned int)arg3 hfsFlags:(unsigned short)arg4; + +@end + +@interface IMNetworkManager : NSObject +{ +} + ++ (id)sharedInstance; ++ (id)alloc; + +@end + + +@interface IMMobileNetworkManager : IMNetworkManager +{ + BOOL _registered; + BOOL _shouldBringUpDataContext; + BOOL _isDataContextAttached; + BOOL _isDataContextActive; + BOOL _isDataIndicatorNone; + BOOL _isDataContextUsable; + NSRecursiveLock *_lock; + NSMutableSet *_cellAutoAssociationTokens; + NSMutableSet *_wiFiAutoAssociationTokens; +} + +@property(retain, nonatomic) NSMutableSet *wiFiAutoAssociationTokens; // @synthesize wiFiAutoAssociationTokens=_wiFiAutoAssociationTokens; +@property(nonatomic) BOOL isDataContextUsable; // @synthesize isDataContextUsable=_isDataContextUsable; +@property(nonatomic) BOOL isDataIndicatorNone; // @synthesize isDataIndicatorNone=_isDataIndicatorNone; +@property(nonatomic) BOOL isDataContextActive; // @synthesize isDataContextActive=_isDataContextActive; +@property(nonatomic) BOOL isDataContextAttached; // @synthesize isDataContextAttached=_isDataContextAttached; +@property(nonatomic) BOOL shouldBringUpDataContext; // @synthesize shouldBringUpDataContext=_shouldBringUpDataContext; +@property(nonatomic) BOOL registered; // @synthesize registered=_registered; +@property(retain, nonatomic) NSMutableSet *cellularAutoAssociationTokens; // @synthesize cellularAutoAssociationTokens=_cellAutoAssociationTokens; +@property(retain, nonatomic) NSRecursiveLock *lock; // @synthesize lock=_lock; +- (void)setDataConnectionActive:(BOOL)arg1; +@property(readonly, nonatomic) BOOL isDataConnectionActive; +@property(readonly, nonatomic) BOOL isDataSwitchEnabled; +@property(readonly, nonatomic) BOOL hasLTEDataConnection; +@property(readonly, nonatomic) BOOL has2GDataConnection; +@property(readonly, nonatomic) BOOL dataConnectionExists; +- (BOOL)_legacy_inValidSIMState; +@property(readonly, nonatomic) BOOL inValidSIMState; +- (void)showSIMUnlock; +- (id)_telephonyDataSIMStatus; +@property(readonly, nonatomic) BOOL isSIMLocked; +@property(readonly, nonatomic) BOOL isSIMRemoved; +@property(readonly, nonatomic) BOOL requiresSIMInserted; +- (void)_makeDataConnectionAvailable:(BOOL)arg1; +- (BOOL)_isDataConnectionAvailable; +- (void)removeCellularAutoAssociationClientToken:(id)arg1; +- (void)addCellularAutoAssociationClientToken:(id)arg1; +@property(readonly, nonatomic) BOOL autoAssociateCellular; +- (void)showNetworkOptions; +- (void)removeWiFiAutoAssociationClientToken:(id)arg1; +- (void)addWiFiAutoAssociationClientToken:(id)arg1; +@property(readonly, nonatomic) BOOL autoAssociateWiFi; +@property(readonly, nonatomic) BOOL isWiFiCaptive; +@property(readonly, nonatomic) BOOL isWiFiEnabled; +@property(readonly, nonatomic) BOOL isWiFiAssociated; +@property(readonly, nonatomic) BOOL isWiFiUsable; +@property(readonly, retain, nonatomic) NSNumber *wiFiScaledRate; +@property(readonly, retain, nonatomic) NSNumber *wiFiScaledRSSI; +@property(readonly, retain, nonatomic) NSNumber *wiFiSignalStrength; +@property(readonly, nonatomic) BOOL willTryToSearchForWiFiNetwork; +@property(readonly, nonatomic) BOOL willTryToAutoAssociateWiFiNetwork; +@property(readonly, nonatomic) BOOL isHostingWiFiHotSpot; +- (void)removeFastDormancyDisableToken:(id)arg1; +- (void)addFastDormancyDisableToken:(id)arg1; +@property(readonly, nonatomic) BOOL disableFastDormancy; +- (void)_lockedAdjustCellularAutoAssociation; +- (void)_adjustCellularAutoAssociation; +@property(readonly, nonatomic) BOOL isAirplaneModeEnabled; +- (void)cutWiFiManagerLinkDidChange:(id)arg1 context:(id)arg2; +- (void)dealloc; +- (id)init; + +@end + +@interface IMInvocationQueue : NSObject +{ + BOOL _holdQueue; + id _delegate; + id _target; + double _dequeueRate; + NSMutableArray *_queue; + NSMutableArray *_options; + NSProtocolChecker *_protocolChecker; +} + +@property(readonly, nonatomic) BOOL holdQueue; // @synthesize holdQueue=_holdQueue; +@property(readonly, retain, nonatomic) NSProtocolChecker *protocolChecker; // @synthesize protocolChecker=_protocolChecker; +@property(readonly, retain, nonatomic) NSMutableArray *options; // @synthesize options=_options; +@property(readonly, retain, nonatomic) NSMutableArray *queue; // @synthesize queue=_queue; +@property(nonatomic) double dequeueRate; // @synthesize dequeueRate=_dequeueRate; +@property id target; // @synthesize target=_target; +@property id delegate; // @synthesize delegate=_delegate; +- (id)peek; +@property(readonly, nonatomic) BOOL isEmpty; +@property(readonly, nonatomic) unsigned long long count; +- (void)invokeAll; +- (void)removeAllInvocations; +- (id)_dequeueInvocation; +- (long long)_enqueueInvocation:(id)arg1 options:(unsigned long long)arg2; +- (BOOL)_insertInvocation:(id)arg1 options:(unsigned long long)arg2; +- (BOOL)_replaceSimilarInvocation:(id)arg1; +- (BOOL)_acceptsOptions:(unsigned long long)arg1; +- (int)_maxQueueLimitSize; +- (int)_numberOfLimitedMessagesInQueue; +- (unsigned long long)_optionsForInvocation:(id)arg1; +- (void)_checkQueue; +- (BOOL)_invokeInvocation:(id)arg1; +- (void)_setQueueTimer; +- (void)_releaseQueueNotification:(id)arg1; +- (void)_holdQueueNotification:(id)arg1; +- (void)_stepQueueNotification:(id)arg1; +@property(retain, nonatomic) Protocol *protocol; +- (id)methodSignatureForSelector:(SEL)arg1; +- (void)forwardInvocation:(id)arg1; +- (void)dealloc; +- (id)init; + +@end + +@interface IMUserDefaults : NSObject +{ +} + ++ (BOOL)isLiveDeliveryWarmUpEnabled; ++ (void)setEnableLiveDeliveryWarmUp:(BOOL)arg1; ++ (BOOL)isDebugPiscoLoggingEnabled; ++ (BOOL)isDeviceScoringEnabled; ++ (BOOL)isBAACertDisabled; ++ (BOOL)isAbsintheV4Enabled; ++ (BOOL)isPiscoDisabled; ++ (id)phoneNumberValidationPreflightTestData; ++ (void)setPhoneNumberValidationPreflightTestData:(id)arg1; ++ (long long)phoneNumberValidationMode; ++ (void)setPhoneNumberValidationMode:(long long)arg1; ++ (BOOL)isEngramEnabled; ++ (void)setEnableEngram:(BOOL)arg1; ++ (id)sharedDefaults; +- (id)copyValueForKey:(id)arg1 applicationID:(struct __CFString *)arg2 userName:(struct __CFString *)arg3 hostName:(struct __CFString *)arg4; +- (id)copyMultipleForCurrentKeys:(id)arg1 applicationID:(struct __CFString *)arg2 userName:(struct __CFString *)arg3 hostName:(struct __CFString *)arg4; +- (id)copyKeyListForApplicationID:(struct __CFString *)arg1 userName:(struct __CFString *)arg2 hostName:(struct __CFString *)arg3; +- (void)synchronizeApplicationID:(struct __CFString *)arg1 userName:(struct __CFString *)arg2 hostName:(struct __CFString *)arg3; +- (void)setMultiple:(id)arg1 remove:(id)arg2 applicationID:(struct __CFString *)arg3 userName:(struct __CFString *)arg4 hostName:(struct __CFString *)arg5; +- (void)setValue:(void *)arg1 forKey:(id)arg2 applicationID:(struct __CFString *)arg3 userName:(struct __CFString *)arg4 hostName:(struct __CFString *)arg5; +- (id)copyValueForKey:(id)arg1 appID:(id)arg2; +- (id)copyMultipleForCurrentKeys:(id)arg1 appID:(id)arg2; +- (id)copyKeyListForAppID:(id)arg1; +- (void)synchronizeAppID:(id)arg1; +- (void)setMultiple:(id)arg1 remove:(id)arg2 appID:(id)arg3; +- (void)setValue:(void *)arg1 forKey:(id)arg2 appID:(id)arg3; +- (void)setAppBool:(BOOL)arg1 forKey:(id)arg2; +- (BOOL)appBoolForKey:(id)arg1; +- (void)removeAppValueForKey:(id)arg1; +- (void)setAppValue:(id)arg1 forKey:(id)arg2; +- (id)appValueForKey:(id)arg1; +- (void)setAppBool:(BOOL)arg1 byHostForKey:(id)arg2; +- (BOOL)appBoolByHostForKey:(id)arg1; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; + +@property(readonly) Class superclass; + +@end + +@interface IMDeviceSupport : NSObject +{ + NSString *_model; + NSString *_productName; + NSString *_productVersion; + NSString *_buildVersion; + NSRecursiveLock *_lock; +} + ++ (id)marketingNameForModel:(id)arg1; ++ (id)sharedInstance; +@property(readonly, nonatomic) NSString *deviceInformationString; +@property(readonly, nonatomic) NSString *productBuildVersion; +@property(readonly, nonatomic) NSString *productVersion; +@property(readonly, nonatomic) NSString *productName; +@property(readonly, nonatomic) NSString *userAgentString; +- (void)_generateProductInformation; +@property(readonly, nonatomic) NSString *model; +- (void)dealloc; +- (id)init; + +@end + +@interface IMManualUpdater : NSObject +{ + id _target; + SEL _action; + unsigned int _needsUpdate:1; +} + +@property(nonatomic) SEL action; // @synthesize action=_action; +@property(nonatomic) id target; // @synthesize target=_target; +@property(nonatomic) BOOL needsUpdate; // @dynamic needsUpdate; +- (void)updateIfNeeded; +- (void)setNeedsUpdate; +- (id)initWithTarget:(id)arg1 action:(SEL)arg2; +- (id)description; + +@end + +@interface IMScheduledUpdater : IMManualUpdater +{ + NSCountedSet *_holdingUpdatesKeys; +} + +@property(retain, nonatomic) NSCountedSet *holdingUpdatesKeys; // @synthesize holdingUpdatesKeys=_holdingUpdatesKeys; +- (void)invalidate; +- (BOOL)isHoldingUpdatesForKey:(id)arg1; +- (BOOL)isHoldingUpdates; +- (void)endHoldingUpdatesForAllKeys; +- (void)endHoldingUpdatesForKey:(id)arg1; +- (void)beginHoldingUpdatesForKey:(id)arg1; +- (void)updateIfNeeded; +- (void)setNeedsUpdate; +- (id)initWithTarget:(id)arg1 action:(SEL)arg2; +- (id)description; +- (void)dealloc; + +@end + +@interface IMMessageContext : NSObject +{ + NSObject *_xpcMessage; +// IMLocalObject *_localObject; + id _context; + BOOL _boost; +// NSObject *_voucher; +} + +//@property(retain) NSObject *voucher; // @synthesize voucher=_voucher; +@property(retain) id context; // @synthesize context=_context; +@property BOOL shouldBoost; // @synthesize shouldBoost=_boost; +//@property(retain) IMLocalObject *localObject; // @synthesize localObject=_localObject; +@property(retain) NSObject *xpcMessage; // @synthesize xpcMessage=_xpcMessage; +- (void)dealloc; +- (id)init; + +@end + +@interface NetworkChangeNotifier : NSObject +{ + BOOL _lastPostedNetworkUp; + struct __SCDynamicStore *_store; + NSString *_myIP; + NSArray *_myIPs; + IMConnectionMonitor *_connectionMonitor; +} + ++ (void)disableNotifications; ++ (BOOL)enableNotifications; ++ (id)sharedInstance; +@property(nonatomic) BOOL lastPostedNetworkUp; // @synthesize lastPostedNetworkUp=_lastPostedNetworkUp; +@property(retain, nonatomic) IMConnectionMonitor *connectionMonitor; // @synthesize connectionMonitor=_connectionMonitor; +@property(retain, nonatomic) NSArray *myIPs; // @synthesize myIPs=_myIPs; +@property(retain, nonatomic) NSString *myIP; // @synthesize myIP=_myIP; +@property(nonatomic) struct __SCDynamicStore *store; // @synthesize store=_store; +- (id)primaryInterfaceName; +- (BOOL)isPrimaryCellular; +@property(readonly, nonatomic) BOOL isNetworkUp; +- (void)connectionMonitorDidUpdate:(id)arg1; +- (unsigned long long)linkQualityForInterfaceType:(unsigned long long)arg1; +- (int)linkQualityValueForInterface:(id)arg1; +- (int)linkQualityValueForInterfaceType:(unsigned long long)arg1; +@property(readonly, nonatomic) struct __SCDynamicStore *getDynamicStore; +@property(readonly, nonatomic) NSString *myIPAddress; +@property(readonly, nonatomic) NSString *myGatewayAddress; +@property(readonly, nonatomic) NSArray *myIPAddresses; +- (void)dealloc; +- (id)init; +- (BOOL)_listenForChanges; +- (void)systemDidWake; +- (void)systemWillSleep; +- (void)_clearIPCache; + +@end + +@interface _IMTimingInstance : NSObject +{ + double _startTiming; + double _stopTiming; + double _totalTime; + BOOL _isRunning; +} + ++ (id)createTimingInstanceWithStartTime:(float)arg1; +@property(nonatomic) BOOL isRunning; // @synthesize isRunning=_isRunning; +@property(nonatomic) double totalTime; // @synthesize totalTime=_totalTime; +- (id)description; +- (void)stopUsingTime:(double)arg1; +- (void)startUsingTime:(double)arg1; +- (id)init; + +@end + +@interface IMTimingCollection : NSObject +{ + NSMutableDictionary *_timings; + NSObject *_queue; +} + +- (BOOL)hasKey:(id)arg1; +- (id)description; +- (void)removeTimingForKey:(id)arg1; +- (double)totalTimeForKey:(id)arg1; +- (void)stopTimingForKey:(id)arg1; +- (void)startTimingForKey:(id)arg1; +- (void)dealloc; +- (id)init; + +@end + +@interface IMMultiDict : NSObject +{ + NSMutableDictionary *_dictionary; + unsigned long long _count; +} + +@property(readonly, nonatomic) unsigned long long count; // @synthesize count=_count; +@property(retain, nonatomic) NSMutableDictionary *dictionary; // @synthesize dictionary=_dictionary; +@property(readonly, nonatomic) NSArray *allKeys; +- (void)enumerateKeysAndObjectsUsingBlock:(CDUnknownBlockType)arg1; +- (unsigned long long)countForKey:(id)arg1; +- (void)removeObject:(id)arg1 forKey:(id)arg2; +- (void)removeAllObjects; +- (void)removeObjectsForKey:(id)arg1; +- (id)objectsForKey:(id)arg1; +- (id)dequeueObjectForKey:(id)arg1; +- (id)headObjectForKey:(id)arg1; +- (void)enqueueObject:(id)arg1 forKey:(id)arg2; +- (id)popObjectForKey:(id)arg1; +- (id)peekObjectForKey:(id)arg1; +- (void)pushObject:(id)arg1 forKey:(id)arg2; +- (id)description; +- (id)init; +- (void)dealloc; + +@end + +@interface IMURLResponseToPlist : NSObject +{ +} + ++ (void)generate:(id)arg1 data:(id)arg2 toFilePath:(id)arg3; + +@end + +@interface IMMockURLResponse : NSObject +{ + NSHTTPURLResponse *_response; + NSData *_data; + NSString *_requestBodyKeyPath; + NSString *_mockID; +} + ++ (id)objectFromPlist:(id)arg1; ++ (BOOL)supportsSecureCoding; +@property(copy) NSString *mockID; // @synthesize mockID=_mockID; +@property(copy) NSString *requestBodyKeyPath; // @synthesize requestBodyKeyPath=_requestBodyKeyPath; +@property(retain) NSData *data; // @synthesize data=_data; +@property(retain) NSHTTPURLResponse *response; // @synthesize response=_response; +- (void)dealloc; +- (id)initWithCoder:(id)arg1; +- (void)encodeWithCoder:(id)arg1; + +@end + +@interface IMAllocTracking : NSObject +{ + NSMutableArray *_callStacks; +} + +- (void)dealloc; +- (oneway void)release; +- (id)retain; +- (void)_registerCallstack; + +@end + +@interface IMSystemMonitor : NSObject +{ + BOOL _watchesDataProtectionLockState; + BOOL _watchesScreenLightState; + BOOL _receivesMemoryWarnings; + BOOL _willSleep; + BOOL _screenLocked; + BOOL _screensaverActive; + BOOL _watchesSystemLockState; + BOOL _underFirstLock; + BOOL _active; + BOOL _backingUp; + BOOL _switchedOut; + BOOL _screenLit; + BOOL _systemLocked; + BOOL _idleOverride; + BOOL _usesPowerNotifications; + BOOL _usesSystemIdleState; + BOOL _inBackground; + int _dataProtectionState; + int _userIdleToken; + NSMutableArray *_listeners; + NSDate *_idleStart; + NSTimer *_timer; + NSDate *_dateScreenLightLastChanged; + NSDate *_dateSystemLockLastChanged; + NSString *_userID; + double _delayTime; + NSMutableArray *_earlyListeners; + long long _resignActiveCount; + struct _opaque_pthread_mutex_t _ivarLock; +} + ++ (id)sharedInstance; +@property(nonatomic) long long resignActiveCount; // @synthesize resignActiveCount=_resignActiveCount; +@property(nonatomic) struct _opaque_pthread_mutex_t ivarLock; // @synthesize ivarLock=_ivarLock; +@property(nonatomic) int userIdleToken; // @synthesize userIdleToken=_userIdleToken; +@property(retain, nonatomic) NSMutableArray *_earlyListeners; // @synthesize _earlyListeners; +@property(nonatomic) BOOL _idleOverride; // @synthesize _idleOverride; +@property(nonatomic) double _delayTime; // @synthesize _delayTime; +@property(retain, nonatomic) NSString *_userID; // @synthesize _userID; +@property(retain, nonatomic) NSTimer *_timer; // @synthesize _timer; +@property(retain, nonatomic) NSDate *_idleStart; // @synthesize _idleStart; +@property(retain, nonatomic) NSMutableArray *_listeners; // @synthesize _listeners; +@property(nonatomic) BOOL isFastUserSwitched; // @synthesize isFastUserSwitched=_switchedOut; +@property(nonatomic) BOOL _underFirstLock; // @synthesize _underFirstLock; +@property(nonatomic) int _dataProtectionState; // @synthesize _dataProtectionState; +@property(nonatomic) BOOL receivesMemoryWarnings; // @synthesize receivesMemoryWarnings=_receivesMemoryWarnings; +- (void)_receivedMemoryNotification; +- (void)_unregisterForLoginWindowNotifications; +- (void)_registerForLoginWindowNotifications; +- (void)_handleLoginWindowNotification:(id)arg1; +- (void)_forceSuspended; +- (void)_forceResumed; +@property(readonly, nonatomic) BOOL isSetup; +- (void)_unregisterForRestoreNotifications; +- (void)_registerForRestoreNotifications; +- (void)_setupStateChanged; +- (void)_restoreDidStop; +- (void)_restoreDidStart; +- (void)_checkRestoredFromBackup; +- (void)removeListener:(id)arg1; +- (void)addListener:(id)arg1; +- (void)_removeEarlyListener:(id)arg1; +- (void)_addEarlyListener:(id)arg1; +- (void)_systemWillShutdown; +@property(readonly, nonatomic) BOOL systemIsShuttingDown; +@property(readonly, nonatomic) double systemIdleTime; +- (BOOL)_alreadyLocked_isSystemIdle; +@property(readonly, nonatomic) BOOL isSystemIdle; +- (void)_checkIdleTime:(id)arg1; +- (void)_alreadyLocked_clearIdleTimer; +- (void)_clearIdleTimer; +- (void)_armIdleTimer; +- (void)_overrideAndDisableIdleTimer:(BOOL)arg1; +- (void)_setIdleState:(BOOL)arg1; +@property(nonatomic) BOOL usesSystemIdleState; // @synthesize usesSystemIdleState=_usesSystemIdleState; +- (void)_updateIdleState; +- (void)_setSystemLockState:(BOOL)arg1; +- (void)_setSystemScreenState:(BOOL)arg1; +@property(nonatomic) BOOL usesPowerNotifications; // @synthesize usesPowerNotifications=_usesPowerNotifications; +@property(nonatomic) BOOL watchesScreenLightState; // @synthesize watchesScreenLightState=_watchesScreenLightState; +@property(nonatomic) BOOL watchesSystemLockState; // @synthesize watchesSystemLockState=_watchesSystemLockState; +@property(nonatomic) BOOL watchesDataProtectionLockState; // @synthesize watchesDataProtectionLockState=_watchesDataProtectionLockState; +@property(readonly, nonatomic) BOOL isUnderFirstDataProtectionLock; +- (BOOL)_isUnderDataProtectionLockForState:(int)arg1; +@property(readonly, nonatomic) BOOL isUnderDataProtectionLock; +- (void)_setDataProtectionLockState:(int)arg1; +- (BOOL)_deviceStillUnderFirstLock; +- (void)_applicationDidRemoveDeactivationReason:(id)arg1; +- (void)_applicationWillAddDeactivationReason:(id)arg1; +- (void)_applicationDidEnterBackground:(id)arg1; +- (void)_applicationWillEnterForeground:(id)arg1; +- (void)_screenSaverStarted:(id)arg1; +- (void)_screenSaverStopped:(id)arg1; +- (void)_postScreenSaverStarted; +- (void)_notificationCenterDidDisappear:(id)arg1; +- (void)_notificationCenterWillAppear:(id)arg1; +- (void)_resume:(id)arg1; +- (void)_suspend:(id)arg1; +- (void)_resumeEventsOnly:(id)arg1; +- (void)_suspendEventsOnly:(id)arg1; +- (void)_applicationDidBecomeActive:(id)arg1; +- (void)_applicationWillResignActive:(id)arg1; +@property(readonly, nonatomic) BOOL isScreenLocked; // @synthesize isScreenLocked=_screenLocked; +- (void)_screenUnlocked:(id)arg1; +- (void)_screenLocked:(id)arg1; +- (void)_postScreenLocked; +- (void)_systemWillSleep; +- (void)_systemDidWake; +- (void)_deliverNotificationSelector:(SEL)arg1; +@property(nonatomic, setter=setActive:) BOOL isActive; // @synthesize isActive=_active; +- (void)dealloc; +- (id)init; +@property(readonly, nonatomic) BOOL isInBackground; // @synthesize isInBackground=_inBackground; +@property(readonly, nonatomic) BOOL isSystemLocked; // @synthesize isSystemLocked=_systemLocked; +@property(readonly, nonatomic) BOOL isScreenLit; // @synthesize isScreenLit=_screenLit; +@property(readonly, nonatomic) BOOL isBackingUp; // @synthesize isBackingUp=_backingUp; +@property(readonly, nonatomic) BOOL isScreenSaverActive; // @synthesize isScreenSaverActive=_screensaverActive; +@property(readonly, nonatomic) BOOL systemIsSleeping; // @synthesize systemIsSleeping=_willSleep; +@property(readonly, retain, nonatomic) NSDate *dateSystemLockLastChanged; // @synthesize dateSystemLockLastChanged=_dateSystemLockLastChanged; +@property(readonly, retain, nonatomic) NSDate *dateScreenLightLastChanged; // @synthesize dateScreenLightLastChanged=_dateScreenLightLastChanged; + +@end + +@interface IMUserNotification : NSObject +{ + id _reserved; +} + ++ (id)userNotificationWithIdentifier:(id)arg1 title:(id)arg2 message:(id)arg3 defaultButton:(id)arg4 alternateButton:(id)arg5 otherButton:(id)arg6; ++ (id)userNotificationWithIdentifier:(id)arg1 timeout:(double)arg2 alertLevel:(unsigned long long)arg3 displayFlags:(unsigned long long)arg4 displayInformation:(id)arg5; +- (void)_setResponseFlags:(unsigned long long)arg1 responseInformation:(id)arg2; +@property(readonly, retain, nonatomic) NSDictionary *responseInformation; +@property(readonly, nonatomic) unsigned long long responseFlags; +@property(retain, nonatomic) NSDictionary *userInfo; +@property(nonatomic) BOOL usesNotificationCenter; +@property(nonatomic) BOOL showInLockScreen; +@property(retain, nonatomic) NSString *representedApplicationBundle; +@property(readonly, nonatomic) unsigned long long response; +@property(readonly, retain, nonatomic) NSDictionary *displayInformation; +@property(readonly, nonatomic) unsigned long long displayFlags; +@property(readonly, nonatomic) double timeout; +@property(readonly, retain, nonatomic) id identifier; +- (void)dealloc; +- (id)_initWithIdentifier:(id)arg1 timeout:(double)arg2 displayFlags:(unsigned long long)arg3 displayInformation:(id)arg4; + +@end + +@interface IMUserNotificationCenter : NSObject +{ + NSMutableDictionary *_identifierToIMUserNotificationQueueMap; + NSMutableDictionary *_identifierToListenerQueueMap; + NSMutableDictionary *_identifierToBlockQueueMap; + NSMutableDictionary *_identifierToRunLoopSourcesMap; + NSMutableDictionary *_identifierToCFUserNotificationMap; +} + ++ (id)sharedInstance; +@property(retain, nonatomic) NSMutableDictionary *identifierToCFUserNotificationMap; // @synthesize identifierToCFUserNotificationMap=_identifierToCFUserNotificationMap; +@property(retain, nonatomic) NSMutableDictionary *identifierToRunLoopSourcesMap; // @synthesize identifierToRunLoopSourcesMap=_identifierToRunLoopSourcesMap; +@property(retain, nonatomic) NSMutableDictionary *identifierToBlockQueueMap; // @synthesize identifierToBlockQueueMap=_identifierToBlockQueueMap; +@property(retain, nonatomic) NSMutableDictionary *identifierToListenerQueueMap; // @synthesize identifierToListenerQueueMap=_identifierToListenerQueueMap; +@property(retain, nonatomic) NSMutableDictionary *identifierToIMUserNotificationQueueMap; // @synthesize identifierToIMUserNotificationQueueMap=_identifierToIMUserNotificationQueueMap; +- (void)removeAllListeners; +- (void)removeListener:(id)arg1; +- (void)removeNotificationsForServiceIdentifier:(id)arg1; +- (unsigned long long)countForIdentifier:(id)arg1; +- (void)addUserNotification:(id)arg1 listener:(id)arg2 completionHandler:(CDUnknownBlockType)arg3; +- (void)addUserNotification:(id)arg1 listener:(id)arg2; +- (void)_handleUserNotification:(struct __CFUserNotification *)arg1 responseFlags:(unsigned long long)arg2; +- (void)_displayNextUserNotificationForIdentifier:(id)arg1; +- (void)_cancelActiveUserNotificationForIdentifier:(id)arg1; +- (void)userNotificationCenter:(id)arg1 didDeliverNotification:(id)arg2; +- (void)userNotificationCenter:(id)arg1 didActivateNotification:(id)arg2; +- (BOOL)userNotificationCenter:(id)arg1 shouldPresentNotification:(id)arg2; +- (void)_enqueueBlock:(CDUnknownBlockType)arg1 forIdentifier:(id)arg2; +- (void)_enqueueListener:(id)arg1 forIdentifier:(id)arg2; +- (void)_enqueueUserNotification:(id)arg1 forIdentifier:(id)arg2; +- (CDUnknownBlockType)_dequeueBlockForIdentifier:(id)arg1; +- (id)_dequeueListenerForIdentifier:(id)arg1; +- (id)_dequeueUserNotificationForIdentifier:(id)arg1; +- (CDUnknownBlockType)_frontBlockForIdentifier:(id)arg1; +- (id)_frontListenerForIdentifier:(id)arg1; +- (id)_frontUserNotificationForIdentifier:(id)arg1; +- (void)dealloc; + +@end + +@interface IMFileCopier : NSObject +{ + BOOL _shouldCancel; + BOOL _didErrorOccur; + BOOL _inProgress; + id _delegate; + NSURL *_inputURL; + NSURL *_outputURL; + id _identifier; + unsigned long long _operation; + void *_BOMCopier; + NSObject *_queue; + CDUnknownBlockType _callback; +} + +@property(copy) CDUnknownBlockType _callback; // @synthesize _callback; +@property(retain) NSObject *_queue; // @synthesize _queue; +@property void *_BOMCopier; // @synthesize _BOMCopier; +@property unsigned long long operation; // @synthesize operation=_operation; +@property BOOL inProgress; // @synthesize inProgress=_inProgress; +@property(readonly, nonatomic) BOOL didErrorOccur; // @synthesize didErrorOccur=_didErrorOccur; +@property(readonly, nonatomic) BOOL wasCancelled; // @synthesize wasCancelled=_shouldCancel; +@property(readonly, retain) id identifier; // @synthesize identifier=_identifier; +@property(readonly, retain) NSURL *outputURL; // @synthesize outputURL=_outputURL; +@property(readonly, retain) NSURL *inputURL; // @synthesize inputURL=_inputURL; +@property id delegate; // @synthesize delegate=_delegate; +- (void)_worker_doCopy; +- (void)_main_copierFinishedWithResult:(id)arg1; +- (void)cleanup; +- (void)cancel; +- (void)start; +- (void)_fillOutputURLFromInputURL; +- (id)_temporaryCopierPath; +- (void)dealloc; +- (id)initWithInputURL:(id)arg1 outputURL:(id)arg2 identifier:(id)arg3 operation:(unsigned long long)arg4 completionBlock:(CDUnknownBlockType)arg5 queue:(id)arg6; +- (id)initWithInputURL:(id)arg1 outputURL:(id)arg2 identifier:(id)arg3 operation:(unsigned long long)arg4 delegate:(id)arg5; + +@end + +@interface IMReachability : NSObject +{ + BOOL _gettingFlags; + id _delegate; + unsigned long long _flags; + NSString *_description; + void *_reachabilityRef; + NSObject *_queue; +} + ++ (id)reachabilityWithLocalAddress:(id)arg1 remoteAddress:(id)arg2; ++ (id)reachabilityWithRemoteAddress:(id)arg1; ++ (id)reachabilityWithHostName:(id)arg1; +@property(retain, nonatomic) NSObject *_queue; // @synthesize _queue; +@property(nonatomic) void *reachabilityRef; // @synthesize reachabilityRef=_reachabilityRef; +@property(retain, nonatomic) NSString *reachabilityDescription; // @synthesize reachabilityDescription=_description; +@property(nonatomic) unsigned long long flags; // @synthesize flags=_flags; +@property(nonatomic) BOOL gettingFlags; // @synthesize gettingFlags=_gettingFlags; +@property(nonatomic) __weak id delegate; // @synthesize delegate=_delegate; + +@property(readonly, nonatomic) BOOL connectionRequired; +- (void)_forceGetFlagsIfNecessary; +//- (void)_handleCallbackForSCNetworkReachability:(struct __SCNetworkReachability *)arg1; +- (id)description; +- (void)dealloc; +- (id)initWithLocalSocketAddress:(id)arg1 remoteSocketAddress:(id)arg2 delegate:(id)arg3; +- (id)initWithRemoteHost:(id)arg1 delegate:(id)arg2; +//- (id)_initWithReachabilityRef:(struct __SCNetworkReachability *)arg1 description:(id)arg2 delegate:(id)arg3; + +@end + +@interface IMConnectionMonitor : NSObject +{ + NSString *_remoteHost; + id _delegate; +} + ++ (id)alloc; +@property(nonatomic) id delegate; // @synthesize delegate=_delegate; +@property(readonly, retain, nonatomic) NSString *remoteHost; // @synthesize remoteHost=_remoteHost; +@property(readonly, nonatomic) BOOL isImmediatelyReachable; +@property(readonly, nonatomic) BOOL requiresDataConnectionActivation; +@property(nonatomic, setter=setDataConnectionActive:) BOOL isDataConnectionActive; +- (void)clear; +- (void)goDisconnected; +- (void)goConnectedWithLocalSocketAddress:(id)arg1 remoteSocketAddress:(id)arg2; +- (void)_setup; +- (void)dealloc; +- (id)initWithRemoteHost:(id)arg1 delegate:(id)arg2; + +@end + +@interface IMNetworkConnectionMonitor : IMConnectionMonitor +{ + BOOL _isConnected; + BOOL _isSleeping; + IMReachability *_hostReachability; + IMReachability *_ipReachability; + unsigned long long _hostFlags; + unsigned long long _ipFlags; +} + +@property(nonatomic) BOOL _isSleeping; // @synthesize _isSleeping; +@property(nonatomic) BOOL _isConnected; // @synthesize _isConnected; +@property(nonatomic) unsigned long long _ipFlags; // @synthesize _ipFlags; +@property(nonatomic) unsigned long long _hostFlags; // @synthesize _hostFlags; +@property(retain, nonatomic) IMReachability *_ipReachability; // @synthesize _ipReachability; +@property(retain, nonatomic) IMReachability *_hostReachability; // @synthesize _hostReachability; +- (BOOL)isImmediatelyReachable; +- (void)clear; +- (void)goDisconnected; +- (void)goConnectedWithLocalSocketAddress:(id)arg1 remoteSocketAddress:(id)arg2; +- (void)_setup; +- (void)systemDidWake; +- (void)systemWillSleep; +- (void)reachabilityDidChange:(id)arg1; +- (void)_setupReachability; +- (void)_doCallbackLater; +- (void)_doCallbackNow; +- (void)_clearReachability:(id *)arg1 flags:(unsigned long long *)arg2; +- (void)dealloc; + +@end + +@interface IMLocalObjectInternal : NSObject +{ + IMMessageContext *_currentMessageContext; + NSRecursiveLock *_lock; + id _target; + NSObject *_connection; + NSObject *_queue; + NSObject *_deathLock; + NSString *_portName; + NSString *_processName; + NSProtocolChecker *_protocolChecker; + NSMutableArray *_componentQueue; + NSLock *_componentQueueLock; + NSRecursiveLock *_componentQueueProcessingLock; + struct __CFRunLoopSource *_runloopSource; + BOOL _pendingComponentQueueProcessing; + BOOL _busyForwarding; + BOOL _offMainThread; + NSArray *_whitelistedClasses; +} + +- (void)dealloc; + +@end + +@interface IMLocalObject : NSObject +{ + id _internal; +} + ++ (void)initialize; ++ (void)_unregisterIMLocalObject:(id)arg1; ++ (void)_registerIMLocalObject:(id)arg1; ++ (id)_registeredIMLocalObjectForPort:(unsigned int)arg1; ++ (void)_setExceptionHandlingDisabled:(BOOL)arg1; ++ (id)_imLocalObjectQueue; +- (id)description; +- (void)invalidate; +@property(retain, nonatomic) NSArray *whitelistedClasses; +@property(readonly, nonatomic) BOOL isValid; +- (BOOL)isValidSelector:(SEL)arg1; +- (void)_enqueueInvocationWithPriority:(id)arg1 xpcMessage:(id)arg2 priority:(int)arg3; +- (void)_enqueueInvocationWithPriority:(id)arg1 priority:(int)arg2; +- (void)_enqueueInvocation:(id)arg1 xpcMessage:(id)arg2; +- (void)_enqueueInvocation:(id)arg1; +- (void)_popInvocation; +- (id)_peekInvocation; +- (void)_noteNewInvocation; +- (void)_handleNewInvocations; +- (BOOL)handleInvocation:(id)arg1; +- (BOOL)_handleInvocation:(id)arg1; +- (void)_handleInvocationForSendMessage:(id)arg1; +- (id)_currentMessageContext; +@property(retain, nonatomic) NSString *processName; +- (void)setPortName:(id)arg1; +@property(readonly, nonatomic) NSString *portName; +@property(readonly, nonatomic) NSObject *connection; +- (void)_systemShutdown:(id)arg1; +- (void)terminated; +- (void)_portDidBecomeInvalid; +- (void)_portInterrupted; +- (void)_cancelHandlerCompleted; +- (void)dealloc; +- (void)_clearPort:(BOOL)arg1 signalRunLoopIfNeeded:(BOOL)arg2; +- (void)_clearPort:(BOOL)arg1; +@property(readonly, nonatomic) NSProtocolChecker *protocolChecker; +@property(nonatomic) id target; +- (id)initWithTarget:(id)arg1 portName:(id)arg2 protocol:(id)arg3; +- (id)initWithTarget:(id)arg1 connection:(id)arg2 protocol:(id)arg3 forceSecureCoding:(BOOL)arg4 offMainThread:(BOOL)arg5; +- (id)initWithTarget:(id)arg1 connection:(id)arg2 protocol:(id)arg3 forceSecureCoding:(BOOL)arg4; +- (id)initWithTarget:(id)arg1 connection:(id)arg2 protocol:(id)arg3; +- (id)initWithTarget:(id)arg1 protocol:(id)arg2; + +@end + +@interface IMRemoteObjectInternal : NSObject +{ + NSRecursiveLock *_lock; + NSObject *_connection; + NSObject *_queue; + long long _deathPostPredicate; + Protocol *_protocol; + NSString *_portName; + NSString *_processName; + BOOL _willBeTerminated; + int _pid; +} + +@end + +@interface IMRemoteObject : NSObject +{ + id _internal; +} + ++ (void)initialize; ++ (void)_unregisterIMRemoteObject:(id)arg1; ++ (void)_registerIMRemoteObject:(id)arg1; ++ (id)_remoteObjects; +- (id)_queue; +- (id)description; +- (void)invalidate; +- (void)setPortName:(id)arg1; +@property(readonly, nonatomic) NSString *portName; +@property(retain, nonatomic) NSString *processName; +@property(nonatomic) int pid; +@property(readonly, nonatomic) NSObject *connection; +- (void)forwardInvocation:(id)arg1; +- (unsigned long long)forwardXPCObject:(id)arg1 messageContext:(id)arg2; +- (id)methodSignatureForSelector:(SEL)arg1; +- (void)_systemShutdown:(id)arg1; +@property(readonly, nonatomic) BOOL isValid; +- (void)_portDidBecomeInvalid; +- (void)dealloc; +- (void)_cleanupMachBitsCanPost:(BOOL)arg1; +- (id)initWithConnection:(id)arg1 protocol:(id)arg2 alreadyConfigured:(BOOL)arg3; +- (id)initWithConnection:(id)arg1 protocol:(id)arg2 alreadyConfigured:(BOOL)arg3 forceSecureCoding:(BOOL)arg4; +- (id)initWithPortName:(id)arg1 protocol:(id)arg2; +- (id)initWithConnection:(id)arg1 protocol:(id)arg2; +- (id)_initWithConnection:(id)arg1 portName:(id)arg2 protocol:(id)arg3 alreadyConfigured:(BOOL)arg4 forceSecureCoding:(BOOL)arg5; + +@end + +@interface IMRemoteObjectBroadcaster : NSObject +{ + NSObject *_queue; +} + ++ (id)defaultBroadcaster; +- (void)flushProxy:(id)arg1; +- (void)blockUntilSendQueueIsEmpty; +- (id)broadcastProxyForTargets:(id)arg1 messageContext:(id)arg2 protocol:(id)arg3; +- (id)broadcastProxyForTarget:(id)arg1 messageContext:(id)arg2 protocol:(id)arg3 priority:(int)arg4 completion:(CDUnknownBlockType)arg5; +- (id)broadcastProxyForTarget:(id)arg1 messageContext:(id)arg2 protocol:(id)arg3 priority:(int)arg4; +- (id)broadcastProxyForTarget:(id)arg1 messageContext:(id)arg2 protocol:(id)arg3; +- (id)_queue; +- (void)dealloc; +- (id)init; + +@end + +@interface Broadcaster : NSProxy +{ + NSArray *_targets; + IMRemoteObjectBroadcaster *_parent; + Protocol *_protocol; + IMMessageContext *_messageContext; + int _curXPCMessagePriority; + CDUnknownBlockType _completion; +} + +@property(nonatomic) int curXPCMessagePriority; // @synthesize curXPCMessagePriority=_curXPCMessagePriority; +- (void)forwardInvocation:(id)arg1; +- (id)methodSignatureForSelector:(SEL)arg1; +- (void)sendXPCObject:(id)arg1; +- (void)dealloc; +- (id)initWithNotifier:(id)arg1 messageContext:(id)arg2 protocol:(id)arg3 targets:(id)arg4 priority:(int)arg5 completion:(CDUnknownBlockType)arg6; +- (id)initWithNotifier:(id)arg1 messageContext:(id)arg2 protocol:(id)arg3 targets:(id)arg4 priority:(int)arg5; +- (id)initWithNotifier:(id)arg1 messageContext:(id)arg2 protocol:(id)arg3 targets:(id)arg4; + +@end + +@interface IMRGLog : NSObject +{ +} + ++ (id)watchPairing; ++ (id)voicemailSync; ++ (id)uniqueID; ++ (id)sysdiagnose_oversized; ++ (id)sub_services; ++ (id)sms; ++ (id)serverBag; ++ (id)reloadAccounts; ++ (id)registrationListener; ++ (id)registrationAuthKit; ++ (id)regeneration; ++ (id)queryRetry; ++ (id)pushToken; ++ (id)phoneRepair; ++ (id)pairingProtocolDebug; ++ (id)pairingIdentities; ++ (id)pairing; ++ (id)pairedIdentities; ++ (id)pairedDeviceRepo; ++ (id)nonce; ++ (id)migration; ++ (id)messageDelivery_oversized; ++ (id)liveMigration; ++ (id)keychainManager; ++ (id)keychain; ++ (id)keyRoll; ++ (id)isActive; ++ (id)internalCleanup; ++ (id)iMessageSpam; ++ (id)IMMacNotificationCenterManager; ++ (id)iCloud; ++ (id)healthDebugging; ++ (id)healthDebug; ++ (id)deviceState; ++ (id)deviceIDMap; ++ (id)deviceHeartbeat; ++ (id)dataProtectionClass; ++ (id)classKeys; ++ (id)appleCare; ++ (id)activeID; ++ (id)accountsDebugging; ++ (id)accountUpdate; ++ (id)accountSync; ++ (id)accountEnabled; ++ (id)accountCleanup; ++ (id)OTRStore; ++ (id)NSUUID; ++ (id)NRPairing; ++ (id)IDSService_oversized; ++ (id)IDSService; ++ (id)GDR; ++ (id)FTMessageDelivery_oversized; ++ (id)engram; ++ (id)ACKTracker; ++ (id)warning; ++ (id)registration; + +@end + +@interface IMCallMonitor : NSObject +{ +// CXCallObserver *_callCenter; + BOOL _wasOnCall; + NSDate *_lastCallDate; +} + ++ (id)sharedInstance; +@property(readonly, retain, nonatomic) NSDate *dateLastCallEnded; // @synthesize dateLastCallEnded=_lastCallDate; +@property(readonly, nonatomic) BOOL isOnCall; +- (void)dealloc; +- (id)init; + +@end + + +@interface IMDesktopNetworkManager : IMNetworkManager +{ +} + +@end + +@interface IMLockdownManager : NSObject +{ + BOOL _settingUpActivationState; + BOOL _isInternalInstall; + BOOL _isCarrierInstall; + BOOL _isNonUIInstall; + BOOL _isVendorInstall; + BOOL _hasShownMismatchedSIM; + BOOL _hasShownWaitingAlertThisSession; + unsigned long long _state; +} + ++ (id)sharedInstance; +@property(nonatomic) BOOL _hasShownWaitingAlertThisSession; // @synthesize _hasShownWaitingAlertThisSession; +@property(nonatomic) BOOL _hasShownMismatchedSIM; // @synthesize _hasShownMismatchedSIM; +@property(nonatomic) BOOL _isVendorInstall; // @synthesize _isVendorInstall; +@property(nonatomic) BOOL _isNonUIInstall; // @synthesize _isNonUIInstall; +@property(nonatomic) BOOL _isCarrierInstall; // @synthesize _isCarrierInstall; +@property(nonatomic) BOOL _isInternalInstall; // @synthesize _isInternalInstall; +@property(nonatomic) BOOL _settingUpActivationState; // @synthesize _settingUpActivationState; +- (id)description; +@property(readonly, nonatomic) NSString *uniqueDeviceIdentifier; +@property(readonly, nonatomic) BOOL isExpired; +@property(readonly, nonatomic) BOOL isActivated; +@property(readonly, nonatomic) BOOL isCarrierInstall; +- (long long)lockdownState; +@property(readonly, nonatomic) BOOL isInternalInstall; +@property(readonly, nonatomic) BOOL isVendorInstall; +@property(readonly, nonatomic) BOOL isNonUIInstall; +- (void)_calculateInstallType; +- (void)_setupActivationState; +@property(nonatomic, setter=_setState:) unsigned long long _state; // @synthesize _state; +- (void)_resetActivationState; +- (void)dealloc; +- (id)init; + +@end + +@interface _IMLogFileCompressor : NSObject +{ + NSMutableArray *_archivers; +} + ++ (id)sharedInstance; +- (void)fileCopierDidFinish:(id)arg1; +- (void)fileCopierDidStart:(id)arg1; +- (void)compressPath:(id)arg1 toPath:(id)arg2; +- (void)dealloc; +- (id)init; + +@end + +@interface IMLogging : NSObject +{ +} + ++ (void)enableConsoleLoggingForLevel:(int)arg1; ++ (void)logString:(id)arg1 toFolder:(id)arg2 toFileNamed:(id)arg3; ++ (id)timeFormatter; ++ (id)dateFormatter; ++ (id)logFileDirectory; ++ (void)logAtLevel:(int)arg1 type:(id)arg2 category:(id)arg3 insertProcessInfo:(BOOL)arg4 simpleLogString:(id)arg5; ++ (void)logAtLevel:(int)arg1 type:(id)arg2 category:(id)arg3 insertProcessInfo:(BOOL)arg4 simpleLogString:(id)arg5 time:(unsigned long long)arg6; ++ (void)logAtLevel:(int)arg1 type:(id)arg2 category:(id)arg3 insertProcessInfo:(BOOL)arg4 format:(id)arg5 arguments:(struct __va_list_tag [1])arg6; ++ (void)logAtLevel:(int)arg1 type:(id)arg2 category:(id)arg3 insertProcessInfo:(BOOL)arg4 simpleLogString:(id)arg5 format:(id)arg6 arguments:(struct __va_list_tag [1])arg7 time:(unsigned long long)arg8; ++ (void)logAtLevel:(int)arg1 type:(id)arg2 category:(id)arg3 format:(id)arg4 arguments:(struct __va_list_tag [1])arg5; ++ (void)logAtLevel:(int)arg1 type:(id)arg2 category:(id)arg3 insertProcessInfo:(BOOL)arg4 format:(id)arg5; ++ (void)logAtLevel:(int)arg1 type:(id)arg2 category:(id)arg3 format:(id)arg4; ++ (id)stringForDate; ++ (BOOL)loggingEnabledForLevel:(int)arg1; + +@end + +@interface IMRemoteURLConnectionMockScheduler : NSObject +{ + NSObject *_connection; +} + +- (void)scheduleMockResponse:(id)arg1; +- (void)scheduleMockResponse:(id)arg1 forURL:(id)arg2; +- (BOOL)_connect; +- (id)init; + +@end + +@interface IMMacNotificationCenterManager : NSObject +{ + NSUserNotificationCenter *_center; +// APSConnection *_connection; + NSArray *_topics; + NSString *_identifier; +} + +@property(retain, nonatomic) NSArray *topics; // @synthesize topics=_topics; +- (void)invalidate; +- (void)_cleanupNotificationCenter; +- (void)_NCUpdated:(id)arg1; +- (void)userNotificationCenter:(id)arg1 notificationPreferencesChanged:(unsigned long long)arg2; +- (void)userNotificationCenter:(id)arg1 notificationsDisabled:(BOOL)arg2; +- (void)updateNotificationsStatus; +- (void)enableNotificationCenter:(BOOL)arg1; +- (void)dealloc; +- (id)initWithIdentifier:(id)arg1 topics:(id)arg2 connection:(id)arg3; + +@end + +@interface IMTimer : NSObject +{ + id _timer; + id _target; + NSDictionary *_userInfo; + NSString *_name; + double _timeInterval; + NSObject *_queue; + SEL _selector; + BOOL _wakeDevice; + BOOL _useCurrentRunLoop; +} + +@property(readonly, retain, nonatomic) id userInfo; // @synthesize userInfo=_userInfo; +- (void)dealloc; +- (void)invalidate; +@property(readonly, retain, nonatomic) NSDate *fireDate; +- (void)_reschedulePCPersistentTimer; +- (void)setFireTimeInterval:(double)arg1; +- (id)_initWithTimeInterval:(double)arg1 name:(id)arg2 shouldWake:(BOOL)arg3 target:(id)arg4 selector:(SEL)arg5 userInfo:(id)arg6 useCurrentRunLoop:(BOOL)arg7 queue:(id)arg8; +- (id)initWithTimeInterval:(double)arg1 name:(id)arg2 shouldWake:(BOOL)arg3 target:(id)arg4 selector:(SEL)arg5 userInfo:(id)arg6 queue:(id)arg7; +- (id)initWithTimeInterval:(double)arg1 name:(id)arg2 shouldWake:(BOOL)arg3 target:(id)arg4 selector:(SEL)arg5 userInfo:(id)arg6 useCurrentRunLoop:(BOOL)arg7; +- (id)initWithTimeInterval:(double)arg1 name:(id)arg2 shouldWake:(BOOL)arg3 target:(id)arg4 selector:(SEL)arg5 userInfo:(id)arg6; + +@end + +@interface IMOrderedMutableDictionary : NSObject +{ + NSMutableDictionary *_dictionary; +// IMDoubleLinkedList *_linkedList; +} + +- (BOOL)containsKey:(id)arg1; +- (BOOL)containsOrderedObject:(id)arg1; +- (id)orderedObjects; +- (void)removeOrderedObjectForKey:(id)arg1; +- (id)orderedObjectForKey:(id)arg1; +- (void)setOrderedObject:(id)arg1 forKey:(id)arg2; +- (void)dealloc; +- (id)init; + +@end + +@interface IMIDSLog : NSObject +{ +} + ++ (id)dataDetector; ++ (id)daemon; ++ (id)encryption; + +@end + +@interface _IMNotificationObservationHelper : NSObject +{ + id _observer; + id _object; + CDUnknownBlockType _block; + NSString *_name; +} + +- (void)_notification:(id)arg1; +- (void)dealloc; +- (id)initWithObserver:(id)arg1 name:(id)arg2 object:(id)arg3 block:(CDUnknownBlockType)arg4; + +@end + +@interface IMRKMessageResponseManager : NSObject +{ +} + ++ (id)sharedManager; ++ (id)alloc; + +@end + +@interface IMRKResponse : NSObject +{ + NSString *_string; + NSDictionary *_attributes; + NSString *_category; +} + ++ (id)alloc; +@property(readonly) NSString *category; // @synthesize category=_category; +@property(readonly) NSDictionary *attributes; // @synthesize attributes=_attributes; +@property(readonly) NSString *string; // @synthesize string=_string; + +@end + +@interface IMRemoteURLConnection : NSObject +{ + NSURLRequest *_request; + NSString *_bundleIdentifierForDataUsage; + CDUnknownBlockType _block; + NSObject *_connection; + BOOL _cancelled; + BOOL _loading; + BOOL _forceCellularIfPossible; + BOOL _alwaysForceCellular; + BOOL _requireIDSHost; + int _retries; + BOOL _shouldUsePipelining; + int _concurrentConnections; + BOOL _disableKeepAlive; + int _keepAliveWifi; + int _keepAliveCell; + BOOL _shouldReturnTimingData; +} + +@property BOOL shouldReturnTimingData; // @synthesize shouldReturnTimingData=_shouldReturnTimingData; +@property BOOL alwaysForceCellular; // @synthesize alwaysForceCellular=_alwaysForceCellular; +@property(copy) CDUnknownBlockType block; // @synthesize block=_block; +@property(retain) NSURLRequest *request; // @synthesize request=_request; +@property int keepAliveCell; // @synthesize keepAliveCell=_keepAliveCell; +@property int keepAliveWifi; // @synthesize keepAliveWifi=_keepAliveWifi; +@property BOOL disableKeepAlive; // @synthesize disableKeepAlive=_disableKeepAlive; +@property int concurrentConnections; // @synthesize concurrentConnections=_concurrentConnections; +@property BOOL shouldUsePipelining; // @synthesize shouldUsePipelining=_shouldUsePipelining; +@property BOOL requireIDSHost; // @synthesize requireIDSHost=_requireIDSHost; +@property(retain) NSString *bundleIdentifierForDataUsage; // @synthesize bundleIdentifierForDataUsage=_bundleIdentifierForDataUsage; +@property BOOL forceCellularIfPossible; // @synthesize forceCellularIfPossible=_forceCellularIfPossible; +- (void)cancel; +- (void)load; +- (void)dealloc; +- (id)initWithURLRequest:(id)arg1 completionBlockWithTimingData:(CDUnknownBlockType)arg2; +- (id)initWithURLRequest:(id)arg1 completionBlock:(CDUnknownBlockType)arg2; +- (BOOL)_connect; +- (BOOL)_disconnect; +- (void)_disconnected; + +@end + +@interface IMNetworkReachability : NSObject +{ + BOOL localWiFiRef; + struct __SCNetworkReachability *reachabilityRef; +} + ++ (id)reachabilityForLocalWiFi; ++ (id)reachabilityForInternetConnection; +//+ (id)reachabilityWithAddress:(const struct sockaddr_in *)arg1; ++ (id)reachabilityWithHostName:(id)arg1; +- (long long)currentReachabilityStatus; +- (long long)networkStatusForFlags:(unsigned int)arg1; +- (long long)localWiFiStatusForFlags:(unsigned int)arg1; +- (void)dealloc; + +@end + +@interface IMNetworkAvailability : NSObject +{ + NSString *_guid; + NSTimer *_timer; + void *_context; + double _timeout; + double _wifiTimeout; + double _startTime; + unsigned long long _flags; + unsigned long long _options; + CDUnknownBlockType _completionBlock; +} + +@property(nonatomic) void *context; // @synthesize context=_context; +- (void)cancel; +- (void)start; +- (void)_setTimer; +- (void)_timerHit:(id)arg1; +- (void)_cancel; +- (void)dealloc; +- (id)initWithFlags:(unsigned long long)arg1 timeout:(double)arg2 wifiTimeout:(double)arg3 completionBlock:(CDUnknownBlockType)arg4; +- (id)initWithFlags:(unsigned long long)arg1 options:(unsigned long long)arg2 timeout:(double)arg3 wifiTimeout:(double)arg4 completionBlock:(CDUnknownBlockType)arg5; + +@end + +@interface IMMultiQueue : NSObject +{ + NSMutableDictionary *_queueMap; + NSObject *_queue; +} + +- (void)_addBlock:(CDUnknownBlockType)arg1 withGUID:(id)arg2 forKey:(id)arg3 description:(id)arg4; +- (void)addBlock:(CDUnknownBlockType)arg1 forKey:(id)arg2 description:(id)arg3; +- (void)addBlock:(CDUnknownBlockType)arg1 withTimeout:(double)arg2 forKey:(id)arg3 description:(id)arg4; +- (void)_popEnqueuedBlockWithGUID:(id)arg1 key:(id)arg2; +- (void)dealloc; +- (id)initWithQueue:(id)arg1; +- (id)init; + +@end + +@interface IMWeakObjectCache : NSObject +{ + NSMutableDictionary *_weakObjectCache; + struct _opaque_pthread_mutex_t _tableLock; +} + ++ (id)sharedInstance; +- (void)removeObject:(id)arg1 key:(id)arg2; +- (id)objectForKey:(id)arg1; +- (id)copyObjectForKey:(id)arg1; +- (id)copyOrSetObject:(id)arg1 forKey:(id)arg2; +- (void)dealloc; +- (id)init; + +@end + + +@interface IMPurgableObject : NSObject +{ + id _instanceObject; + CDUnknownBlockType _setupBlock; + CDUnknownBlockType _cleanupBlock; + NSObject *_queue; +} + +- (void)_receivedMemoryWarning:(id)arg1; +- (id)instance; +- (void)_cleanupInstance; +- (void)_setupInstance; +- (void)dealloc; +- (id)initWithSetupBlock:(CDUnknownBlockType)arg1 cleanupBlock:(CDUnknownBlockType)arg2 queue:(id)arg3; + +@end + +@interface IMWeakReference : NSObject +{ + id _object; + unsigned long long _objectAddress; +} + ++ (id)weakRefWithObject:(id)arg1; +- (id)object; +- (id)initRefWithObject:(id)arg1; +- (id)copyObject; +- (BOOL)isEqual:(id)arg1; +- (unsigned long long)hash; +- (void)dealloc; + +@end + +@interface IMDoubleLinkedListNode : NSObject +{ + IMDoubleLinkedListNode *_prev; + IMDoubleLinkedListNode *_next; + id _object; +} + +@property(retain) id object; // @synthesize object=_object; +@property(retain) IMDoubleLinkedListNode *next; // @synthesize next=_next; +@property(retain) IMDoubleLinkedListNode *prev; // @synthesize prev=_prev; +- (void)orphan; +- (void)removeFromList; +- (void)dealloc; +- (id)initWithObject:(id)arg1; + +@end + +@interface IMDoubleLinkedList : NSObject +{ + IMDoubleLinkedListNode *_first; + IMDoubleLinkedListNode *_last; + unsigned long long _count; +} + +@property(readonly) unsigned long long count; // @synthesize count=_count; +@property(retain) IMDoubleLinkedListNode *last; // @synthesize last=_last; +@property(retain) IMDoubleLinkedListNode *first; // @synthesize first=_first; +- (BOOL)containsObject:(id)arg1; +- (id)allObjects; +- (void)removeAllObjects; +- (void)removeLinkedListNode:(id)arg1; +- (void)pushLinkedListNode:(id)arg1; +- (void)appendLinkedListNode:(id)arg1; +- (id)popObject; +- (void)pushObject:(id)arg1; +- (void)appendObject:(id)arg1; +- (void)dealloc; +- (id)init; + +@end + +@interface OSLogHandleManager : NSObject +{ +} + ++ (id)sharedInstance; + +@end + +@interface _IMPingPacketData : NSObject +{ + int _sequenceNumber; + BOOL _timedOut; + int _error; + struct timeval _timeSent; + double _rtt; +} + +@property(readonly, nonatomic) double rtt; // @synthesize rtt=_rtt; +@property(readonly, nonatomic) int error; // @synthesize error=_error; +@property(readonly, nonatomic) struct timeval timeSent; // @synthesize timeSent=_timeSent; +@property(readonly, nonatomic) BOOL timedOut; // @synthesize timedOut=_timedOut; +@property(readonly, nonatomic) int sequenceNumber; // @synthesize sequenceNumber=_sequenceNumber; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (void)_returnPacketArrived; +- (void)_markPacketAsTimedOut:(double)arg1; +- (id)initWithSequeneceNumber:(int)arg1 timesent:(struct timeval *)arg2 error:(int)arg3; + +@end + +@interface IMPingStatistics : NSObject +{ + double _packetLossRate; + double _medianRoundtripTime; + double _averageRoundtripTime; + double _minRoundtripTime; + double _maxRoundtripTime; + double _standardDeviationRoundtripTime; + double _sumRoundtripTimes; + int _numPingsTransmitted; + int _numPingsReceived; + int _numPacketsSuccessfullySent; +} + +@property(nonatomic, setter=_setStandardDeviationRoundtripTime:) double standardDeviationRoundtripTime; // @synthesize standardDeviationRoundtripTime=_standardDeviationRoundtripTime; +@property(readonly, nonatomic) int packetsSuccessfullySent; // @synthesize packetsSuccessfullySent=_numPacketsSuccessfullySent; +@property(readonly, nonatomic) int numPingsTransmitted; // @synthesize numPingsTransmitted=_numPingsTransmitted; +@property(readonly, nonatomic) int numPingsReceived; // @synthesize numPingsReceived=_numPingsReceived; +@property(readonly, nonatomic) double averageRoundtripTime; // @synthesize averageRoundtripTime=_averageRoundtripTime; +@property(nonatomic, setter=_setMinRoundtripTime:) double minRoundtripTime; // @synthesize minRoundtripTime=_minRoundtripTime; +@property(nonatomic, setter=_setMedianRoundtripTime:) double medianRoundtripTime; // @synthesize medianRoundtripTime=_medianRoundtripTime; +@property(nonatomic, setter=_setMaxRoundtripTime:) double maxRoundtripTime; // @synthesize maxRoundtripTime=_maxRoundtripTime; +- (id)description; +@property(readonly, nonatomic) double packetLossRate; // @synthesize packetLossRate=_packetLossRate; +- (void)_addReceivedPacket:(double)arg1; +- (void)_addTransmittedPacket:(BOOL)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)initWithMaxRTT:(double)arg1 medianRTT:(double)arg2 avgRTT:(double)arg3 minRTT:(double)arg4 transmitted:(int)arg5 successful:(int)arg6 received:(int)arg7; + +@end + +@interface _IMPingStatisticsCollector : NSObject +{ + _IMPingPacketData *_timestampArray[160]; + NSMutableArray *_roundTriptimes; + NSMutableString *_stringToWriteToFile; + IMPingStatistics *_stats; +} + +- (double)_computeStandardDeviation:(id)arg1 numPings:(int)arg2 averageRTT:(double)arg3; +- (double)_computeMedianTime:(id)arg1; +- (id)pingStatsForLastNSeconds:(double)arg1; +- (id)pingStats; +- (BOOL)logStatsToFile:(id)arg1 error:(id *)arg2; +- (void)timeoutOldSequenceNumbers:(double)arg1; +- (void)addEchoReplyPacket:(int)arg1; +- (struct timeval)timeSentForPacket:(int)arg1; +- (void)dealloc; +- (void)addEchoPacket:(int)arg1 packetTimestamp:(struct timeval)arg2 error:(int)arg3; +- (id)init; + +@end + +@interface IMPingTest : NSObject +{ + NSString *_address; + BOOL _usesWifi; + id _collector; + BOOL _isRunning; + NSObject *_sendTimer; + NSObject *_socketReadSource; + double _secondsToRun; +} + +@property(readonly, nonatomic) double secondsToRun; // @synthesize secondsToRun=_secondsToRun; +- (double)longTimeInterval; +//- (void)_setupReadSource:(int)arg1 address:(struct sockaddr_in)arg2 icmID:(unsigned short)arg3 queue:(id)arg4 completionHander:(CDUnknownBlockType)arg5; +//- (void)_doPingWithSocket:(int)arg1 address:(struct sockaddr_in)arg2 timeToRunTestInSeconds:(double)arg3 pingTimeout:(double)arg4 queue:(id)arg5 completionHandler:(CDUnknownBlockType)arg6; +- (int)_setupAndPerformPing:(double)arg1 queue:(id)arg2 completionHandler:(CDUnknownBlockType)arg3; +- (BOOL)writeResultsToFile:(id)arg1 error:(id *)arg2; +- (id)pingStats:(double)arg1; +- (id)pingStats; +- (void)stop; +- (void)startWithTimeout:(double)arg1 queue:(id)arg2 completionHandler:(CDUnknownBlockType)arg3; +- (void)dealloc; +- (id)initWithAddress:(id)arg1 wifi:(BOOL)arg2; + +@end + +@interface IMPowerAssertion : NSObject +{ + unsigned int _assertion; + NSString *_identifier; +} + +- (id)description; +- (void)dealloc; +- (id)initWithIdentifier:(id)arg1; +- (id)initWithIdentifier:(id)arg1 timeout:(double)arg2; + +@end + +@interface NSBundle (FezBundleHelpers) +- (id)_cachedMainBundleResourcePath; +@end + +@interface NSObject (FezAdditions) +- (BOOL)isNull; +@end + +@interface NSProtocolChecker (FezAdditions) +- (id)_imMethodSignatureForSelector:(SEL)arg1; +@end + +@interface NSNumber (FezAdditions) +- (id)localizedString; +@end + +@interface NSCharacterSet (IMFoundationAdditions) ++ (id)invalidCharactersForFileTransferName; +@end + +@interface NSString (FezAdditions) ++ (id)generatedRoomNameForGroupChat; ++ (id)randomString; ++ (id)copyStringGUIDForObject:(id)arg1; ++ (id)stringGUIDForObject:(id)arg1; ++ (id)stringGUID; ++ (id)copyStringGUID; +- (BOOL)roomNameIsProbablyAutomaticallyGenerated; +- (id)stringByRemovingCharactersFromSet:(id)arg1; +- (id)stringWithLTREmbedding; +- (id)pathStringForDisplay; +- (id)__stringByStrippingAttachmentAndControlCharacters; +- (id)__stringByStrippingControlCharacters; +- (id)uniqueSavePath; +- (id)stringByRemovingWhitespace; +- (struct _NSRange)__rangeOfNewlineInRange:(struct _NSRange)arg1; +- (id)stringByResolvingAndStandardizingPath; +- (BOOL)_appearsToBeBusinessID; +- (BOOL)_appearsToBeDSID; +- (BOOL)_appearsToBePhoneNumber; +- (id)_md5Hash; +- (id)_stripPotentialTokenURIWithToken:(id *)arg1; +- (BOOL)_appearsToBeEmail; +- (id)_IDFromFZIDType:(long long)arg1; +- (id)_URIFromFZIDType:(long long)arg1; +- (id)_URIFromCanonicalizedFZIDType:(long long)arg1; +- (long long)_FZBestGuessFZIDType; +- (id)_bestGuessURIFromCanicalizedID; +- (id)_URIFromCanonicalizedBusinessID; +- (id)_URIFromCanonicalizedDSID; +- (id)_URIFromCanonicalizedPhoneNumber; +- (id)_URIFromCanonicalizedEmail; +- (id)_bestGuessURI; +- (id)_URIFromBusinessID; +- (id)_URIFromDSID; +- (id)_URIFromPhoneNumber; +- (id)_URIFromEmail; +- (long long)_FZIDType; +- (id)_FZIDFromPhoneNumber; +- (id)_FZIDFromEmail; +- (id)_stripFZIDPrefix; +- (id)urlFromString; +- (id)stringByAddingURLEscapes; +- (id)stringByRemovingURLEscapes; +- (id)trimmedString; +- (long long)localizedCompareToString:(id)arg1; +- (unsigned int)unsignedIntValue; +- (unsigned int)hexValue; +- (BOOL)isDirectory; +- (BOOL)isEqualToIgnoringCase:(id)arg1; +@end + +@interface NSURL (FezAdditions) +- (id)__imURLByAppendingQueryString:(id)arg1; +@end + +@interface NSMutableString (FezAdditions) +- (void)replaceNewlinesWithSpaces; +@end + +@interface NSAttributedString (FezAdditions) +- (id)trimmedString; +- (BOOL)attribute:(id)arg1 existsInRange:(struct _NSRange)arg2; +@end + +@interface NSMutableAttributedString (FezAdditions) +- (void)removeCharactersWithAttribute:(id)arg1; +- (void)replaceAttribute:(id)arg1 value:(id)arg2 withValue:(id)arg3; +- (void)replaceNewlinesWithSpaces; +- (void)trimWhitespace; +@end + +@interface NSArray (FezAdditions) +- (id)__imArrayByApplyingBlock:(CDUnknownBlockType)arg1 filter:(CDUnknownBlockType)arg2; +- (id)__imArrayByApplyingBlock:(CDUnknownBlockType)arg1; +- (id)__imArrayByFilteringWithBlock:(CDUnknownBlockType)arg1; +- (void)__imForEach:(CDUnknownBlockType)arg1; +- (BOOL)containsObject:(id)arg1 matchingComparison:(SEL)arg2; +- (long long)indexOfObject:(id)arg1 matchingComparison:(SEL)arg2; +- (BOOL)containsObjectIdenticalTo:(id)arg1; +- (id)__imFirstObject; +- (id)_copyForEnumerating; +- (BOOL)_hasSameMembers:(id)arg1; +- (id)__imDeepCopy; +- (BOOL)__imIsMutable; +- (id)__imSetFromArray; +- (id)__IMStripPotentialTokenURIs; +@end + +@interface NSSet (FezAdditions) +- (id)__imSetByApplyingBlock:(CDUnknownBlockType)arg1; +- (void)__imForEach:(CDUnknownBlockType)arg1; +@end + +@interface NSMutableSet (FezAdditions) ++ (id)nonRetainingSet; +@end + +@interface NSMutableArray (FezAdditions) ++ (id)nonRetainingArray; ++ (id)copyNonRetainingArray; +- (void)removeFirstObject; +@end + +@interface NSDictionary (FezAdditions) ++ (id)dictionaryWithKeyArray:(id)arg1 defaultValue:(id)arg2; ++ (id)dictionaryWithPlistData:(id)arg1; +- (id)__imDeepCopy; +- (id)dictionaryFromChanges:(id)arg1; +- (id)plistData; +- (id)keysOfChangedEntriesComparedTo:(id)arg1; +- (BOOL)__imIsMutable; +@end + +@interface NSData (FezAdditions) ++ (id)__imDataWithRandomBytes:(unsigned long long)arg1; ++ (id)__imDataWithHexString:(id)arg1; +- (id)_FTOptionallyDecompressData; +- (id)_FTDecompressData; +- (id)__imHexString; +- (id)__imHexStringOfBytes:(char *)arg1 withLength:(unsigned long long)arg2; +@end + +@interface NSFileManager (FezAdditions) +- (BOOL)copyItemAtPath:(id)arg1 toPath:(id)arg2 uniquePath:(id *)arg3 error:(id *)arg4; +- (BOOL)moveItemAtPath:(id)arg1 toPath:(id)arg2 uniquePath:(id *)arg3 error:(id *)arg4; +- (BOOL)_moveItemAtPath:(id)arg1 toPath:(id)arg2 uniquePath:(id *)arg3 error:(id *)arg4 asCopy:(BOOL)arg5; +- (id)createUniqueDirectoryWithName:(id)arg1 atPath:(id)arg2 ofType:(id)arg3; +- (id)uniqueFilename:(id)arg1 atPath:(id)arg2 ofType:(id)arg3; +- (BOOL)makeDirectoriesInPath:(id)arg1 mode:(unsigned int)arg2; +- (BOOL)_isPathOnMissingVolume:(id)arg1; +- (id)_randomSimilarFilePathAsPath:(id)arg1; +- (id)_randomTemporaryPathWithFileName:(id)arg1 withAppendedPathComponent:(id)arg2; +- (id)_randomTemporaryPathWithFileName:(id)arg1; +- (id)_randomTemporaryPathWithSuffix:(id)arg1 fileName:(id)arg2 withAppendedPathComponent:(id)arg3; +- (id)_randomTemporaryPathWithSuffix:(id)arg1 fileName:(id)arg2; +- (id)_randomTemporaryPathWithSuffix:(id)arg1 withAppendedPathComponent:(id)arg2; +- (id)_randomTemporaryPathWithSuffix:(id)arg1; +- (id)_generateLinkForURL:(id)arg1; +@end + +@interface NSMutableDictionary (IMFoundation_Additions) ++ (id)nonRetainingKeyAndValueDictionary; ++ (id)nonRetainingDictionary; ++ (id)retainingKeyDictionary; +@end + +@interface NSError (FezAdditions) ++ (id)genericErrorWithFile:(const char *)arg1 function:(const char *)arg2 lineNumber:(long long)arg3; +@end + +@interface NSObject (DelayedPerformAdditions) +- (void)performSelector:(SEL)arg1 withObject:(id)arg2 afterDelay:(double)arg3 ignoreMenuTracking:(BOOL)arg4; +@end + +@interface NSUserDefaults (SpecificDomainAdditions) ++ (id)_IMObjectForKey:(id)arg1 inDomain:(id)arg2; ++ (void)_IMSetObject:(id)arg1 forKey:(id)arg2 inDomain:(id)arg3; ++ (id)_IMAppObjectForKey:(id)arg1; ++ (id)_IMAgentObjectForKey:(id)arg1; +@end + +@interface NSDictionary (DictionaryTypeChecking) +- (id)_dataForKey:(id)arg1; +- (id)_stringForKey:(id)arg1; +- (id)_numberForKey:(id)arg1; +- (id)_arrayForKey:(id)arg1; +- (id)_dictionaryForKey:(id)arg1; +@end + +@interface NSThread (_IMThreadBlockSupport) ++ (void)_im_runBlock:(CDUnknownBlockType)arg1; +- (void)__im_performBlock:(CDUnknownBlockType)arg1 afterDelay:(double)arg2 modes:(id)arg3; +- (void)__im_performBlock:(CDUnknownBlockType)arg1 afterDelay:(double)arg2; +- (void)__im_performBlock:(CDUnknownBlockType)arg1 waitUntilDone:(BOOL)arg2 modes:(id)arg3; +- (void)__im_performBlock:(CDUnknownBlockType)arg1 waitUntilDone:(BOOL)arg2; +- (void)__im_performBlock:(CDUnknownBlockType)arg1 modes:(id)arg2; +- (void)__im_performBlock:(CDUnknownBlockType)arg1; +@end + +@interface NSObject (_IMSupportMessagingProxy) +- (id)__im_getInvocation:(id *)arg1; +- (id)__im_afterDelay:(double)arg1 modes:(id)arg2; +- (id)__im_afterDelay:(double)arg1; +- (id)__im_onThread:(id)arg1; +- (id)__im_onThread:(id)arg1 immediateForMatchingThread:(BOOL)arg2; +- (id)__im_onDetachedThread; +- (id)__im_onMainThreadIfNecessary; +- (id)__im_onMainThread; +@end + +@interface NSMutableArray (IMMutableArrayRandomization) +- (void)__imRandomizeArray; +@end + +@interface NSString (IMFastFormatAdditions) +- (id)_imInitWithFormat:(id)arg1 arguments:(struct __va_list_tag [1])arg2; +@end + +@interface NSProtocolChecker (IMFixComplileWarnings) +- (id)initWithProtocol:(id)arg1; +@end + +@interface NSDictionary (HFSFileAttributes) +@property(readonly, nonatomic) unsigned long long fileHFSResourceForkSize; +@property(readonly, nonatomic) unsigned short fileHFSFlags; +@end + +@interface NSData (FezSecurityAdditions) +@property(readonly, nonatomic) NSData *SHA256Data; +@property(readonly, nonatomic) NSString *SHA1HexString; +@property(readonly, nonatomic) NSData *SHA1Data; +@end + +@interface NSInvocation (IMInvocationQueueAdditions) +- (BOOL)wantsReturnValue; +@end + +@interface NSString (MobileMeHelpers) +@property(readonly, nonatomic) NSString *stripMobileMSuffixIfPresent; +@property(readonly, nonatomic) BOOL hasMobileMeSuffix; +@property(readonly, nonatomic) NSString *mobileMeDomain; +@end + +@interface NSNotificationCenter (_IMNotificationCenterAdditions) +- (void)__mainThreadPostNotificationName:(id)arg1 object:(id)arg2 userInfo:(id)arg3; +- (void)__mainThreadPostNotificationName:(id)arg1 object:(id)arg2; +- (void)__mainThreadPostNotification:(id)arg1; +- (void)postNotificationName:(id)arg1; +@end + +@interface NSArray (MyersDiff) +- (void)differencesFromArray:(id)arg1 usingComparator:(CDUnknownBlockType)arg2 removedIndexes:(id *)arg3 insertedIndexes:(id *)arg4; +- (void)differencesFromArray:(id)arg1 removedIndexes:(id *)arg2 insertedIndexes:(id *)arg3; +@end + diff --git a/Dumped Classes/IMSharedUtilities_ClassDump.h b/Dumped Classes/IMSharedUtilities_ClassDump.h new file mode 100644 index 0000000..a49ab41 --- /dev/null +++ b/Dumped Classes/IMSharedUtilities_ClassDump.h @@ -0,0 +1,1698 @@ +// +// Generated by class-dump 3.5 (64 bit). +// +// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard. +// + +#pragma mark Blocks + +typedef void (^CDUnknownBlockType)(void); // return type and parameters are unknown + +#pragma mark Named Structures + +struct IMFileLocation_t { + char *_field1; + char *_field2; + char *_field3; + char *_field4; + int _field5; +}; + +struct IMPreviewConstraints { + double _field1; + struct CGSize _field2; + double _field3; + char _field4; +}; + +struct _TidyDoc { + int _field1; +}; + +struct __va_list_tag { + unsigned int _field1; + unsigned int _field2; + void *_field3; + void *_field4; +}; + +#pragma mark - + +// +// File: Versions/A/IMSharedUtilities +// UUID: 889CA3DD-770D-3AAB-85AE-7A6E5B8E4FAE +// +// Arch: x86_64 +// Current version: 1.0.0 +// Compatibility version: 1.0.0 +// Source version: 1981.1.15.0.0 +// +// Objective-C Garbage Collection: Unsupported +// + +@interface IMItem : NSObject +{ + NSString *_handle; + NSString *_service; + NSString *_account; + NSString *_unformattedID; + NSString *_accountID; + NSString *_roomName; + NSDictionary *_senderInfo; + NSString *_guid; + NSDate *_time; + NSString *_countryCode; + long long _messageID; + id _context; + long long _type; + NSString *_balloonBundleID; + unsigned long long _sortID; + NSString *_destinationCallerID; + NSDate *_clientSendTime; + NSString *_personCentric; + long long _cloudKitSyncState; + NSString *_cloudKitRecordID; + NSData *_cloudKitServerChangeTokenBlob; + NSString *_cloudKitRecordChangeTag; + NSString *_parentChatID; + long long _srCloudKitSyncState; + NSString *_srCloudKitRecordID; + NSString *_srCloudKitRecordChangeTag; +} + ++ (BOOL)supportsSecureCoding; ++ (Class)classForMessageItemDictionary:(id)arg1; ++ (Class)classForIMItemType:(long long)arg1; +@property(copy, nonatomic) NSString *srCloudKitRecordChangeTag; // @synthesize srCloudKitRecordChangeTag=_srCloudKitRecordChangeTag; +@property(copy, nonatomic) NSString *srCloudKitRecordID; // @synthesize srCloudKitRecordID=_srCloudKitRecordID; +@property(nonatomic) long long srCloudKitSyncState; // @synthesize srCloudKitSyncState=_srCloudKitSyncState; +@property(copy, nonatomic) NSString *parentChatID; // @synthesize parentChatID=_parentChatID; +@property(copy, nonatomic) NSString *cloudKitRecordChangeTag; // @synthesize cloudKitRecordChangeTag=_cloudKitRecordChangeTag; +@property(copy, nonatomic) NSData *cloudKitServerChangeTokenBlob; // @synthesize cloudKitServerChangeTokenBlob=_cloudKitServerChangeTokenBlob; +@property(copy, nonatomic) NSString *cloudKitRecordID; // @synthesize cloudKitRecordID=_cloudKitRecordID; +@property(nonatomic) long long cloudKitSyncState; // @synthesize cloudKitSyncState=_cloudKitSyncState; +@property(retain, nonatomic) NSString *personCentric; // @synthesize personCentric=_personCentric; +@property(retain, nonatomic) NSDate *clientSendTime; // @synthesize clientSendTime=_clientSendTime; +@property(retain, nonatomic) NSString *destinationCallerID; // @synthesize destinationCallerID=_destinationCallerID; +@property(nonatomic) unsigned long long sortID; // @synthesize sortID=_sortID; +@property(retain, nonatomic) NSString *balloonBundleID; // @synthesize balloonBundleID=_balloonBundleID; +@property(nonatomic) long long type; // @synthesize type=_type; +@property(retain, nonatomic) id context; // @synthesize context=_context; +@property(nonatomic, setter=_setMessageID:) long long messageID; // @synthesize messageID=_messageID; +@property(retain, nonatomic) NSString *countryCode; // @synthesize countryCode=_countryCode; +@property(retain, nonatomic) NSDate *time; // @synthesize time=_time; +@property(retain, nonatomic) NSString *guid; // @synthesize guid=_guid; +@property(retain, nonatomic) NSDictionary *senderInfo; // @synthesize senderInfo=_senderInfo; +@property(retain, nonatomic) NSString *roomName; // @synthesize roomName=_roomName; +@property(retain, nonatomic) NSString *accountID; // @synthesize accountID=_accountID; +@property(retain, nonatomic) NSString *unformattedID; // @synthesize unformattedID=_unformattedID; +@property(retain, nonatomic) NSString *account; // @synthesize account=_account; +@property(retain, nonatomic) NSString *service; // @synthesize service=_service; +@property(retain, nonatomic) NSString *handle; // @synthesize handle=_handle; +@property(readonly, nonatomic) BOOL isLastMessageCandidate; +@property(readonly, nonatomic) BOOL isFirstMessageCandidate; +- (unsigned long long)hash; +- (BOOL)isOlderThanItem:(id)arg1; +- (BOOL)isEqual:(id)arg1; +@property(retain, nonatomic) NSString *personCentricID; +@property(retain, nonatomic) NSString *sender; +@property(readonly, nonatomic) BOOL isFromMe; +- (id)dictionaryRepresentation; +- (id)copyDictionaryRepresentation; +- (id)initWithIMRemoteObjectSerializedDictionary:(id)arg1; +- (void)encodeWithIMRemoteObjectSerializedDictionary:(id)arg1; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithCoder:(id)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (void)dealloc; +- (id)initWithSenderInfo:(id)arg1 time:(id)arg2 guid:(id)arg3 messageID:(long long)arg4 account:(id)arg5 accountID:(id)arg6 service:(id)arg7 handle:(id)arg8 roomName:(id)arg9 unformattedID:(id)arg10 countryCode:(id)arg11 type:(long long)arg12; +- (id)initWithSender:(id)arg1 time:(id)arg2 guid:(id)arg3 type:(long long)arg4; +- (id)initWithDictionary:(id)arg1; +- (id)description; +- (struct _NSRange)associatedMessageRange; +- (BOOL)isSticker; +- (BOOL)isMessageEdit; +- (BOOL)isBreadcrumb; +- (BOOL)isMessageAcknowledgment; +- (long long)associatedMessageType; +- (id)associatedMessageGUID; +- (BOOL)isAssociatedMessageItem; +- (id)pluginSessionGUID; +- (id)consumedSessionPayloads; + +@end + + +@protocol IMEventListenerResponse +@property(readonly, nonatomic) NSError *error; +@property(readonly, nonatomic) NSDictionary *userInfo; +@property(readonly, nonatomic, getter=didSucceed) BOOL success; +@end + +@protocol IMKeyValueCollectionStorage +- (void)removeObjectForKey:(id)arg1; +- (id)objectForKey:(id)arg1; +- (void)setObject:(id)arg1 forKey:(id)arg2; +@end + +@protocol IMPreviewGeneratorProtocol ++ (BOOL)shouldShadePreview; ++ (BOOL)shouldScaleUpPreview; ++ (BOOL)writesToDisk; ++ (double)maxUpScale; ++ (NSString *)previewExtension; ++ (NSURL *)generateAndPersistPreviewFromSourceURL:(NSURL *)arg1 withPreviewConstraints:(struct IMPreviewConstraints)arg2 error:(id *)arg3; ++ (struct CGImage *)newPreviewFromSourceURL:(NSURL *)arg1 withPreviewConstraints:(struct IMPreviewConstraints)arg2 error:(id *)arg3; +@end + +@protocol IMRemoteObjectCoding +- (id)initWithIMRemoteObjectSerializedDictionary:(NSDictionary *)arg1; +- (void)encodeWithIMRemoteObjectSerializedDictionary:(NSMutableDictionary *)arg1; +@end + +@protocol IMSingletonOverriding + +@optional +- (BOOL)shouldInvokeSelector:(SEL)arg1 onSingleton:(id)arg2; +- (void)didOverrideSingleton:(id)arg1; +@end + +@protocol IMUTITypeInformation ++ (NSArray *)UTITypes; +@end + + +@interface IMTUConversationItem : IMItem +{ + unsigned long long _flags; +} + +@property(nonatomic) unsigned long long flags; // @synthesize flags=_flags; +- (BOOL)isFromMe; +- (id)conversationUUID; +- (id)copyDictionaryRepresentation; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithDictionary:(id)arg1; +- (id)initWithCoder:(id)arg1; + +@end + + + +@interface IMMessageItem : IMItem +{ + BOOL _blockingRichLinks; + BOOL _updatingDataSourcePayload; + BOOL _backwardsCompatibleVersion; + BOOL _isSOS; + unsigned int _error; + NSString *_subject; + NSString *_plainBody; + NSArray *_fileTransferGUIDs; + unsigned long long _flags; + NSAttributedString *_body; + NSData *_bodyData; + long long _replaceID; + NSDate *_timeRead; + NSDate *_timeDelivered; + NSDate *_timePlayed; + long long _expireState; + NSData *_payloadData; + NSData *_contactsAvatarRecipeData; + NSString *_expressiveSendStyleID; + NSDate *_timeExpressiveSendPlayed; + NSData *_typingIndicatorIcon; + NSDictionary *_messageSummaryInfo; + NSDictionary *_bizIntent; + NSString *_locale; + NSString *_notificationIDSTokenURI; +} + ++ (BOOL)messageContainsSurfDD:(id)arg1; ++ (BOOL)supportsSecureCoding; +@property(nonatomic) BOOL isSOS; // @synthesize isSOS=_isSOS; +@property(nonatomic) BOOL backwardsCompatibleVersion; // @synthesize backwardsCompatibleVersion=_backwardsCompatibleVersion; +@property(nonatomic, getter=isUpdatingDataSourcePayload) BOOL updatingDataSourcePayload; // @synthesize updatingDataSourcePayload=_updatingDataSourcePayload; +@property(retain, nonatomic) NSString *notificationIDSTokenURI; // @synthesize notificationIDSTokenURI=_notificationIDSTokenURI; +@property(nonatomic) BOOL blockingRichLinks; // @synthesize blockingRichLinks=_blockingRichLinks; +@property(retain, nonatomic) NSString *locale; // @synthesize locale=_locale; +@property(retain, nonatomic) NSDictionary *bizIntent; // @synthesize bizIntent=_bizIntent; +@property(retain, nonatomic) NSDictionary *messageSummaryInfo; // @synthesize messageSummaryInfo=_messageSummaryInfo; +@property(retain, nonatomic) NSData *typingIndicatorIcon; // @synthesize typingIndicatorIcon=_typingIndicatorIcon; +@property(retain, nonatomic) NSDate *timeExpressiveSendPlayed; // @synthesize timeExpressiveSendPlayed=_timeExpressiveSendPlayed; +@property(retain, nonatomic) NSString *expressiveSendStyleID; // @synthesize expressiveSendStyleID=_expressiveSendStyleID; +@property(retain, nonatomic) NSData *contactsAvatarRecipeData; // @synthesize contactsAvatarRecipeData=_contactsAvatarRecipeData; +@property(retain, nonatomic) NSData *payloadData; // @synthesize payloadData=_payloadData; +@property(nonatomic) long long expireState; // @synthesize expireState=_expireState; +@property(retain, nonatomic) NSDate *timePlayed; // @synthesize timePlayed=_timePlayed; +@property(retain, nonatomic) NSDate *timeDelivered; // @synthesize timeDelivered=_timeDelivered; +@property(retain, nonatomic) NSDate *timeRead; // @synthesize timeRead=_timeRead; +@property(nonatomic) long long replaceID; // @synthesize replaceID=_replaceID; +@property(retain, nonatomic) NSData *bodyData; // @synthesize bodyData=_bodyData; +@property(nonatomic) unsigned long long flags; // @synthesize flags=_flags; +@property(retain, nonatomic) NSArray *fileTransferGUIDs; // @synthesize fileTransferGUIDs=_fileTransferGUIDs; +@property(nonatomic) unsigned int errorCode; // @synthesize errorCode=_error; +@property(retain, nonatomic) NSString *plainBody; // @synthesize plainBody=_plainBody; +@property(retain, nonatomic) NSString *subject; // @synthesize subject=_subject; +- (id)_localizedBackwardsCompatibleExpressiveSendText; +- (BOOL)isLastMessageCandidate; +- (BOOL)isFirstMessageCandidate; +- (id)description; +@property(readonly, copy, nonatomic) NSAttributedString *breadcrumbText; +- (BOOL)isEqual:(id)arg1; +@property(retain, nonatomic) NSAttributedString *body; // @synthesize body=_body; +- (void)_clearBodyData; +- (void)_regenerateBodyData; +- (void)_regenerateBodyText; +- (void)_generateBodyTextIfNeeded; +- (void)_generateBodyDataIfNeeded; +- (void)adjustIsEmptyFlag; +- (void)_updateFlags:(unsigned long long)arg1; +- (void)setWasDataDetected:(BOOL)arg1; +@property(readonly, nonatomic) BOOL wasDataDetected; +@property(nonatomic) BOOL hasDataDetectorResults; +@property(nonatomic) BOOL isCorrupt; +@property(readonly, nonatomic) BOOL isFromExternalSource; +@property(readonly, nonatomic) BOOL wasDowngraded; +@property(readonly, nonatomic) BOOL isSent; +@property(readonly, nonatomic) BOOL isEmote; +@property(readonly, nonatomic) BOOL isLocatingMessage; +@property(readonly, nonatomic) BOOL isTypingMessage; +@property(readonly, nonatomic) BOOL isPrepared; +@property(readonly, nonatomic) BOOL isDelivered; +- (BOOL)isFromMe; +@property(readonly, nonatomic) BOOL isPlayed; +@property(readonly, nonatomic) BOOL isExpirable; +@property(readonly, nonatomic) BOOL isAudioMessage; +@property(readonly, nonatomic) BOOL isRead; +@property(readonly, nonatomic) BOOL isEmpty; +@property(readonly, nonatomic) BOOL isFinished; +@property(readonly, nonatomic) BOOL isAlert; +- (id)sender; +- (void)dealloc; +- (id)initWithSenderInfo:(id)arg1 time:(id)arg2 timeRead:(id)arg3 timeDelivered:(id)arg4 timePlayed:(id)arg5 subject:(id)arg6 body:(id)arg7 bodyData:(id)arg8 attributes:(id)arg9 fileTransferGUIDs:(id)arg10 flags:(unsigned long long)arg11 guid:(id)arg12 messageID:(long long)arg13 account:(id)arg14 accountID:(id)arg15 service:(id)arg16 handle:(id)arg17 roomName:(id)arg18 unformattedID:(id)arg19 countryCode:(id)arg20 expireState:(long long)arg21 balloonBundleID:(id)arg22 payloadData:(id)arg23 expressiveSendStyleID:(id)arg24 timeExpressiveSendPlayed:(id)arg25 bizIntent:(id)arg26 locale:(id)arg27 errorType:(unsigned int)arg28 type:(long long)arg29; +- (id)initWithSenderInfo:(id)arg1 time:(id)arg2 timeRead:(id)arg3 timeDelivered:(id)arg4 timePlayed:(id)arg5 subject:(id)arg6 body:(id)arg7 bodyData:(id)arg8 attributes:(id)arg9 fileTransferGUIDs:(id)arg10 flags:(unsigned long long)arg11 guid:(id)arg12 messageID:(long long)arg13 account:(id)arg14 accountID:(id)arg15 service:(id)arg16 handle:(id)arg17 roomName:(id)arg18 unformattedID:(id)arg19 countryCode:(id)arg20 expireState:(long long)arg21 balloonBundleID:(id)arg22 payloadData:(id)arg23 expressiveSendStyleID:(id)arg24 timeExpressiveSendPlayed:(id)arg25 bizIntent:(id)arg26 locale:(id)arg27 errorType:(unsigned int)arg28; +- (id)initWithSenderInfo:(id)arg1 time:(id)arg2 guid:(id)arg3 messageID:(long long)arg4 account:(id)arg5 accountID:(id)arg6 service:(id)arg7 handle:(id)arg8 roomName:(id)arg9 unformattedID:(id)arg10 countryCode:(id)arg11; +- (id)initWithSender:(id)arg1 time:(id)arg2 guid:(id)arg3 type:(long long)arg4; +- (id)initWithSender:(id)arg1 time:(id)arg2 body:(id)arg3 attributes:(id)arg4 fileTransferGUIDs:(id)arg5 flags:(unsigned long long)arg6 error:(id)arg7 guid:(id)arg8 type:(long long)arg9; +- (id)initWithSender:(id)arg1 time:(id)arg2 body:(id)arg3 attributes:(id)arg4 fileTransferGUIDs:(id)arg5 flags:(unsigned long long)arg6 error:(id)arg7 guid:(id)arg8; +- (id)copyDictionaryRepresentation; +- (id)initWithDictionary:(id)arg1; +- (id)initWithDictionary:(id)arg1 hint:(id)arg2; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithCoder:(id)arg1; +- (void)enumerateAttachmentGUIDsWithBlock:(CDUnknownBlockType)arg1; +- (id)copyForBackwardsCompatibility; +- (id)copyWithFlags:(unsigned long long)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + +@interface FZMessage : IMMessageItem +{ +} + ++ (BOOL)supportsSecureCoding; +- (id)initWithIMRemoteObjectSerializedDictionary:(id)arg1; +- (void)encodeWithIMRemoteObjectSerializedDictionary:(id)arg1; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithCoder:(id)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; + +@end + + + +@interface IMDeviceConditions : NSObject +{ +} + ++ (id)sharedInstance; +@property(readonly) BOOL isDeviceCharging; +- (id)_batteryStatus; +@property(readonly) BOOL isDeviceOnWifi; + +@end + +@interface IMCoreAutomationNotifications : NSObject +{ + long long _chatsWrittenCount; + long long _messagesWrittenCount; + long long _attachmentsWrittenCount; +} + ++ (id)sharedInstance; +@property(readonly) long long attachmentsWrittenCount; // @synthesize attachmentsWrittenCount=_attachmentsWrittenCount; +@property(readonly) long long messagesWrittenCount; // @synthesize messagesWrittenCount=_messagesWrittenCount; +@property(readonly) long long chatsWrittenCount; // @synthesize chatsWrittenCount=_chatsWrittenCount; +- (void)addNewMessagesSyncedCount:(long long)arg1; +- (void)addNewAttachmentsSyncedCount:(long long)arg1; +- (void)addNewChatsSyncedCount:(long long)arg1; +- (void)postCoreAutomationNotificationFinishedTapToDownload:(id)arg1 downloadedFromCloudKitSuccessfully:(BOOL)arg2; +- (void)postCoreAutomationNotificationFinishedPurgingAttachments:(id)arg1 withErrorString:(id)arg2; +- (void)postCoreAutomationNotificationWithDictionary:(id)arg1 withVerboseLogging:(BOOL)arg2; +- (void)postCoreAutomationNotificationWithAction:(id)arg1; +- (void)postCoreAutomationNotificationFinishedPeriodicSyncNotificationWithStartTime:(id)arg1 chatsDidsync:(BOOL)arg2 messagesDidSync:(BOOL)arg3 attachmentsDidSync:(BOOL)arg4; +- (void)clearSyncCounts; +- (id)init; + +@end + +@interface IMEventNotificationManager : NSObject + +@property long long busyCount; // @synthesize busyCount=_busyCount; +@property(readonly, nonatomic) NSMutableArray *registeredNotificationQueues; // @synthesize registeredNotificationQueues=_registeredNotificationQueues; +//@property(readonly, nonatomic) IMEventListenerList *eventListeners; // @synthesize eventListeners=_eventListeners; +@property double eventTimeout; // @synthesize eventTimeout=_eventTimeout; +//@property(readonly, nonatomic) IMAutomaticEventNotificationQueue *notificationQueue; // @synthesize notificationQueue=_notificationQueue; + +- (void)appendNotificationForEventHandler:(id)arg1 sender:(id)arg2 eventNotificationBlock:(CDUnknownBlockType)arg3; +- (void)pushNotificationForEventHandler:(id)arg1 sender:(id)arg2 eventNotificationBlock:(CDUnknownBlockType)arg3; +- (void)appendNotificationForEventHandler:(id)arg1 eventNotificationBlock:(CDUnknownBlockType)arg2; +- (void)pushNotificationForEventHandler:(id)arg1 eventNotificationBlock:(CDUnknownBlockType)arg2; +- (void)pauseEventNotifications:(BOOL)arg1; +- (void)cancelAllEventNotifications; +- (void)cancelEventNotificationsForEventHandler:(id)arg1; +- (id)createEventListenerForNotificationName:(id)arg1 object:(id)arg2; +- (void)registerEventListener:(id)arg1; +- (void)eventListenerDidFinish:(id)arg1; +- (void)registerNotificationQueue:(id)arg1; +- (void)eventNotificationQueue:(id)arg1 didChangeBusyState:(BOOL)arg2; +@property(readonly, getter=isBusy) BOOL busy; +- (void)dealloc; +- (id)init; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly) unsigned long long hash; +@property(readonly) Class superclass; + +@end + +@interface IMStickerPack : NSObject +{ + NSMutableSet *_stickers; + struct NSString *_GUID; + NSString *_name; + NSURL *_displayAssetURL; + NSURL *_fileURL; + NSString *_appBundleIdentifier; + NSString *_appVersion; +} + +@property(copy, nonatomic) NSString *appVersion; // @synthesize appVersion=_appVersion; +@property(copy, nonatomic) NSString *appBundleIdentifier; // @synthesize appBundleIdentifier=_appBundleIdentifier; +@property(copy, nonatomic) NSURL *fileURL; // @synthesize fileURL=_fileURL; +@property(copy, nonatomic) NSURL *displayAssetURL; // @synthesize displayAssetURL=_displayAssetURL; +@property(copy, nonatomic) NSString *name; // @synthesize name=_name; +@property(copy, nonatomic) NSString *GUID; // @synthesize GUID=_GUID; +- (id)initWithStickerPackProperties:(id)arg1 stickerPackBundleURL:(id)arg2 appBundleIdentifier:(id)arg3 appVersion:(id)arg4; +- (id)_generatePackGUIDWithPackID:(id)arg1 appBundleID:(id)arg2 appVersion:(id)arg3; +- (id)description; +- (id)initWithDictionary:(id)arg1; +- (id)dictionaryRepresentation; +- (void)addSticker:(id)arg1; +- (void)dealloc; +@property(readonly, nonatomic) NSSet *stickers; +- (id)initWithGUID:(struct NSString *)arg1 name:(id)arg2 displayAssetURL:(id)arg3 fileURL:(id)arg4 appBundleIdentifier:(id)arg5 appVersion:(id)arg6; + +@end + + +@interface IMPreviewGeneratorManager : NSObject +{ + NSDictionary *_UTITypes; + NSDictionary *_dynamicTypes; +} + ++ (id)previewGeneratorClasses; ++ (id)sharedInstance; +@property(copy, nonatomic) NSDictionary *dynamicTypes; // @synthesize dynamicTypes=_dynamicTypes; +@property(copy, nonatomic) NSDictionary *UTITypes; // @synthesize UTITypes=_UTITypes; +- (void)dealloc; +- (Class)_classForUTIType:(id)arg1; +- (Class)_previewGeneratorClassForSourceURL:(id)arg1; +- (BOOL)movePreviewToDiskCache:(id)arg1 previewURL:(id)arg2 error:(id *)arg3; +- (BOOL)persistPreviewToDiskCache:(struct CGImage *)arg1 previewURL:(id)arg2 error:(id *)arg3; +- (struct CGImage *)newPreviewFromSourceURL:(id)arg1 withPreviewConstraints:(struct IMPreviewConstraints)arg2 error:(id *)arg3; +- (BOOL)generateAndPersistPreviewFromSourceURL:(id)arg1 previewURL:(id)arg2 previewConstraints:(struct IMPreviewConstraints)arg3 error:(id *)arg4; +- (id)init; + +@end + +@interface IMDeviceUtilities : NSObject +{ +} + ++ (BOOL)IMDeviceIsGreenTea; ++ (BOOL)IMDeviceIsChinaRegion; ++ (BOOL)IMSupportsASTC; + +@end + +@interface IMRecentItem : NSObject +{ + NSNumber *_timestamp; + NSString *_GUID; + NSURL *_fileURL; + NSData *_payloadData; + NSDictionary *_messageItemInfo; + NSString *_accessibilityString; +} + +@property(retain, nonatomic) NSString *accessibilityString; // @synthesize accessibilityString=_accessibilityString; +@property(retain, nonatomic) NSDictionary *messageItemInfo; // @synthesize messageItemInfo=_messageItemInfo; +@property(retain, nonatomic) NSNumber *timestamp; // @synthesize timestamp=_timestamp; +@property(retain, nonatomic) NSData *payloadData; // @synthesize payloadData=_payloadData; +@property(retain, nonatomic) NSURL *fileURL; // @synthesize fileURL=_fileURL; +@property(copy, nonatomic) NSString *GUID; // @synthesize GUID=_GUID; +- (id)asJSONObject; +- (unsigned long long)hash; +- (BOOL)isEqual:(id)arg1; +- (id)initWithGUID:(id)arg1 data:(id)arg2 messageItemInfo:(id)arg3; +- (void)dealloc; + +@end + +@interface IMRecentItemsList : NSObject +{ + NSObject *_diskWritingQueue; +} + ++ (id)sharedInstance; +- (id)_guidForFileURL:(id)arg1; +- (void)_updateRecentsCache:(id)arg1 forDomain:(id)arg2; +- (id)_recentsCacheForDomain:(id)arg1; +- (id)_buildLRUCacheUsingArray:(id)arg1 forDomain:(id)arg2; +- (void)_removeRecentDataPayloadEntryFromDisk:(id)arg1 forDomain:(id)arg2; +- (void)_saveRecentDataPayloadEntryToDisk:(id)arg1 forDomain:(id)arg2; +- (void)_removeRecentDataPayloadEntry:(id)arg1 forDomain:(id)arg2; +- (void)addRecentItemAtFileURL:(id)arg1 GUID:(id)arg2 infoDictionary:(id)arg3 forDomain:(id)arg4; +- (void)_addRecentDataPayloadEntry:(id)arg1 toDomain:(id)arg2; +- (void)fetchRecentItemsForDomain:(id)arg1 completion:(CDUnknownBlockType)arg2; +- (void)fetchRecentStickersWithCompletion:(CDUnknownBlockType)arg1; +- (void)addRecentItemWithData:(id)arg1 GUID:(id)arg2 infoDictionary:(id)arg3 forDomain:(id)arg4; +- (void)deleteRecentsInFirstLaunch; +- (void)deleteAllRecentItemsForDomain:(id)arg1; +- (void)deleteRecentItemWithData:(id)arg1 GUID:(id)arg2 forDomain:(id)arg3; +- (void)deleteRecentItemWithFileURL:(id)arg1 GUID:(id)arg2 forDomain:(id)arg3; +- (void)dispatchCacheUpdateWithBlock:(CDUnknownBlockType)arg1; +- (long long)cacheSizeForDomain:(id)arg1; +- (void)dealloc; +- (id)init; + +@end + + +@interface IMTranscoderTelemetry : NSObject +{ + unsigned char _signpostId; +} + +- (void)emitSignpostTranscodeSkipSourceUTI:(id)arg1; +- (void)emitSignpostTranscodeFinalForDestinationUTI:(id)arg1; +- (void)emitSignpostTranscodeStepForDestinationUTI:(id)arg1; +- (void)emitSignpostNoTranscodeFromUTI:(id)arg1; +- (void)_emitSignpostTranscodeRange:(long long)arg1 begin:(BOOL)arg2; +- (void)_emitSignpostPreviewGenerationRange:(long long)arg1 begin:(BOOL)arg2; +- (void)emitPreviewGenerationEndFromUTI:(id)arg1; +- (void)emitPreviewGenerationBeginFromUTI:(id)arg1; +- (void)emitTranscodeEndFromUTI:(id)arg1; +- (void)emitTranscodeBeginFromUTI:(id)arg1; +- (long long)_telemetryImageTypeForUTI:(id)arg1; +- (id)init; + +@end + +@interface IMLocationShareStatusChangeItem : IMItem +{ + BOOL _actionable; + BOOL _expired; + long long _status; + NSString *_otherCountryCode; + NSString *_otherHandle; + NSString *_otherUnformattedID; + long long _direction; +} + ++ (BOOL)supportsSecureCoding; +@property(nonatomic) long long direction; // @synthesize direction=_direction; +@property(retain, nonatomic) NSString *otherUnformattedID; // @synthesize otherUnformattedID=_otherUnformattedID; +@property(retain, nonatomic) NSString *otherHandle; // @synthesize otherHandle=_otherHandle; +@property(retain, nonatomic) NSString *otherCountryCode; // @synthesize otherCountryCode=_otherCountryCode; +@property(nonatomic) BOOL expired; // @synthesize expired=_expired; +@property(nonatomic) BOOL actionable; // @synthesize actionable=_actionable; +@property(nonatomic) long long status; // @synthesize status=_status; +- (BOOL)isLastMessageCandidate; +- (id)copyDictionaryRepresentation; +- (id)initWithDictionary:(id)arg1; +- (BOOL)isEqual:(id)arg1; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithCoder:(id)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (void)dealloc; + +@end + +@interface IMGroupTitleChangeItem : IMItem +{ + NSString *_title; + NSString *_otherCountryCode; + NSString *_otherHandle; + NSString *_otherUnformattedID; +} + ++ (BOOL)supportsSecureCoding; +@property(retain, nonatomic) NSString *otherUnformattedID; // @synthesize otherUnformattedID=_otherUnformattedID; +@property(retain, nonatomic) NSString *otherHandle; // @synthesize otherHandle=_otherHandle; +@property(retain, nonatomic) NSString *otherCountryCode; // @synthesize otherCountryCode=_otherCountryCode; +@property(retain, nonatomic) NSString *title; // @synthesize title=_title; +- (id)copyDictionaryRepresentation; +- (id)initWithDictionary:(id)arg1; +- (BOOL)isEqual:(id)arg1; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithCoder:(id)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (void)dealloc; + +@end + +@interface IMCTSMSUtilities : NSObject +{ +} + ++ (BOOL)IMMessagesFilteringSettingForPreferedSubscription; ++ (void)IMSynchronizePreferredSubscriptionMMSCapabilityToWatch; ++ (void)IMSynchronizeMMSCapabilityToWatch:(BOOL)arg1; ++ (BOOL)MMSRestrictedModeEnabledForPhoneNumber:(id)arg1 simID:(id)arg2 reset:(BOOL)arg3; ++ (BOOL)IMMMSRestrictedModeEnabledForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (BOOL)IMMMSEagerUploadDisabledInCarrierBundleForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (BOOL)IMIsEagerUploadEnabledForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (BOOL)IMShouldShowMMSEmailAddress:(id)arg1 simID:(id)arg2; ++ (id)IMMMSEmailAddressToMatchForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (unsigned long long)IMiMessageMaxTransferVideoFileSizeForWifiForPhoneNumber:(unsigned long long *)arg1 cellSize:(unsigned long long *)arg2 serverConfigurationBag:(id)arg3 phoneNumber:(id)arg4 simID:(id)arg5; ++ (unsigned long long)IMiMessageMaxTransferAudioFileSizeForWifiForPhoneNumber:(unsigned long long *)arg1 cellSize:(unsigned long long *)arg2 serverConfigurationBag:(id)arg3 phoneNumber:(id)arg4 simID:(id)arg5; ++ (void)IMiMessageMaxTransferFileSizeForWifiForPhoneNumber:(unsigned long long *)arg1 cellSize:(unsigned long long *)arg2 serverConfigurationBag:(id)arg3 phoneNumber:(id)arg4 simID:(id)arg5; ++ (double)IMMMSMaximumDurationWithPreset:(id)arg1 phoneNumber:(id)arg2 simID:(id)arg3; ++ (double)IMMMSMaximumVideoDurationForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (double)IMMMSMaximumAudioDurationForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (BOOL)IMMMSSupportsH264VideoForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (int)IMMMSMaxImageDimensionForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (int)IMMMSMaxRecipientsForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (BOOL)IMMMSGroupTextOnlyMessagesSendAsMMSForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (int)IMMMSMaximumMessageByteCountForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (int)IMMMSMaximumSlideCountForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (BOOL)IMMMSSupportedAndConfiguredForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (unsigned long long)IMReadAttachmentPreviewTranscodingQualitySizeCarrierValueForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (BOOL)IMReadEnablePreviewTranscodingQualityCarrierValueForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (BOOL)IMMMSEnabledForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (id)IMPhoneNumbersEnabledForMultipleSubscriptionDevice; ++ (BOOL)IMReadMMSUserOverrideForPhoneNumber:(id)arg1 simID:(id)arg2; ++ (id)IMUniqueIdentifierForPhoneNumber:(id)arg1 simID:(id)arg2; + +@end + +@interface IMEventNotificationQueue : NSObject +{ + BOOL _paused; + BOOL _scheduled; + BOOL _busy; +} + +//@property(readonly, nonatomic) IMDoubleLinkedList *eventNotificationList; // @synthesize eventNotificationList=_eventNotificationList; +//@property __weak id delegate; // @synthesize delegate=_delegate; +- (BOOL)containsNotificationTarget:(id)arg1; +@property(readonly) long long count; +@property(getter=isPaused) BOOL paused; // @synthesize paused=_paused; +@property(readonly, getter=isScheduled) BOOL scheduled; // @synthesize scheduled=_scheduled; +- (void)_didChangePausedState:(BOOL)arg1; +- (void)pushEventTarget:(id)arg1 sender:(id)arg2 eventNotificationBlock:(CDUnknownBlockType)arg3; +- (void)appendEventTarget:(id)arg1 sender:(id)arg2 eventNotificationBlock:(CDUnknownBlockType)arg3; +- (void)pushEventTarget:(id)arg1 eventNotificationBlock:(CDUnknownBlockType)arg2; +- (void)appendEventTarget:(id)arg1 eventNotificationBlock:(CDUnknownBlockType)arg2; +- (void)cancelAllEventNotifications; +- (void)cancelEventNotificationsForNotificationTarget:(id)arg1; +- (void)_didCancelNotifications; +- (void)appendEventNotification:(id)arg1; +- (void)pushEventNotification:(id)arg1; +- (void)_didAddNotification:(id)arg1; +- (void)_processQueue; +- (void)_invokeNotifications; +- (void)enumerateObjectsUsingBlock:(CDUnknownBlockType)arg1; +- (void)_willProcessQueue; +- (void)_didProcessQueue; +- (void)_setBusy:(BOOL)arg1; +- (void)_didChangeBusyState:(BOOL)arg1; +@property(readonly, getter=isBusy) BOOL busy; // @synthesize busy=_busy; +- (void)_invokeEvent:(id)arg1; +- (void)_scheduleIfNeeded:(BOOL)arg1; +- (void)_dispatchProcessQueue; +- (id)init; + +@end + +@interface IMAutomaticEventNotificationQueue : IMEventNotificationQueue +{ +} + +- (void)_didCancelNotifications; +- (void)_didAddNotification:(id)arg1; +- (void)_didProcessQueue; +- (void)_invokeEvent:(id)arg1; + +@end + +@interface IMEventNotificationBroadcaster : IMEventNotificationQueue +{ +} + +- (void)broadcastEventToListeners:(CDUnknownBlockType)arg1; +- (void)_didProcessQueue; +- (void)_willProcessQueue; + +@end + +@interface IMEventNotification : NSObject // IMDoubleLinkedListNode +{ + id _target; + id _sender; + CDUnknownBlockType _eventNotificationWithSenderBlock; + CDUnknownBlockType _eventNotificationBlock; +} + ++ (id)eventNotification:(id)arg1; ++ (id)eventNotification:(id)arg1 sender:(id)arg2 eventNotificationBlock:(CDUnknownBlockType)arg3; ++ (id)eventNotification:(id)arg1 eventNotificationBlock:(CDUnknownBlockType)arg2; +@property(copy) CDUnknownBlockType eventNotificationBlock; // @synthesize eventNotificationBlock=_eventNotificationBlock; +@property(copy) CDUnknownBlockType eventNotificationWithSenderBlock; // @synthesize eventNotificationWithSenderBlock=_eventNotificationWithSenderBlock; +@property __weak id sender; // @synthesize sender=_sender; +@property __weak id target; // @synthesize target=_target; +- (void)cache; +- (BOOL)wasCancelled; +- (void)cancel; +- (BOOL)invoke; + +@end + + +@interface IMParticipantChangeItem : IMItem +{ + long long _changeType; + NSString *_otherCountryCode; + NSString *_otherHandle; + NSString *_otherUnformattedID; +} + ++ (BOOL)supportsSecureCoding; +@property(retain, nonatomic) NSString *otherUnformattedID; // @synthesize otherUnformattedID=_otherUnformattedID; +@property(retain, nonatomic) NSString *otherHandle; // @synthesize otherHandle=_otherHandle; +@property(retain, nonatomic) NSString *otherCountryCode; // @synthesize otherCountryCode=_otherCountryCode; +@property(nonatomic) long long changeType; // @synthesize changeType=_changeType; +- (BOOL)isEqual:(id)arg1; +- (id)copyDictionaryRepresentation; +- (id)initWithDictionary:(id)arg1; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithCoder:(id)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (void)dealloc; + +@end + + +@interface IMKeyValueCollectionUserDefaultsStorage : NSObject +{ + NSString *_domain; +} + +@property(readonly, copy, nonatomic) NSString *domain; // @synthesize domain=_domain; + +@property(readonly, copy) NSString *description; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (void)removeObjectForKey:(id)arg1; +- (void)setObject:(id)arg1 forKey:(id)arg2; +- (id)objectForKey:(id)arg1; +- (void)_actuallyWriteObject:(id)arg1 forKey:(id)arg2; +- (id)_actuallyReadObjectForKey:(id)arg1; +- (id)_decodeData:(id)arg1 forKey:(id)arg2; +- (id)initWithDomain:(id)arg1; +- (id)init; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; + +@property(readonly) Class superclass; + +@end + +@interface IMImageUtilities : NSObject +{ +} + ++ (struct CGImage *)newThumbnailForTargetSize:(struct CGSize)arg1 imageSize:(struct CGSize)arg2 imageSource:(struct CGImageSource *)arg3 atIndex:(unsigned long long)arg4 mode:(long long)arg5 scale:(double)arg6; ++ (struct CGImage *)newThumbnailForTargetSize:(struct CGSize)arg1 imageSize:(struct CGSize)arg2 imageSource:(struct CGImageSource *)arg3 mode:(long long)arg4 scale:(double)arg5; ++ (BOOL)persistCPBitmapWithImage:(struct CGImage *)arg1 url:(id)arg2; ++ (void)sampleImageEdges:(char *)arg1 usingRect:(struct CGRect)arg2 forMostlyWhitePixels:(unsigned long long *)arg3 otherPixels:(unsigned long long *)arg4 bytesPerRow:(long long)arg5; ++ (struct CGSize)imageRefPxSize:(struct CGImage *)arg1; ++ (struct CGSize)imageSourcePxSize:(struct CGImageSource *)arg1; + +@end + +@interface IMOneTimeCodeUtilities : NSObject +{ +} + +- (id)createOTCFromMessageBody:(id)arg1 sender:(id)arg2 guid:(id)arg3; +- (BOOL)isValidOneTimeCode:(id)arg1; + +@end + +@interface IMEventListenerResponse : NSObject +{ + BOOL _success; + NSDictionary *_userInfo; + NSError *_error; +} + +@property(retain, nonatomic) NSError *error; // @synthesize error=_error; +@property(retain, nonatomic) NSDictionary *userInfo; // @synthesize userInfo=_userInfo; +@property(nonatomic, getter=didSucceed) BOOL success; // @synthesize success=_success; +@property(readonly, copy) NSString *description; +- (id)initWithSuccess:(BOOL)arg1 userInfo:(id)arg2 error:(id)arg3; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly) Class superclass; + +@end + +@interface IMEventListener : NSObject +{ + BOOL _willRepeat; + double _timerStart; + NSObject *_semaphore; + double _timeListeningStarted; + double _timeListeningStopped; + double _timeLastEventReceived; + double _timeout; + unsigned long long _eventCount; + id _target; + CDUnknownBlockType _completionBlock; + CDUnknownBlockType _willInvokeCompletion; + CDUnknownBlockType _didInvokeCompletion; +} + ++ (id)eventListenerWithNotificationName:(id)arg1 object:(id)arg2; ++ (id)eventListener; ++ (id)allListeners; ++ (id)_mutableListenerDictionary; +@property(nonatomic) BOOL willRepeat; // @synthesize willRepeat=_willRepeat; +@property(copy) CDUnknownBlockType didInvokeCompletion; // @synthesize didInvokeCompletion=_didInvokeCompletion; +@property(copy) CDUnknownBlockType willInvokeCompletion; // @synthesize willInvokeCompletion=_willInvokeCompletion; +@property __weak id target; // @synthesize target=_target; +@property(readonly) unsigned long long eventCount; // @synthesize eventCount=_eventCount; +@property(readonly, nonatomic) NSObject *semaphore; // @synthesize semaphore=_semaphore; +@property(nonatomic) double timerStart; // @synthesize timerStart=_timerStart; +- (void)_didReceiveEvent:(BOOL)arg1 userInfo:(id)arg2 error:(id)arg3; +@property double timeout; // @synthesize timeout=_timeout; +- (void)reset; +@property(copy) CDUnknownBlockType completionBlock; // @synthesize completionBlock=_completionBlock; +@property(readonly) double elapsedWaitingTime; +@property(readonly) double timeLastEventReceived; // @synthesize timeLastEventReceived=_timeLastEventReceived; +@property(readonly) double timeListeningStopped; // @synthesize timeListeningStopped=_timeListeningStopped; +@property(readonly) double timeListeningStarted; // @synthesize timeListeningStarted=_timeListeningStarted; +- (void)startListening; +- (void)stopListening; +@property(readonly, getter=isListening) BOOL listening; +- (void)startListeningForEventTarget:(id)arg1 completion:(CDUnknownBlockType)arg2; +- (void)startListeningForEventTarget:(id)arg1 sendStartingEvent:(CDUnknownBlockType)arg2 completion:(CDUnknownBlockType)arg3; +- (void)waitForCompletion; +- (void)_dispatchStartEventBlock:(CDUnknownBlockType)arg1; +- (void)_startTimeoutTimerIfNeeded; +- (void)_reset; +- (void)willReset; +- (void)_cancelTimeoutTimer; +- (void)_stopListening; +- (void)willStopListening; +- (void)_startListening; +- (void)willStartListening; +- (void)_handleTimeout:(id)arg1; +- (void)_invokeCompletion:(BOOL)arg1 userInfo:(id)arg2 error:(id)arg3; +- (id)createResult:(BOOL)arg1 userInfo:(id)arg2 error:(id)arg3; +- (void)_addToListeners; +- (void)_removeFromListeners; + +@end + +@interface IMNotificationCenterEventListener : IMEventListener +{ + NSString *_registeredNotificationName; + NSString *_notificationName; + id _notificationObject; +} + ++ (id)eventListenerForNotificationName:(id)arg1 object:(id)arg2; ++ (id)eventListenerForNotificationName:(id)arg1; +@property(readonly) __weak id notificationObject; // @synthesize notificationObject=_notificationObject; +@property(readonly, copy) NSString *notificationName; // @synthesize notificationName=_notificationName; +@property(readonly, nonatomic) NSString *registeredNotificationName; // @synthesize registeredNotificationName=_registeredNotificationName; +- (void)willReset; +- (void)willStopListening; +- (void)willStartListening; +- (BOOL)isListening; +- (void)dealloc; +- (void)registerForNotificationName:(id)arg1 object:(id)arg2; +- (void)registerForNotificationName:(id)arg1; +- (void)_notification:(id)arg1; +@property(readonly) BOOL isRegisteredForNotification; + +@end + +@interface IMEventListenerReference : NSObject +{ + IMEventListener *_eventListener; +} + +@property(readonly, nonatomic) __weak IMEventListener *eventListener; // @synthesize eventListener=_eventListener; +- (id)initWithEventListener:(id)arg1; + +@end + +@interface IMEventListenerList : NSObject +{ + NSMutableArray *_eventListeners; +} + +- (void)enumerateObjectsUsingBlock:(CDUnknownBlockType)arg1; +- (BOOL)containsObject:(id)arg1; +- (void)removeObject:(id)arg1; +- (void)addObject:(id)arg1; +- (unsigned long long)count; +- (id)init; + +@end + +@interface IMSticker : NSObject +{ + NSURL *_fileURL; + struct NSString *_stickerGUID; + struct NSString *_stickerPackGUID; + NSString *_accessibilityLabel; + NSString *_moodCategory; + NSString *_stickerName; + NSData *_recipe; + NSString *_ballonBundleID; + NSDictionary *_attributionInfo; +} + +@property(copy, nonatomic) NSDictionary *attributionInfo; // @synthesize attributionInfo=_attributionInfo; +@property(copy, nonatomic) NSString *ballonBundleID; // @synthesize ballonBundleID=_ballonBundleID; +@property(retain, nonatomic) NSData *recipe; // @synthesize recipe=_recipe; +@property(copy, nonatomic) NSString *stickerName; // @synthesize stickerName=_stickerName; +@property(copy, nonatomic) NSString *moodCategory; // @synthesize moodCategory=_moodCategory; +@property(copy, nonatomic) NSString *accessibilityLabel; // @synthesize accessibilityLabel=_accessibilityLabel; +@property(readonly, copy, nonatomic) NSString *stickerPackGUID; // @synthesize stickerPackGUID=_stickerPackGUID; +@property(readonly, copy, nonatomic) NSString *stickerGUID; // @synthesize stickerGUID=_stickerGUID; +@property(readonly, copy, nonatomic) NSURL *fileURL; // @synthesize fileURL=_fileURL; +- (id)initWithStickerPropertyDictionary:(id)arg1 stickerPackID:(struct NSString *)arg2 stickerPackBundlePath:(id)arg3; +- (unsigned long long)hash; +- (BOOL)isEqual:(id)arg1; +- (void)dealloc; +- (id)description; +- (id)initWithStickerID:(struct NSString *)arg1 stickerPackID:(struct NSString *)arg2 fileURL:(id)arg3 accessibilityLabel:(id)arg4 moodCategory:(id)arg5 stickerName:(id)arg6; +- (id)init; + +@end + +@interface IMMessageActionItem : IMItem +{ + long long _actionType; + NSString *_otherCountryCode; + NSString *_otherHandle; + NSString *_otherUnformattedID; + NSString *_originalMessageGUID; +} + ++ (BOOL)supportsSecureCoding; +@property(retain, nonatomic) NSString *originalMessageGUID; // @synthesize originalMessageGUID=_originalMessageGUID; +@property(retain, nonatomic) NSString *otherUnformattedID; // @synthesize otherUnformattedID=_otherUnformattedID; +@property(retain, nonatomic) NSString *otherHandle; // @synthesize otherHandle=_otherHandle; +@property(retain, nonatomic) NSString *otherCountryCode; // @synthesize otherCountryCode=_otherCountryCode; +@property(nonatomic) long long actionType; // @synthesize actionType=_actionType; +- (BOOL)isEqual:(id)arg1; +- (id)copyDictionaryRepresentation; +- (id)initWithDictionary:(id)arg1; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithCoder:(id)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)description; +- (void)dealloc; + +@end + + +@interface IMXMLParserContext : NSObject +{ + NSData *_inContentAsData; +} + +@property(readonly, retain) NSData *inContentAsData; // @synthesize inContentAsData=_inContentAsData; +@property(readonly, retain) NSArray *resultsForLogging; +@property(readonly, retain) NSString *name; +- (id)inContent; +- (void)reset; +- (void)dealloc; +- (id)initWithContentAsData:(id)arg1; +- (id)initWithContent:(id)arg1; + +@end + +@interface IMXMLParserFrame : NSObject +{ +} + +- (void)parser:(id)arg1 context:(id)arg2 foundIgnorableWhitespace:(id)arg3; +- (void)parser:(id)arg1 context:(id)arg2 foundCharacters:(id)arg3; +- (void)parser:(id)arg1 context:(id)arg2 didEndElement:(id)arg3 namespaceURI:(id)arg4 qualifiedName:(id)arg5; +- (void)parser:(id)arg1 context:(id)arg2 didStartElement:(id)arg3 namespaceURI:(id)arg4 qualifiedName:(id)arg5 attributes:(id)arg6; + +@end + +@interface IMSharedMessageSendingUtilities : NSObject +{ + long long _serviceAvailability; +} + ++ (void)_setupAccountMonitor; ++ (id)sharedInstance; ++ (void)initialize; +@property long long serviceAvailability; // @synthesize serviceAvailability=_serviceAvailability; +- (BOOL)canSendPhotos:(int)arg1 videos:(int)arg2 audioClips:(int)arg3; +- (long long)_maxMMSMessageByteCount; +- (long long)_maxMMSAttachmentCount; +- (BOOL)_isiMessageSupported; +- (BOOL)isSupportedAttachmentUTI:(id)arg1; +- (BOOL)isiMessageEnabled; +- (BOOL)isMMSEnabled; +- (BOOL)canSendText; +- (id)_managedConfigAppWhitelist; +- (void)_updateServiceAvailability; +- (BOOL)_canSendText; +- (BOOL)_hasSMSCapability; + +@end + +@interface IMXMLParser : NSObject +{ + NSXMLParser *_parser; + IMXMLParserContext *_context; + IMXMLParserFrame *_topFrame; + NSMutableArray *_otherFrames; + struct _TidyDoc *_tidyDoc; + struct __CFDictionary *_framespace; +} + ++ (id)sharedInstance; +- (void)parser:(id)arg1 parseErrorOccurred:(id)arg2; +- (void)parser:(id)arg1 foundIgnorableWhitespace:(id)arg2; +- (void)parser:(id)arg1 foundCharacters:(id)arg2; +- (void)parser:(id)arg1 didEndElement:(id)arg2 namespaceURI:(id)arg3 qualifiedName:(id)arg4; +- (void)parser:(id)arg1 didStartElement:(id)arg2 namespaceURI:(id)arg3 qualifiedName:(id)arg4 attributes:(id)arg5; +- (BOOL)parseContext:(id)arg1; +- (id)_newDataByTidyingData:(id)arg1; +- (void)_teardownTidy; +- (void)_setupTidy; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly) Class superclass; + +@end + + +@interface IMToSuperParserContext : IMXMLParserContext +{ + unsigned long long _underlineCount; + unsigned long long _boldCount; + unsigned long long _italicCount; + unsigned long long _strikethroughCount; + unsigned long long _messagePartNumber; + NSMutableArray *_fontFamilyStack; + NSMutableArray *_fontSizeStack; + NSMutableArray *_linkStack; + NSMutableArray *_backgroundColorStack; + NSMutableArray *_foregroundColorStack; + NSMutableDictionary *_currentAttributes; + BOOL _didAddBodyAttributes; + NSMutableAttributedString *_body; + NSMutableArray *_fileTransferGUIDs; + NSString *_backgroundColor; + NSString *_foregroundColor; + long long _baseWritingDirection; +} + +@property long long baseWritingDirection; // @synthesize baseWritingDirection=_baseWritingDirection; +@property(copy, nonatomic) NSString *foregroundColor; // @synthesize foregroundColor=_foregroundColor; +@property(copy, nonatomic) NSString *backgroundColor; // @synthesize backgroundColor=_backgroundColor; +@property(retain, nonatomic) NSArray *fileTransferGUIDs; // @synthesize fileTransferGUIDs=_fileTransferGUIDs; +@property(readonly, nonatomic) NSAttributedString *body; +- (void)appendBreadcrumbText:(id)arg1 withOptions:(unsigned int)arg2; +- (void)appendInlineImageWithGUID:(id)arg1 filename:(id)arg2 width:(long long)arg3 height:(long long)arg4 emoji:(long long)arg5; +- (void)appendInlineImageWithGUID:(id)arg1 filename:(id)arg2 width:(long long)arg3 height:(long long)arg4; +- (void)appendFileTransferWithGUID:(id)arg1; +- (void)appendString:(id)arg1; +- (void)_incrementMessagePartNumber; +- (void)popForegroundColor; +- (void)pushForegroundColor:(id)arg1; +- (void)popBackgroundColor; +- (void)pushBackgroundColor:(id)arg1; +- (void)popLink; +- (void)pushLink:(id)arg1; +- (void)popFontSize; +- (void)pushFontSize:(id)arg1; +- (void)popFontFamily; +- (void)pushFontFamily:(id)arg1; +- (void)_popValueFromStack:(id)arg1 attributeName:(id)arg2; +- (void)_pushValue:(id)arg1 ontoStack:(id)arg2 attributeName:(id)arg3; +- (void)decrementStrikethroughCount; +- (void)incrementStrikethroughCount; +- (void)decrementUnderlineCount; +- (void)incrementUnderlineCount; +- (void)decrementItalicCount; +- (void)incrementItalicCount; +- (void)decrementBoldCount; +- (void)incrementBoldCount; +- (void)_updateFontSize; +- (void)_updateFontFamily; +- (void)_clearIvars; +- (void)_initIvars; +- (id)resultsForLogging; +- (id)name; +- (void)reset; +- (void)dealloc; + +@end + +@interface IMToSuperParserFrame : IMXMLParserFrame +{ +} + +- (void)parser:(id)arg1 context:(id)arg2 foundIgnorableWhitespace:(id)arg3; +- (void)parser:(id)arg1 context:(id)arg2 foundCharacters:(id)arg3; +- (void)parser:(id)arg1 context:(id)arg2 didEndElement:(id)arg3 namespaceURI:(id)arg4 qualifiedName:(id)arg5; +- (void)parser:(id)arg1 context:(id)arg2 didStartElement:(id)arg3 namespaceURI:(id)arg4 qualifiedName:(id)arg5 attributes:(id)arg6; + +@end + +@interface IMMessageNotificationTimer : NSObject +{ + NSDate *_date; + NSNumber *_numberDingsLeft; +} + +@property(readonly, nonatomic) NSNumber *numberDingsLeft; // @synthesize numberDingsLeft=_numberDingsLeft; +@property(retain, nonatomic) NSDate *date; // @synthesize date=_date; +- (void)reduceNumberDingsLeft; +@property(readonly, nonatomic) BOOL areDingsRemaining; +- (void)dealloc; +- (id)initWithDate:(id)arg1; + +@end + +@interface IMMessageNotificationTimeManager : NSObject +{ + NSMutableDictionary *_chatsStartTimeDictionary; + NSString *_latestIDSTokenURI; +} + ++ (id)sharedInstance; +@property(retain, nonatomic) NSString *latestIDSTokenURI; // @synthesize latestIDSTokenURI=_latestIDSTokenURI; +@property(retain, nonatomic) NSMutableDictionary *chatsStartTimeDictionary; // @synthesize chatsStartTimeDictionary=_chatsStartTimeDictionary; +- (void)acquireAssertionToUnsuspendProcess; +- (void)sendNotificationMessageIfNeededForIncomingMessageFromChatIdentifier:(id)arg1; +- (void)setLatestNotificationIDSTokenURI:(id)arg1; +- (BOOL)_shouldSendNotificationForChatIdentifier:(id)arg1; +- (long long)_getToneTimeWindow; +- (long long)_getTimeWindowOverride; +- (BOOL)_isToneToggleSwitchOn; +- (void)setDate:(id)arg1 forChatIdentifier:(id)arg2; +- (void)tearDownSessionForChatIdentifier:(id)arg1; +- (void)dealloc; +- (id)init; + +@end + + +@interface IMPreviewGenerator : NSObject +{ +} + ++ (struct CGRect)_scaledTargetRectForSize:(struct CGSize)arg1 andThumbnailSize:(struct CGSize)arg2; ++ (double)_scaleFactorForThumbnailWithSize:(struct CGSize)arg1 constraints:(struct IMPreviewConstraints)arg2 targetPxSize:(struct CGSize)arg3; ++ (struct CGImage *)newCroppedAndRescaledImageFromImage:(struct CGImage *)arg1 constraints:(struct IMPreviewConstraints)arg2 targetPxSize:(struct CGSize)arg3; ++ (id)generateAndPersistPreviewFromSourceURL:(id)arg1 withPreviewConstraints:(struct IMPreviewConstraints)arg2 error:(id *)arg3; ++ (struct CGImage *)newPreviewFromSourceURL:(id)arg1 withPreviewConstraints:(struct IMPreviewConstraints)arg2 error:(id *)arg3; ++ (double)maxUpScale; ++ (BOOL)shouldShadePreview; ++ (BOOL)shouldScaleUpPreview; ++ (BOOL)writesToDisk; ++ (id)previewExtension; ++ (id)UTITypes; + +@end + +@interface IMGroupBlacklistManager : NSObject +{ + NSDate *_lastModifiedDate; +} + ++ (id)sharedInstance; ++ (id)groupsBlacklistFilename; +@property(retain) NSDate *lastModifiedDate; // @synthesize lastModifiedDate=_lastModifiedDate; + +- (void)reloadIfNeeded; +- (void)_updateLastModifiedDate:(id)arg1; +- (void)loadFromFile:(id)arg1; +- (void)loadData; +- (void)save; +- (BOOL)isFeatureDisabled; +- (BOOL)isGroupInBlacklist:(id)arg1; +- (void)blacklistGroupId:(id)arg1; +- (BOOL)hasFileChanged; +- (id)initFromFile:(id)arg1; +- (id)init; + +@end + + +@interface IMAttributedStringParserContext : NSObject +{ + NSAttributedString *_inString; +} + +@property(readonly, retain) NSAttributedString *inString; // @synthesize inString=_inString; +- (id)parser:(id)arg1 preprocessedAttributesForAttributes:(id)arg2 range:(struct _NSRange)arg3; +@property(readonly) BOOL shouldPreprocess; +- (void)parserDidEnd:(id)arg1; +- (void)parser:(id)arg1 foundAttributes:(id)arg2 inRange:(struct _NSRange)arg3; +- (void)parserDidStart:(id)arg1; +@property(readonly, retain) NSArray *resultsForLogging; +@property(readonly, retain) NSString *name; +- (void)dealloc; +- (id)initWithAttributedString:(id)arg1; + +@end + +@interface IMAttributedStringParser : NSObject +{ + IMAttributedStringParserContext *_context; +} + ++ (id)sharedInstance; +- (void)parseContext:(id)arg1; +- (void)_preprocessWithContext:(id)arg1 string:(id *)arg2; + +@end + + +@interface IMAssociatedMessageItem : IMMessageItem +{ + NSString *_associatedMessageGUID; + long long _associatedMessageType; + NSArray *_consumedSessionPayloads; + struct _NSRange _associatedMessageRange; +} + ++ (BOOL)supportsSecureCoding; +@property(retain, nonatomic) NSArray *consumedSessionPayloads; // @synthesize consumedSessionPayloads=_consumedSessionPayloads; +@property(nonatomic) struct _NSRange associatedMessageRange; // @synthesize associatedMessageRange=_associatedMessageRange; +@property(nonatomic) long long associatedMessageType; // @synthesize associatedMessageType=_associatedMessageType; +@property(retain, nonatomic) NSString *associatedMessageGUID; // @synthesize associatedMessageGUID=_associatedMessageGUID; +- (BOOL)isEqual:(id)arg1; +- (BOOL)isSticker; +- (BOOL)isMessageEdit; +- (BOOL)isBreadcrumb; +- (BOOL)isMessageAcknowledgment; +- (BOOL)isLastMessageCandidate; +- (BOOL)isFirstMessageCandidate; +- (BOOL)isAssociatedMessageItem; +- (id)description; +- (id)copyForBackwardsCompatibility; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)copyDictionaryRepresentation; +- (void)encodeWithCoder:(id)arg1; +- (id)initWithCoder:(id)arg1; +- (void)dealloc; +- (id)initWithMessageItem:(id)arg1; +- (id)initWithSenderInfo:(id)arg1 time:(id)arg2 timeRead:(id)arg3 timeDelivered:(id)arg4 timePlayed:(id)arg5 subject:(id)arg6 body:(id)arg7 bodyData:(id)arg8 attributes:(id)arg9 fileTransferGUIDs:(id)arg10 flags:(unsigned long long)arg11 guid:(id)arg12 messageID:(long long)arg13 account:(id)arg14 accountID:(id)arg15 service:(id)arg16 handle:(id)arg17 roomName:(id)arg18 unformattedID:(id)arg19 countryCode:(id)arg20 expireState:(long long)arg21 balloonBundleID:(id)arg22 payloadData:(id)arg23 expressiveSendStyleID:(id)arg24 timeExpressiveSendPlayed:(id)arg25 errorType:(unsigned int)arg26 associatedMessageGUID:(id)arg27 associatedMessageType:(long long)arg28 associatedMessageRange:(struct _NSRange)arg29 bizIntent:(id)arg30 locale:(id)arg31 messageSummaryInfo:(id)arg32; +- (id)initWithSender:(id)arg1 time:(id)arg2 body:(id)arg3 attributes:(id)arg4 fileTransferGUIDs:(id)arg5 flags:(unsigned long long)arg6 error:(id)arg7 guid:(id)arg8 associatedMessageGUID:(id)arg9 associatedMessageType:(long long)arg10 associatedMessageRange:(struct _NSRange)arg11 messageSummaryInfo:(id)arg12; +- (id)initWithDictionary:(id)arg1 hint:(id)arg2; + +@end + + +@interface IMKeyValueCollectionDictionaryStorage : NSObject +{ + NSMutableDictionary *_dictionary; +} + +@property(readonly, copy) NSString *description; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (void)removeObjectForKey:(id)arg1; +- (void)setObject:(id)arg1 forKey:(id)arg2; +- (id)objectForKey:(id)arg1; +- (id)init; +- (id)initWithDictionary:(id)arg1; +@property(readonly, copy, nonatomic) NSDictionary *dictionary; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly) Class superclass; + +@end + +@interface IMKeyValueCollection : NSObject +{ + long long _batchCount; + id _keyValueStorage; + id /* */ _delegate; + NSMutableDictionary *_recordedChanges; +} + +@property(readonly) NSMutableDictionary *recordedChanges; // @synthesize recordedChanges=_recordedChanges; +@property(nonatomic) __weak id delegate; // @synthesize delegate=_delegate; +@property(readonly, nonatomic) id keyValueStorage; // @synthesize keyValueStorage=_keyValueStorage; + +@property(readonly, copy) NSString *description; +- (void)setString:(id)arg1 forKey:(id)arg2; +- (id)stringForKey:(id)arg1; +- (id)stringForKey:(id)arg1 withDefault:(id)arg2; +- (void)setDouble:(double)arg1 forKey:(id)arg2; +- (double)doubleForKey:(id)arg1; +- (double)doubleForKey:(id)arg1 withDefault:(double)arg2; +- (void)setUint64:(long long)arg1 forKey:(id)arg2; +- (unsigned long long)uint64ForKey:(id)arg1; +- (unsigned long long)uint64ForKey:(id)arg1 withDefault:(unsigned long long)arg2; +- (void)setInt64:(long long)arg1 forKey:(id)arg2; +- (long long)int64ForKey:(id)arg1; +- (long long)int64ForKey:(id)arg1 withDefault:(long long)arg2; +- (void)setInteger:(long long)arg1 forKey:(id)arg2; +- (long long)integerForKey:(id)arg1; +- (long long)integerForKey:(id)arg1 withDefault:(long long)arg2; +- (void)setBool:(BOOL)arg1 forKey:(id)arg2; +- (BOOL)boolForKey:(id)arg1; +- (BOOL)boolForKey:(id)arg1 withDefault:(BOOL)arg2; +- (void)_commitBatchWrite; +- (void)_startBatchWrite; +- (void)removeObjectForKey:(id)arg1; +- (void)setObject:(id)arg1 forKey:(id)arg2; +- (void)_recordChange:(id)arg1 forKey:(id)arg2; +- (void)_setObject:(id)arg1 forKey:(id)arg2; +- (id)objectForKey:(id)arg1 withDefault:(id)arg2; +- (id)objectForKey:(id)arg1; +- (void)_broadcastIfNeeded; +- (void)_notifyListeners; +- (id)initWithKeyValueStorage:(id)arg1; +- (id)copyWithZone:(struct _NSZone *)arg1; +- (id)init; +- (id)errorArrayForKey:(id)arg1; +- (void)addErrorToArray:(id)arg1 forKey:(id)arg2; +- (id)errorForKey:(id)arg1; +- (void)setError:(id)arg1 forKey:(id)arg2; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly) Class superclass; + +@end + +@interface IMBroadcastingKeyValueCollection : IMKeyValueCollection +{ +} + +- (void)_notifyListeners; + +@end + +@interface IMAnimatedImagePreviewGenerator : IMPreviewGenerator +{ +} + ++ (BOOL)writesToDisk; ++ (id)generateAndPersistPreviewFromSourceURL:(id)arg1 withPreviewConstraints:(struct IMPreviewConstraints)arg2 error:(id *)arg3; ++ (id)UTITypes; + +@end + +@interface IMMessageNotificationController : NSObject /* */ +{ + // IDSService *_messageNotificationControllerIDSService; +} + ++ (id)sharedInstance; +// @property(retain, nonatomic) IDSService *messageNotificationControllerIDSService; // @synthesize messageNotificationControllerIDSService=_messageNotificationControllerIDSService; +- (void)_sendNotificationMessageRequest:(id)arg1 toTokenURI:(id)arg2; +- (void)sendNotificationMessageToTokenURI:(id)arg1 withCommmand:(long long)arg2; +- (void)sendNotificationMessageToUniqueID:(id)arg1 withCommmand:(long long)arg2; +- (void)service:(id)arg1 account:(id)arg2 identifier:(id)arg3 didSendWithSuccess:(BOOL)arg4 error:(id)arg5; +- (void)service:(id)arg1 account:(id)arg2 incomingMessage:(id)arg3 fromID:(id)arg4 context:(id)arg5; +- (void)_executeCommandFromMessageRequest:(id)arg1; +- (void)_playTone; +- (id)_copyIDSIdentifierOrDefault:(id)arg1; +- (BOOL)audioAccessoryDeviceWithTokenURIExists:(id)arg1; +- (id)_copyIDForDevice:(id)arg1; +- (BOOL)_deviceIsAudioAccessory:(id)arg1; +- (BOOL)_isCurrentDeviceAudioAccessory; +- (void)dealloc; +- (id)init; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly) unsigned long long hash; +@property(readonly) Class superclass; + +@end + +@interface IMUnarchiverDecoder : NSObject +{ +} + ++ (id)decodeEncodedDataSecurely:(id)arg1 ofClass:(Class)arg2 includesWhitelistedClasses:(id)arg3; ++ (id)_decodeEncodedData:(id)arg1 ofClass:(Class)arg2 includesWhitelistedClasses:(id)arg3; + +@end + +@interface IMXMLReparser : NSObject +{ + NSXMLParser *_parser; + NSMutableString *_output; + // IMXMLReparserContext *_context; + NSError *_error; + unsigned long long _depth; +} + +- (void)parser:(id)arg1 parseErrorOccurred:(id)arg2; +- (void)parser:(id)arg1 foundCharacters:(id)arg2; +- (void)parser:(id)arg1 didEndElement:(id)arg2 namespaceURI:(id)arg3 qualifiedName:(id)arg4; +- (void)parser:(id)arg1 didStartElement:(id)arg2 namespaceURI:(id)arg3 qualifiedName:(id)arg4 attributes:(id)arg5; +- (BOOL)parseWithContext:(id)arg1; + +// Remaining properties +@property(readonly, copy) NSString *debugDescription; +@property(readonly, copy) NSString *description; +@property(readonly) Class superclass; + +@end + +@interface IMXMLReparserContext : NSObject +{ + NSString *_inContent; + NSString *_outContent; + NSDictionary *_attributesToMerge; + NSError *_error; + NSArray *_attributesToPreserve; +} + +@property(readonly, copy, nonatomic) NSString *outContent; // @synthesize outContent=_outContent; +@property(readonly, retain, nonatomic) NSError *error; // @synthesize error=_error; +@property(readonly, retain, nonatomic) NSDictionary *attributesToMerge; // @synthesize attributesToMerge=_attributesToMerge; +@property(readonly, retain, nonatomic) NSArray *attributesToPreserve; // @synthesize attributesToPreserve=_attributesToPreserve; +@property(readonly, retain) NSString *_inContent; // @synthesize _inContent; +- (void)_setOutContent:(id)arg1 error:(id)arg2; +- (void)dealloc; +- (id)initWithContent:(id)arg1 attributesToPreserve:(id)arg2 attributesToMerge:(id)arg3; + +@end + +@interface IMImagePreviewGenerator : IMPreviewGenerator +{ +} + ++ (struct CGImage *)newThumbnailFillToSize:(struct CGSize)arg1 imagePxSize:(struct CGSize)arg2 imageSource:(struct CGImageSource *)arg3 scale:(double)arg4; ++ (struct CGImage *)newPreviewFromSourceURL:(id)arg1 withPreviewConstraints:(struct IMPreviewConstraints)arg2 error:(id *)arg3; ++ (id)UTITypes; ++ (id)fetchUTITypes; + +@end + + +@interface IMAKAppleIDAuthenticationController : NSObject +{ +} + ++ (id)IMAKUserInfoChangedSecurityLevelKey; ++ (id)IMAKUserInfoChangedAltDSIDKey; ++ (id)IMAKUserInfoChangedNotification; + +@end + +@interface IMFileTransfer : NSObject +{ + BOOL _isIncoming; + BOOL _isDirectory; + BOOL _shouldAttemptToResume; + BOOL _wasRegisteredAsStandalone; + BOOL _shouldForceArchive; + BOOL _needsWrapper; + BOOL _isAuxImage; + BOOL _isAuxVideo; + BOOL _isSticker; + BOOL _hideAttachment; + BOOL _isLocation; + BOOL _isContact; + BOOL _appMessageFallbackImage; + unsigned short _hfsFlags; + unsigned int _hfsType; + unsigned int _hfsCreator; + double _lastUpdatedInterval; + double _lastAveragedInterval; + unsigned long long _lastAveragedBytes; + NSString *_guid; + NSString *_messageGUID; + NSDate *_startDate; + NSDate *_createdDate; + long long _transferState; + NSString *_filename; + NSURL *_transferDataURL; + NSString *_utiType; + NSString *_mimeType; + NSString *_accountID; + NSString *_otherPerson; + unsigned long long _currentBytes; + unsigned long long _totalBytes; + unsigned long long _averageTransferRate; + long long _error; + NSString *_errorDescription; + NSDictionary *_localUserInfo; + NSString *_transferredFilename; + NSDictionary *_transcoderUserInfo; + NSDictionary *_AuxTranscoderUserInfo; + NSDictionary *_stickerUserInfo; + NSArray *_attachmentSendContexts; + long long _cloudKitSyncState; + NSData *_cloudKitServerChangeTokenBlob; + NSString *_cloudKitRecordID; + long long _srCloudKitSyncState; + NSData *_srCloudKitServerChangeTokenBlob; + NSString *_srCloudKitRecordID; + NSURL *_localURL; + NSURL *_temporaryHighQualityLocalURL; + NSDictionary *_attributionInfo; + NSString *_originalGUID; +} + ++ (id)guidByStrippingAuxPrefix:(id)arg1; ++ (id)AuxGUIDFromFileTransferGUID:(id)arg1; ++ (BOOL)_doesLocalURLRequireArchiving:(id)arg1; +@property(retain, nonatomic) NSString *originalGUID; // @synthesize originalGUID=_originalGUID; +@property(nonatomic) BOOL appMessageFallbackImage; // @synthesize appMessageFallbackImage=_appMessageFallbackImage; +@property(retain, nonatomic) NSDictionary *attributionInfo; // @synthesize attributionInfo=_attributionInfo; +@property(retain, nonatomic) NSURL *temporaryHighQualityLocalURL; // @synthesize temporaryHighQualityLocalURL=_temporaryHighQualityLocalURL; +@property(retain, nonatomic, setter=_setLocalURL:) NSURL *localURL; // @synthesize localURL=_localURL; +@property(retain, nonatomic) NSString *srCloudKitRecordID; // @synthesize srCloudKitRecordID=_srCloudKitRecordID; +@property(retain, nonatomic) NSData *srCloudKitServerChangeTokenBlob; // @synthesize srCloudKitServerChangeTokenBlob=_srCloudKitServerChangeTokenBlob; +@property(nonatomic) long long srCloudKitSyncState; // @synthesize srCloudKitSyncState=_srCloudKitSyncState; +@property(retain, nonatomic) NSString *cloudKitRecordID; // @synthesize cloudKitRecordID=_cloudKitRecordID; +@property(retain, nonatomic) NSData *cloudKitServerChangeTokenBlob; // @synthesize cloudKitServerChangeTokenBlob=_cloudKitServerChangeTokenBlob; +@property(nonatomic) long long cloudKitSyncState; // @synthesize cloudKitSyncState=_cloudKitSyncState; +@property(nonatomic) BOOL isContact; // @synthesize isContact=_isContact; +@property(nonatomic) BOOL isLocation; // @synthesize isLocation=_isLocation; +@property(retain, nonatomic) NSArray *attachmentSendContexts; // @synthesize attachmentSendContexts=_attachmentSendContexts; +@property(nonatomic) BOOL hideAttachment; // @synthesize hideAttachment=_hideAttachment; +@property(retain, nonatomic) NSDictionary *stickerUserInfo; // @synthesize stickerUserInfo=_stickerUserInfo; +@property(nonatomic) BOOL isSticker; // @synthesize isSticker=_isSticker; +@property(retain, nonatomic) NSDictionary *AuxTranscoderUserInfo; // @synthesize AuxTranscoderUserInfo=_AuxTranscoderUserInfo; +@property(nonatomic) BOOL isAuxVideo; // @synthesize isAuxVideo=_isAuxVideo; +@property(nonatomic) BOOL isAuxImage; // @synthesize isAuxImage=_isAuxImage; +@property(retain, nonatomic) NSDictionary *transcoderUserInfo; // @synthesize transcoderUserInfo=_transcoderUserInfo; +@property(retain, nonatomic) NSString *transferredFilename; // @synthesize transferredFilename=_transferredFilename; +@property(nonatomic, setter=_setNeedsWrapper:) BOOL _needsWrapper; // @synthesize _needsWrapper; +@property(retain, nonatomic) NSDictionary *userInfo; // @synthesize userInfo=_localUserInfo; +@property(nonatomic, setter=_setForceArchive:) BOOL shouldForceArchive; // @synthesize shouldForceArchive=_shouldForceArchive; +@property(nonatomic, setter=setRegisteredAsStandalone:) BOOL wasRegisteredAsStandalone; // @synthesize wasRegisteredAsStandalone=_wasRegisteredAsStandalone; +@property(retain, nonatomic, setter=_setErrorDescription:) NSString *errorDescription; // @synthesize errorDescription=_errorDescription; +@property(nonatomic, setter=_setError:) long long error; // @synthesize error=_error; +@property(nonatomic) BOOL shouldAttemptToResume; // @synthesize shouldAttemptToResume=_shouldAttemptToResume; +@property(nonatomic) BOOL isDirectory; // @synthesize isDirectory=_isDirectory; +@property(nonatomic) unsigned long long averageTransferRate; // @synthesize averageTransferRate=_averageTransferRate; +@property(nonatomic) unsigned long long totalBytes; // @synthesize totalBytes=_totalBytes; +@property(nonatomic) unsigned long long currentBytes; // @synthesize currentBytes=_currentBytes; +@property(retain, nonatomic) NSString *otherPerson; // @synthesize otherPerson=_otherPerson; +@property(retain, nonatomic) NSString *accountID; // @synthesize accountID=_accountID; +@property(nonatomic) unsigned int hfsCreator; // @synthesize hfsCreator=_hfsCreator; +@property(nonatomic) unsigned short hfsFlags; // @synthesize hfsFlags=_hfsFlags; +@property(nonatomic) unsigned int hfsType; // @synthesize hfsType=_hfsType; +@property(retain, nonatomic) NSString *type; // @synthesize type=_utiType; +@property(retain, nonatomic, setter=_setTransferDataURL:) NSURL *transferDataURL; // @synthesize transferDataURL=_transferDataURL; +@property(retain, nonatomic) NSString *filename; // @synthesize filename=_filename; +@property(nonatomic) BOOL isIncoming; // @synthesize isIncoming=_isIncoming; +@property(nonatomic, setter=_setTransferState:) long long transferState; // @synthesize transferState=_transferState; +@property(retain, nonatomic) NSDate *createdDate; // @synthesize createdDate=_createdDate; +@property(retain, nonatomic, setter=_setStartDate:) NSDate *startDate; // @synthesize startDate=_startDate; +@property(retain, nonatomic) NSString *messageGUID; // @synthesize messageGUID=_messageGUID; +@property(retain, nonatomic) NSString *guid; // @synthesize guid=_guid; +@property(readonly, nonatomic) unsigned long long _lastAveragedBytes; // @synthesize _lastAveragedBytes; +@property(nonatomic, setter=_setLastAveragedInterval:) double _lastAveragedInterval; // @synthesize _lastAveragedInterval; +@property(nonatomic, setter=_setLastUpdatedInterval:) double _lastUpdatedInterval; // @synthesize _lastUpdatedInterval; +- (id)_auxVideoPathIfItExists; +- (id)description; +@property(readonly, retain, nonatomic) NSString *mimeType; // @synthesize mimeType=_mimeType; +@property(retain, nonatomic, setter=_setLocalPath:) NSString *localPath; +@property(readonly, retain, nonatomic) NSString *permanentHighQualityLocalPath; +@property(readonly, retain, nonatomic) NSString *temporaryHighQualityLocalPath; +@property(readonly, nonatomic) BOOL isOpusAudioMessage; +@property(readonly, nonatomic) BOOL isAutoloopVideo; +@property(readonly, nonatomic) BOOL isRecipeBasedSticker; +@property(readonly, nonatomic) BOOL existsAtLocalPath; +@property(readonly, retain, nonatomic) NSString *displayName; +@property(readonly, nonatomic) BOOL isFinished; +@property(readonly, nonatomic) BOOL canBeAccepted; +- (void)_calculateTypeInformation; +- (id)_dictionaryRepresentation; +- (BOOL)_updateWithDictionaryRepresentation:(id)arg1; +- (void)_clear; +- (void)_setDirectory:(BOOL)arg1 hfsType:(unsigned int)arg2 hfsCreator:(unsigned int)arg3 hfsFlags:(unsigned short)arg4; +- (void)_setAveragedTransferRate:(unsigned long long)arg1 lastAveragedInterval:(double)arg2 lastAveragedBytes:(unsigned long long)arg3; +- (void)_setCurrentBytes:(unsigned long long)arg1 totalBytes:(unsigned long long)arg2; +- (void)_setAccount:(id)arg1 otherPerson:(id)arg2; +- (id)_initWithGUID:(id)arg1 filename:(id)arg2 isDirectory:(BOOL)arg3 localURL:(id)arg4 account:(id)arg5 otherPerson:(id)arg6 totalBytes:(unsigned long long)arg7 hfsType:(unsigned int)arg8 hfsCreator:(unsigned int)arg9 hfsFlags:(unsigned short)arg10 isIncoming:(BOOL)arg11; +- (id)init; +- (void)dealloc; + +@end + +@interface NSArray (IMIDSUtilities) +- (id)__im_canonicalIDSIDsFromAddresses; +@end + +@interface NSDate (IMCoreAdditions) ++ (BOOL)useCourierTime; ++ (id)__im_dateWithCurrentServerTime; ++ (id)__im_dateWithNanosecondTimeIntervalSinceReferenceDate:(long long)arg1; +- (long long)minutesDifferenceFromDate:(id)arg1; +- (long long)hoursDifferenceFromDate:(id)arg1; +- (long long)differenceFromDate:(id)arg1; +- (BOOL)isToday; +- (long long)__im_nanosecondTimeInterval; +@end + +@interface NSObject (IMTesting) +- (void)__im_performAsynchronousTest:(CDUnknownBlockType)arg1 name:(id)arg2 timeout:(double)arg3 finalizer:(CDUnknownBlockType)arg4; +@end + +@interface NSProxy (NSProxyWorkaround) +- (BOOL)__isSingletonProxy__im; +@end + +@interface NSObject (IMSingleton) ++ (BOOL)isSingleton; ++ (BOOL)replaceSingletonWithSubclass:(id)arg1; ++ (BOOL)isSingletonOverridden; ++ (id)overriddenSingleton; ++ (void)replaceSingletonWithObject:(id)arg1; ++ (void)removeSingletonOverride; ++ (void)overrideSingletonWithObject:(id)arg1; ++ (id)singletonOverride; ++ (id)_createSingleton__im; +- (BOOL)__isSingletonProxy__im; +@end + +@interface NSDictionary (IMSharedUtilitiesAdditions) +- (unsigned long long)unsignedLongLongValueForKey:(id)arg1 withDefault:(unsigned long long)arg2; +- (long long)longLongValueForKey:(id)arg1 withDefault:(long long)arg2; +- (unsigned long long)unsignedLongValueForKey:(id)arg1 withDefault:(unsigned long long)arg2; +- (long long)longValueForKey:(id)arg1 withDefault:(long long)arg2; +- (float)floatValueForKey:(id)arg1 withDefault:(float)arg2; +- (double)doubleValueForKey:(id)arg1 withDefault:(double)arg2; +- (unsigned long long)unsignedIntegerValueForKey:(id)arg1 withDefault:(unsigned long long)arg2; +- (long long)integerValueForKey:(id)arg1 withDefault:(long long)arg2; +- (BOOL)boolValueForKey:(id)arg1 withDefault:(BOOL)arg2; +@end + +@interface NSObject (IMKeyValueCollectionUserDefaultsStorage) +- (BOOL)isArchivable_im; +@end + +@interface NSString (IMKeyValueCollectionUserDefaultsStorage) +- (BOOL)isArchivable_im; +@end + +@interface NSDate (IMKeyValueCollectionUserDefaultsStorage) +- (BOOL)isArchivable_im; +@end + +@interface NSNumber (IMKeyValueCollectionUserDefaultsStorage) +- (BOOL)isArchivable_im; +@end + +@interface NSData (IMKeyValueCollectionUserDefaultsStorage) +- (BOOL)isArchivable_im; +@end + +@interface NSArray (IMKeyValueCollectionUserDefaultsStorage) +- (BOOL)isArchivable_im; +@end + +@interface NSDictionary (IMKeyValueCollectionUserDefaultsStorage) +- (BOOL)isArchivable_im; +@end + +@interface NSString (IMSharedUtilities) +- (id)__im_apfsCompatibleFilename; +- (id)__im_filePathWithVariant:(id)arg1; +@end + +@interface NSDictionary (IMAssocatedMessageItemInfo) ++ (id)dictionaryWithMessageSummaryInfoData:(id)arg1; ++ (id)dictionaryWithAssociatedMessageSummary:(id)arg1 contentType:(unsigned char)arg2 pluginBundleID:(id)arg3 pluginDisplayName:(id)arg4; +@property(readonly, nonatomic) NSString *__im_associatedMessagePluginDisplayName; +@property(readonly, nonatomic) NSString *__im_associatedMessagePluginBundleID; +@property(readonly, nonatomic) NSNumber *__im_associatedMessageContentType; +@property(readonly, nonatomic) NSString *__im_associatedMessageSummary; +@end + +@interface NSData (IMAssociatedMessageItemInfo) ++ (id)dataWithMessageSummaryInfoDictionary:(id)arg1; +@end + +@interface NSURL (IMCoreAdditions) +- (BOOL)__im_conformsToDomain:(id)arg1 domainExtension:(id)arg2; +@end + +@interface NSString (IMEngramUtilities) +- (id)__im_engramDataRepresentation; +@end + +@interface NSData (IMEngramUtilities) +- (id)__im_engramStringRepresentation; +@end + +@interface NSError (IMSharedUtilitiesAdditions) ++ (id)serializedErrorArrayFromErrorArray_im:(id)arg1; ++ (id)errorArrayFromSerializedErrorArray_im:(id)arg1; +- (struct NSDictionary *)serializedError_im; +- (id)initWithSerializedError_im:(struct NSDictionary *)arg1; +@end + diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 3e6ee3e..a2d5f5e 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -131,7 +131,6 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 1A0C445D219A458400F2AC00 /* SOAPlugInControllerProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOAPlugInControllerProtocol.h; sourceTree = ""; }; 1A0C445F219A45B400F2AC00 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 1A0C4461219A45B900F2AC00 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; 1A0C4463219A45C700F2AC00 /* MessagesKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessagesKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/MessagesKit.framework; sourceTree = DEVELOPER_DIR; }; @@ -139,10 +138,9 @@ 1A0C4467219A45D500F2AC00 /* IMCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IMCore.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/IMCore.framework; sourceTree = DEVELOPER_DIR; }; 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridge.h; sourceTree = ""; }; 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridge.m; sourceTree = ""; }; - 1A33B43A219A5ACD0034485A /* OSXReleaseDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OSXReleaseDefaults.xcconfig; sourceTree = ""; }; - 1A33B43B219A5ACD0034485A /* DebugDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DebugDefaults.xcconfig; sourceTree = ""; }; - 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OSXDebugDefaults.xcconfig; sourceTree = ""; }; - 1A33B43D219A5ACD0034485A /* ReleaseDefaults.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ReleaseDefaults.xcconfig; sourceTree = ""; }; + 1A257CB023A8570100A4A2C8 /* IMCore_ClassDump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMCore_ClassDump.h; sourceTree = ""; }; + 1A257CB123A857DF00A4A2C8 /* IMSharedUtilities_ClassDump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMSharedUtilities_ClassDump.h; sourceTree = ""; }; + 1A257CB223A85DF200A4A2C8 /* IMFoundation_ClassDump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMFoundation_ClassDump.h; sourceTree = ""; }; 1A33B43E219A5BD80034485A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 1AA43E8D219EBB2D00EDF1A7 /* MBIMJSONDataResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMJSONDataResponse.h; sourceTree = ""; }; 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMJSONDataResponse.m; sourceTree = ""; }; @@ -297,8 +295,7 @@ children = ( 1A33B43E219A5BD80034485A /* README.md */, CDF62333219A895D00690038 /* kordophone */, - 1A33B439219A5ACD0034485A /* Config Files */, - 1A0C445C219A457C00F2AC00 /* Pilfered Headers */, + 1A0C445C219A457C00F2AC00 /* Dumped Classes */, CD83E162219BE91600F4CCEA /* agentHook */, CD14F18C219E2DB400E7DD22 /* Tests */, 1ACFCDE3219EB28A00E2C237 /* CocoaHTTPServer */, @@ -318,12 +315,14 @@ name = Products; sourceTree = ""; }; - 1A0C445C219A457C00F2AC00 /* Pilfered Headers */ = { + 1A0C445C219A457C00F2AC00 /* Dumped Classes */ = { isa = PBXGroup; children = ( - 1A0C445D219A458400F2AC00 /* SOAPlugInControllerProtocol.h */, + 1A257CB023A8570100A4A2C8 /* IMCore_ClassDump.h */, + 1A257CB223A85DF200A4A2C8 /* IMFoundation_ClassDump.h */, + 1A257CB123A857DF00A4A2C8 /* IMSharedUtilities_ClassDump.h */, ); - path = "Pilfered Headers"; + path = "Dumped Classes"; sourceTree = ""; }; 1A0C445E219A45B400F2AC00 /* Frameworks */ = { @@ -360,17 +359,6 @@ path = Bridge; sourceTree = ""; }; - 1A33B439219A5ACD0034485A /* Config Files */ = { - isa = PBXGroup; - children = ( - 1A33B43A219A5ACD0034485A /* OSXReleaseDefaults.xcconfig */, - 1A33B43B219A5ACD0034485A /* DebugDefaults.xcconfig */, - 1A33B43C219A5ACD0034485A /* OSXDebugDefaults.xcconfig */, - 1A33B43D219A5ACD0034485A /* ReleaseDefaults.xcconfig */, - ); - path = "Config Files"; - sourceTree = ""; - }; 1AA43E90219EBB3400EDF1A7 /* Utilities */ = { isa = PBXGroup; children = ( @@ -1148,7 +1136,7 @@ CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx.internal; + SDKROOT = macosx; SYSTEM_FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", @@ -1163,7 +1151,7 @@ CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx.internal; + SDKROOT = macosx; SYSTEM_FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", diff --git a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme index b3bcf4c..9f27664 100644 --- a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme +++ b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme @@ -27,8 +27,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + + isEnabled = "NO"> - - - -@protocol SOAPlugInControllerProtocol - -- (oneway void)connectPlugIn:(NSString *)plugInName withConnectionHandler:(void (^)(NSXPCListenerEndpoint *))replyHandler; -- (void)reconnect; - -@end diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index 1a88222..f1cbe26 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -16,11 +16,8 @@ #import -#import -#import - -#import -#import +#import "IMCore_ClassDump.h" +#import "IMFoundation_ClassDump.h" static const UInt16 kDefaultPort = 5738; @@ -136,11 +133,11 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; [self registerForNotifications]; - [sDaemonController setDelegate:self]; - [sDaemonListener addHandler:self]; + [[IMDaemonController sharedInstance] setDelegate:(id)self]; + [[[IMDaemonController sharedInstance] listener] addHandler:self]; - if (![sDaemonController hasListenerForID:MBIMBridgeToken]) { - if (![sDaemonController addListenerID:MBIMBridgeToken capabilities:(kFZListenerCapFileTransfers | kFZListenerCapManageStatus | kFZListenerCapChats | kFZListenerCapMessageHistory | kFZListenerCapIDQueries | kFZListenerCapSendMessages)]) { + if (![[IMDaemonController sharedInstance] hasListenerForID:MBIMBridgeToken]) { + if (![[IMDaemonController sharedInstance] addListenerID:MBIMBridgeToken capabilities:(kFZListenerCapFileTransfers | kFZListenerCapManageStatus | kFZListenerCapChats | kFZListenerCapMessageHistory | kFZListenerCapIDQueries | kFZListenerCapSendMessages)]) { MBIMLogFatal(@"Failed to connect to imagent"); [self _terminate]; @@ -153,7 +150,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; - (void)disconnect { - [sDaemonController removeListenerID:MBIMBridgeToken]; + [[IMDaemonController sharedInstance] removeListenerID:MBIMBridgeToken]; } #pragma mark - @@ -196,7 +193,7 @@ static NSString *const MBIMBridgeToken = @"net.buzzert.kordophone"; - (void)_chatRegistryDidLoad:(NSNotification *)notification { - MBIMLogInfo(@"Loaded chat registry. %lu existing chats", (unsigned long)[sChatRegistry numberOfExistingChats]); + MBIMLogInfo(@"Loaded chat registry. %lu existing chats", (unsigned long)[[IMChatRegistry sharedInstance] numberOfExistingChats]); } - (void)_chatItemsDidChange:(NSNotification *)notification diff --git a/kordophone/Bridge/MBIMUpdateQueue.h b/kordophone/Bridge/MBIMUpdateQueue.h index 64d7a1a..9cb7a43 100644 --- a/kordophone/Bridge/MBIMUpdateQueue.h +++ b/kordophone/Bridge/MBIMUpdateQueue.h @@ -6,8 +6,8 @@ // Copyright © 2018 James Magahern. All rights reserved. // -#import -#import +#import "IMCore_ClassDump.h" +#import "IMFoundation_ClassDump.h" NS_ASSUME_NONNULL_BEGIN diff --git a/kordophone/Bridge/Operations/MBIMConversationListOperation.m b/kordophone/Bridge/Operations/MBIMConversationListOperation.m index 076346b..0d22701 100644 --- a/kordophone/Bridge/Operations/MBIMConversationListOperation.m +++ b/kordophone/Bridge/Operations/MBIMConversationListOperation.m @@ -10,7 +10,7 @@ #import "MBIMHTTPUtilities.h" #import "IMChat+Encoded.h" -#import +#import "IMCore_ClassDump.h" @implementation MBIMConversationListOperation @@ -26,7 +26,7 @@ __block NSMutableArray *conversations = [NSMutableArray array]; dispatch_sync([[self class] sharedIMAccessQueue], ^{ - NSArray *chats = [sChatRegistry allExistingChats]; + NSArray *chats = [[IMChatRegistry sharedInstance] allExistingChats]; for (IMChat *chat in chats) { NSDictionary *chatDict = [chat mbim_dictionaryRepresentation]; [conversations addObject:chatDict]; diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m index b7cc8b7..5bbce09 100644 --- a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m @@ -9,7 +9,7 @@ #import "MBIMFetchAttachmentOperation.h" #import "MBIMDataResponse.h" -#import +#import "IMCore_ClassDump.h" @implementation MBIMFetchAttachmentOperation diff --git a/kordophone/Bridge/Operations/MBIMMarkOperation.m b/kordophone/Bridge/Operations/MBIMMarkOperation.m index 08992c7..6e79388 100644 --- a/kordophone/Bridge/Operations/MBIMMarkOperation.m +++ b/kordophone/Bridge/Operations/MBIMMarkOperation.m @@ -7,7 +7,7 @@ // #import "MBIMMarkOperation.h" -#import +#import "IMCore_ClassDump.h" @implementation MBIMMarkOperation @@ -31,7 +31,7 @@ } dispatch_sync([[self class] sharedIMAccessQueue], ^{ - IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; + IMChat *chat = [[IMChatRegistry sharedInstance] existingChatWithGUID:guid]; if (!chat) { MBIMLogInfo(@"Chat with guid: %@ not found", guid); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m index e15e121..73c66b2 100644 --- a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -10,7 +10,7 @@ #import "MBIMHTTPUtilities.h" #import "IMMessageItem+Encoded.h" -#import +#import "IMCore_ClassDump.h" @implementation MBIMMessagesListOperation @@ -35,7 +35,7 @@ __block NSMutableArray *messages = [NSMutableArray array]; dispatch_sync([[self class] sharedIMAccessQueue], ^{ - IMChat *chat = [sChatRegistry existingChatWithGUID:guid]; + IMChat *chat = [[IMChatRegistry sharedInstance] existingChatWithGUID:guid]; if (!chat) { MBIMLogInfo(@"Chat with guid: %@ not found", guid); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index a69e21e..a1d71cb 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -8,8 +8,7 @@ #import "MBIMSendMessageOperation.h" -#import -#import +#import "IMCore_ClassDump.h" @implementation MBIMSendMessageOperation @@ -25,7 +24,7 @@ __block BOOL result = YES; dispatch_sync([[self class] sharedIMAccessQueue], ^{ - IMChat *chat = [sChatRegistry existingChatWithGUID:chatGUID]; + IMChat *chat = [[IMChatRegistry sharedInstance] existingChatWithGUID:chatGUID]; // TODO: chat might not be an iMessage chat! IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; diff --git a/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m index b77832e..3ec8a64 100644 --- a/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m @@ -9,7 +9,7 @@ #import "MBIMUploadAttachmentOperation.h" #import "MBIMDataResponse.h" -#import +#import "IMCore_ClassDump.h" @implementation MBIMUploadAttachmentOperation diff --git a/kordophone/Categories/IMChat+Encoded.h b/kordophone/Categories/IMChat+Encoded.h index 6f3f09c..eed0389 100644 --- a/kordophone/Categories/IMChat+Encoded.h +++ b/kordophone/Categories/IMChat+Encoded.h @@ -6,7 +6,7 @@ // Copyright © 2018 James Magahern. All rights reserved. // -#import +#import "IMCore_ClassDump.h" NS_ASSUME_NONNULL_BEGIN diff --git a/kordophone/Categories/IMMessageItem+Encoded.h b/kordophone/Categories/IMMessageItem+Encoded.h index da78de1..61de3cf 100644 --- a/kordophone/Categories/IMMessageItem+Encoded.h +++ b/kordophone/Categories/IMMessageItem+Encoded.h @@ -6,8 +6,7 @@ // Copyright © 2018 James Magahern. All rights reserved. // -#import -#import +#import "IMCore_ClassDump.h" NS_ASSUME_NONNULL_BEGIN From f006af9863fe3650a6869dfd3379b9aabeb972c2 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 16 Dec 2019 17:30:47 -0800 Subject: [PATCH 25/75] Upgrade to recommended settings --- MessagesBridge.xcodeproj/project.pbxproj | 7 +++++-- .../xcshareddata/xcschemes/kordophoned.xcscheme | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index a2d5f5e..8be70f2 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -717,7 +717,7 @@ 1A0C443F219A38E100F2AC00 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1100; + LastUpgradeCheck = 1140; ORGANIZATIONNAME = "James Magahern"; TargetAttributes = { 1ACFCDE1219EB28A00E2C237 = { @@ -741,7 +741,6 @@ knownRegions = ( en, Base, - English, ); mainGroup = 1A0C443E219A38E100F2AC00; productRefGroup = 1A0C4448219A38E100F2AC00 /* Products */; @@ -891,6 +890,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -954,6 +954,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -1133,6 +1134,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = NO; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1148,6 +1150,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = NO; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme index 9f27664..5bc0f94 100644 --- a/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme +++ b/MessagesBridge.xcodeproj/xcshareddata/xcschemes/kordophoned.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 16 Dec 2019 17:35:19 -0800 Subject: [PATCH 26/75] Remove more internal references --- MessagesBridge.xcodeproj/project.pbxproj | 36 ++++++------------------ 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 8be70f2..f454c8a 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -7,12 +7,13 @@ objects = { /* Begin PBXBuildFile section */ + 1A257CC923A867EF00A4A2C8 /* IMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A257CC823A867EF00A4A2C8 /* IMCore.framework */; }; + 1A257CCB23A8681200A4A2C8 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A257CCA23A8681200A4A2C8 /* Security.framework */; }; 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */; }; 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */; }; 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */; }; 1AAB32B121F82EB7004A2A72 /* MBIMLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AAB32B021F82EB7004A2A72 /* MBIMLogging.m */; }; 1AAB32B421F837BB004A2A72 /* hookAgent.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = CD83E1B5219BF78E00F4CCEA /* hookAgent.sh */; }; - 1AAB32B621F83B68004A2A72 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1AAB32B521F83B68004A2A72 /* Security.framework */; }; 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE01219EB2AB00E2C237 /* HTTPLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE02219EB2AB00E2C237 /* HTTPMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -70,7 +71,6 @@ CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */; }; CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A3219FF22700E7DD22 /* IMMessageItem+Encoded.m */; }; - CD14F1A7219FF2F400E7DD22 /* IMSharedUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD14F1A6219FF2F400E7DD22 /* IMSharedUtilities.framework */; }; CD14F1AA219FF3B800E7DD22 /* MBIMUpdateQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */; }; CD14F1AD219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */; }; CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; @@ -86,9 +86,6 @@ 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 */; }; - CDF6233D219A8AF700690038 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C445F219A45B400F2AC00 /* Foundation.framework */; }; - CDF6233E219A8AFC00690038 /* IMCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A0C4467219A45D500F2AC00 /* IMCore.framework */; }; - CDF62343219A9BE200690038 /* ContactsFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDF62342219A9BE200690038 /* ContactsFoundation.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -131,16 +128,13 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 1A0C445F219A45B400F2AC00 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - 1A0C4461219A45B900F2AC00 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; - 1A0C4463219A45C700F2AC00 /* MessagesKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessagesKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/MessagesKit.framework; sourceTree = DEVELOPER_DIR; }; - 1A0C4464219A45C700F2AC00 /* MessagesHelperKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessagesHelperKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/MessagesHelperKit.framework; sourceTree = DEVELOPER_DIR; }; - 1A0C4467219A45D500F2AC00 /* IMCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IMCore.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/IMCore.framework; sourceTree = DEVELOPER_DIR; }; 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridge.h; sourceTree = ""; }; 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridge.m; sourceTree = ""; }; 1A257CB023A8570100A4A2C8 /* IMCore_ClassDump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMCore_ClassDump.h; sourceTree = ""; }; 1A257CB123A857DF00A4A2C8 /* IMSharedUtilities_ClassDump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMSharedUtilities_ClassDump.h; sourceTree = ""; }; 1A257CB223A85DF200A4A2C8 /* IMFoundation_ClassDump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IMFoundation_ClassDump.h; sourceTree = ""; }; + 1A257CC823A867EF00A4A2C8 /* IMCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IMCore.framework; path = System/Library/PrivateFrameworks/IMCore.framework; sourceTree = SDKROOT; }; + 1A257CCA23A8681200A4A2C8 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 1A33B43E219A5BD80034485A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 1AA43E8D219EBB2D00EDF1A7 /* MBIMJSONDataResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMJSONDataResponse.h; sourceTree = ""; }; 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMJSONDataResponse.m; sourceTree = ""; }; @@ -150,7 +144,6 @@ 1AAB32AF21F82EB7004A2A72 /* MBIMLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMLogging.h; sourceTree = ""; }; 1AAB32B021F82EB7004A2A72 /* MBIMLogging.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMLogging.m; sourceTree = ""; }; 1AAB32B221F835BD004A2A72 /* KPServer.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPServer.pch; sourceTree = ""; }; - 1AAB32B521F83B68004A2A72 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.Internal.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CocoaHTTPServer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 1ACFCDFE219EB2AB00E2C237 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = ""; }; @@ -220,7 +213,6 @@ CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMUpdatePollOperation.m; sourceTree = ""; }; CD14F1A2219FF22700E7DD22 /* IMMessageItem+Encoded.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IMMessageItem+Encoded.h"; sourceTree = ""; }; CD14F1A3219FF22700E7DD22 /* IMMessageItem+Encoded.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "IMMessageItem+Encoded.m"; sourceTree = ""; }; - CD14F1A6219FF2F400E7DD22 /* IMSharedUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IMSharedUtilities.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/IMSharedUtilities.framework; sourceTree = DEVELOPER_DIR; }; CD14F1A8219FF3B800E7DD22 /* MBIMUpdateQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMUpdateQueue.h; sourceTree = ""; }; CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMUpdateQueue.m; sourceTree = ""; }; CD14F1AB219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMConcurrentHTTPServer.h; sourceTree = ""; }; @@ -248,8 +240,6 @@ CDE455A621A531ED0041F5DD /* MBIMDataResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMDataResponse.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; }; - CDF62342219A9BE200690038 /* ContactsFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ContactsFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk/System/Library/PrivateFrameworks/ContactsFoundation.framework; sourceTree = DEVELOPER_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -278,12 +268,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1AAB32B621F83B68004A2A72 /* Security.framework in Frameworks */, - CD14F1A7219FF2F400E7DD22 /* IMSharedUtilities.framework in Frameworks */, + 1A257CCB23A8681200A4A2C8 /* Security.framework in Frameworks */, 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */, - CDF62343219A9BE200690038 /* ContactsFoundation.framework in Frameworks */, - CDF6233E219A8AFC00690038 /* IMCore.framework in Frameworks */, - CDF6233D219A8AF700690038 /* Foundation.framework in Frameworks */, + 1A257CC923A867EF00A4A2C8 /* IMCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -328,15 +315,8 @@ 1A0C445E219A45B400F2AC00 /* Frameworks */ = { isa = PBXGroup; children = ( - 1AAB32B521F83B68004A2A72 /* Security.framework */, - CD14F1A6219FF2F400E7DD22 /* IMSharedUtilities.framework */, - CDF62342219A9BE200690038 /* ContactsFoundation.framework */, - CDF62340219A9AAA00690038 /* EmailFoundation.framework */, - 1A0C4467219A45D500F2AC00 /* IMCore.framework */, - 1A0C4464219A45C700F2AC00 /* MessagesHelperKit.framework */, - 1A0C4463219A45C700F2AC00 /* MessagesKit.framework */, - 1A0C4461219A45B900F2AC00 /* AppKit.framework */, - 1A0C445F219A45B400F2AC00 /* Foundation.framework */, + 1A257CCA23A8681200A4A2C8 /* Security.framework */, + 1A257CC823A867EF00A4A2C8 /* IMCore.framework */, ); name = Frameworks; sourceTree = ""; From bb169c3e1c8360de458cbeaa0f999d363ea2d310 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sun, 6 Jun 2021 23:39:04 -0700 Subject: [PATCH 27/75] Adds launchd services --- Services/com.apple.imagent.plist | 53 ++++++++++++++++++++++++++ Services/net.buzzert.kordophoned.plist | 24 ++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 Services/com.apple.imagent.plist create mode 100644 Services/net.buzzert.kordophoned.plist diff --git a/Services/com.apple.imagent.plist b/Services/com.apple.imagent.plist new file mode 100644 index 0000000..c1fe116 --- /dev/null +++ b/Services/com.apple.imagent.plist @@ -0,0 +1,53 @@ + + + + + EnvironmentVariables + + NSRunningFromLaunchd + 1 + DYLD_INSERT_LIBRARIES + /usr/share/kordophone/libagentHook.dylib + + KeepAlive + + SuccessfulExit + + + Label + com.apple.imagent + LaunchEvents + + com.apple.distnoted.matching + + com.apple.authkit.user-info-changed + + Name + com.apple.authkit.user-info-changed + + com.apple.private.IMCore.LoggedIntoHSA2 + + Name + com.apple.private.IMCore.LoggedIntoHSA2 + + + com.apple.xpc.activity + + + MachServices + + com.apple.imagent.cache-delete + + com.apple.imagent.desktop.auth + + com.apple.incoming-call-filter-server + + + POSIXSpawnType + Interactive + ProgramArguments + + /System/Library/PrivateFrameworks/IMCore.framework/imagent.app/Contents/MacOS/imagent + + + diff --git a/Services/net.buzzert.kordophoned.plist b/Services/net.buzzert.kordophoned.plist new file mode 100644 index 0000000..153421a --- /dev/null +++ b/Services/net.buzzert.kordophoned.plist @@ -0,0 +1,24 @@ + + + + + EnvironmentVariables + + NSRunningFromLaunchd + 1 + + KeepAlive + + SuccessfulExit + + + Label + net.buzzert.kordophoned + POSIXSpawnType + Interactive + ProgramArguments + + /usr/share/kordophone/bootstrap_kordophone.sh + + + From 3c99b647d2996bf9d0a5cfd0ca64560ee3c7cf72 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sat, 12 Jun 2021 17:44:31 -0700 Subject: [PATCH 28/75] GPG is too much trouble for the access file --- kordophone/main.m | 62 +++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/kordophone/main.m b/kordophone/main.m index 50689b5..2f45503 100644 --- a/kordophone/main.m +++ b/kordophone/main.m @@ -16,35 +16,55 @@ void printUsage() fprintf(stderr, "\t-h \t Show this help message\n"); fprintf(stderr, "\t-s \t Use SSL (requires -c option)\n"); fprintf(stderr, "\t-c \t SSL certificate path encoded as pkcs12\n"); - fprintf(stderr, "\t-a \t Optional GPG encrypted access control file\n"); + fprintf(stderr, "\t-a \t Optional access control file\n"); } -BOOL acquireCredentials(const char *accessFile, NSString **out_username, NSString **out_password) +BOOL acquireCredentials(bool encrypted, const char *accessFile, NSString **out_username, NSString **out_password) { - NSPipe *stdoutPipe = [NSPipe pipe]; - NSPipe *stderrPipe = [NSPipe pipe]; - NSTask *task = [[NSTask alloc] init]; - task.launchPath = @"/usr/local/bin/gpg"; - task.arguments = @[ @"-q", @"-d", [NSString stringWithUTF8String:accessFile] ]; - task.standardOutput = stdoutPipe; - task.standardError = stderrPipe; - + BOOL success = NO; + NSString *asString = nil; NSError *launchError = nil; - BOOL success = [task launchAndReturnError:&launchError]; - [task waitUntilExit]; - if (success) { - NSFileHandle *stdoutFile = stdoutPipe.fileHandleForReading; - NSData *data = [stdoutFile readDataToEndOfFile]; // blocks - [stdoutFile closeFile]; + NSString *accessFilePath = [NSString stringWithUTF8String:accessFile]; + if (encrypted) { + NSPipe *stdoutPipe = [NSPipe pipe]; + NSPipe *stderrPipe = [NSPipe pipe]; + NSTask *task = [[NSTask alloc] init]; + task.launchPath = @"/usr/local/bin/gpg"; + task.arguments = @[ @"-q", @"-d", accessFilePath ]; + task.standardOutput = stdoutPipe; + task.standardError = stderrPipe; - if ([task terminationStatus] != 0) { - NSData *stderrData = [[stderrPipe fileHandleForReading] readDataToEndOfFile]; - MBIMLogFatal(@"GPG error when decrypting access file: %@", [[NSString alloc] initWithData:stderrData encoding:NSUTF8StringEncoding]); + success = [task launchAndReturnError:&launchError]; + [task waitUntilExit]; + + if (success) { + NSFileHandle *stdoutFile = stdoutPipe.fileHandleForReading; + NSData *data = [stdoutFile readDataToEndOfFile]; // blocks + [stdoutFile closeFile]; + + if ([task terminationStatus] != 0) { + NSData *stderrData = [[stderrPipe fileHandleForReading] readDataToEndOfFile]; + MBIMLogFatal(@"GPG error when decrypting access file: %@", [[NSString alloc] initWithData:stderrData encoding:NSUTF8StringEncoding]); + return NO; + } + + asString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } + } else { + NSError *fileReadError = nil; + asString = [NSString stringWithContentsOfFile:accessFilePath + encoding:NSASCIIStringEncoding + error:&fileReadError]; + if (fileReadError != nil) { + MBIMLogFatal(@"File open error when opening access file: %@", fileReadError.localizedDescription); return NO; } - NSString *asString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + success = (asString.length > 0); + } + + if (success) { NSScanner *scanner = [NSScanner scannerWithString:asString]; BOOL scannerSuccess = NO; @@ -133,7 +153,7 @@ int main(int argc, char *const argv[]) { NSString *username = nil; NSString *password = nil; - BOOL success = acquireCredentials(accessFilePath, &username, &password); + BOOL success = acquireCredentials(false, accessFilePath, &username, &password); if (!success) { MBIMLogInfo( @"Access file must be a GPG encrypted file (encrypted with your private key, to your pub key) " From f64ffcb8cc9bf0fd29f75cde9819a09b1d389451 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 14 Jun 2021 21:40:55 -0700 Subject: [PATCH 29/75] Add port number option --- kordophone/main.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kordophone/main.m b/kordophone/main.m index 2f45503..169407c 100644 --- a/kordophone/main.m +++ b/kordophone/main.m @@ -17,6 +17,7 @@ void printUsage() fprintf(stderr, "\t-s \t Use SSL (requires -c option)\n"); fprintf(stderr, "\t-c \t SSL certificate path encoded as pkcs12\n"); fprintf(stderr, "\t-a \t Optional access control file\n"); + fprintf(stderr, "\t-p \t Specify port number (default: 5738)\n"); } BOOL acquireCredentials(bool encrypted, const char *accessFile, NSString **out_username, NSString **out_password) @@ -104,11 +105,12 @@ int main(int argc, char *const argv[]) { BOOL usesSSL = NO; BOOL showHelp = NO; BOOL usesAccessControl = NO; + long portNumber = -1; const char *certPath = NULL; const char *accessFilePath = NULL; int c = -1; - while ( (c = getopt(argc, argv, "hsc:a:")) != -1 ) { + while ( (c = getopt(argc, argv, "hsc:a:p:")) != -1 ) { switch (c) { case 's': usesSSL = YES; @@ -120,6 +122,9 @@ int main(int argc, char *const argv[]) { usesAccessControl = YES; accessFilePath = optarg; break; + case 'p': + portNumber = strtol(optarg, NULL, 10); + break; case 'h': showHelp = YES; break; @@ -181,6 +186,10 @@ int main(int argc, char *const argv[]) { bridge.sslCertPath = [NSString stringWithCString:certPath encoding:NSASCIIStringEncoding]; } + if (portNumber > 0) { + bridge.port = portNumber; + } + [bridge connect]; BOOL running = YES; From 4d51ba7dd20c56a8aba124f553e4850aa431c0d3 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 6 Jul 2021 22:52:33 -0700 Subject: [PATCH 30/75] Auth: adds JWT bearer auth via /authenticate. Works in addition to digest auth --- MessagesBridge.xcodeproj/project.pbxproj | 20 ++- kordophone/Bridge/MBIMAuthToken.h | 26 +++ kordophone/Bridge/MBIMAuthToken.m | 149 ++++++++++++++++++ kordophone/Bridge/MBIMHTTPConnection.m | 34 +++- .../Operations/MBIMAuthenticateOperation.h | 17 ++ .../Operations/MBIMAuthenticateOperation.m | 72 +++++++++ .../Bridge/Operations/MBIMBridgeOperation.h | 1 + .../Bridge/Operations/MBIMBridgeOperation.m | 5 + 8 files changed, 314 insertions(+), 10 deletions(-) create mode 100644 kordophone/Bridge/MBIMAuthToken.h create mode 100644 kordophone/Bridge/MBIMAuthToken.m create mode 100644 kordophone/Bridge/Operations/MBIMAuthenticateOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMAuthenticateOperation.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index f454c8a..af6d7d7 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -73,6 +73,8 @@ CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A3219FF22700E7DD22 /* IMMessageItem+Encoded.m */; }; CD14F1AA219FF3B800E7DD22 /* MBIMUpdateQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */; }; CD14F1AD219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */; }; + CD2ECEC2269539100055E302 /* MBIMAuthenticateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2ECEC1269539100055E302 /* MBIMAuthenticateOperation.m */; }; + CD2ECEC526953F2A0055E302 /* MBIMAuthToken.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2ECEC426953F2A0055E302 /* MBIMAuthToken.m */; }; CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */; }; CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */; }; @@ -217,6 +219,10 @@ CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMUpdateQueue.m; sourceTree = ""; }; CD14F1AB219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMConcurrentHTTPServer.h; sourceTree = ""; }; CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMConcurrentHTTPServer.m; sourceTree = ""; }; + CD2ECEC0269539100055E302 /* MBIMAuthenticateOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMAuthenticateOperation.h; sourceTree = ""; }; + CD2ECEC1269539100055E302 /* MBIMAuthenticateOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMAuthenticateOperation.m; sourceTree = ""; }; + CD2ECEC326953F2A0055E302 /* MBIMAuthToken.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMAuthToken.h; sourceTree = ""; }; + CD2ECEC426953F2A0055E302 /* MBIMAuthToken.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMAuthToken.m; sourceTree = ""; }; CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridgeOperation.h; sourceTree = ""; }; CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridgeOperation.m; sourceTree = ""; }; CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMMessagesListOperation.h; sourceTree = ""; }; @@ -328,13 +334,14 @@ 1A0C4469219A4BC300F2AC00 /* MBIMBridge.h */, 1AAB32AC21F8212E004A2A72 /* MBIMBridge_Private.h */, 1A0C446A219A4BC300F2AC00 /* MBIMBridge.m */, + CD2ECEC326953F2A0055E302 /* MBIMAuthToken.h */, + CD2ECEC426953F2A0055E302 /* MBIMAuthToken.m */, CD14F1A8219FF3B800E7DD22 /* MBIMUpdateQueue.h */, CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */, CD14F1AB219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.h */, CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */, 1ACFCFE2219EB45300E2C237 /* MBIMHTTPConnection.h */, 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */, - 1AAB32A921F81AD0004A2A72 /* Security */, ); path = Bridge; sourceTree = ""; @@ -352,13 +359,6 @@ path = Utilities; sourceTree = ""; }; - 1AAB32A921F81AD0004A2A72 /* Security */ = { - isa = PBXGroup; - children = ( - ); - path = Security; - sourceTree = ""; - }; 1AAB32AE21F82E73004A2A72 /* Utilities */ = { isa = PBXGroup; children = ( @@ -536,6 +536,8 @@ CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */, 1AD8936C21EFD986009B599A /* MBIMUploadAttachmentOperation.h */, 1AD8936D21EFD986009B599A /* MBIMUploadAttachmentOperation.m */, + CD2ECEC0269539100055E302 /* MBIMAuthenticateOperation.h */, + CD2ECEC1269539100055E302 /* MBIMAuthenticateOperation.m */, ); path = Operations; sourceTree = ""; @@ -831,6 +833,7 @@ CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */, CDE455A421A5308D0041F5DD /* MBIMFetchAttachmentOperation.m in Sources */, + CD2ECEC526953F2A0055E302 /* MBIMAuthToken.m in Sources */, CD83E156219BE10A00F4CCEA /* hooking.m in Sources */, 1AAB32B121F82EB7004A2A72 /* MBIMLogging.m in Sources */, 1AD8936E21EFD986009B599A /* MBIMUploadAttachmentOperation.m in Sources */, @@ -847,6 +850,7 @@ CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, CDE4556421A3578A0041F5DD /* IMChat+Encoded.m in Sources */, 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */, + CD2ECEC2269539100055E302 /* MBIMAuthenticateOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/kordophone/Bridge/MBIMAuthToken.h b/kordophone/Bridge/MBIMAuthToken.h new file mode 100644 index 0000000..93da579 --- /dev/null +++ b/kordophone/Bridge/MBIMAuthToken.h @@ -0,0 +1,26 @@ +// +// MBIMAuthToken.h +// MBIMAuthToken +// +// Created by James Magahern on 7/6/21. +// Copyright © 2021 James Magahern. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMAuthToken : NSObject +@property (nonatomic, readonly) NSString *username; +@property (nonatomic, readonly) NSString *jwtToken; +@property (nonatomic, readonly) NSDate *expirationDate; + +- (instancetype)initWithUsername:(NSString *)username NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithTokenString:(NSString *)tokenString NS_DESIGNATED_INITIALIZER; + +- (BOOL)isValid; + +- (instancetype)init NS_UNAVAILABLE; +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/MBIMAuthToken.m b/kordophone/Bridge/MBIMAuthToken.m new file mode 100644 index 0000000..8ce5c7b --- /dev/null +++ b/kordophone/Bridge/MBIMAuthToken.m @@ -0,0 +1,149 @@ +// +// MBIMAuthToken.m +// MBIMAuthToken +// +// Created by James Magahern on 7/6/21. +// Copyright © 2021 James Magahern. All rights reserved. +// + +#import "MBIMAuthToken.h" +#import + +#define HOUR 3600 +#define DAY (24*HOUR) + +static const NSTimeInterval ExpirationTime = 15 * DAY; +static const char *SecretKey = "709E7CD8-4983-4D5F-B7BF-8B1C6341D2DB"; + +static NSString *const kUsernamePayloadKey = @"user"; +static NSString *const kIssuerPayloadKey = @"iss"; +static NSString *const kExpirationDatePayloadKey = @"exp"; + +static NSString *const kIssuerPayloadValue = @"kordophone"; + +@interface MBIMAuthToken () +@property (nonatomic, copy) NSString *username; +@property (nonatomic, copy) NSString *jwtToken; +@property (nonatomic, copy) NSDate *expirationDate; + +// JWT Payload data +@property (nonatomic, copy) NSString *headerString; +@property (nonatomic, copy) NSString *payloadString; +@property (nonatomic, copy) NSData *signatureData; +@end + +@implementation MBIMAuthToken + +- (instancetype)initWithUsername:(NSString *)username +{ + self = [super init]; + if (self) { + self.username = username; + self.expirationDate = [NSDate dateWithTimeIntervalSinceNow:ExpirationTime]; + } + + return self; +} + +- (instancetype)initWithTokenString:(NSString *)tokenString +{ + NSArray *components = [tokenString componentsSeparatedByString:@"."]; + if (components.count != 3) { + return nil; + } + + NSString *header = components[0]; + NSString *payload = components[1]; + NSString *signature = components[2]; + + NSData *payloadData = [[NSData alloc] initWithBase64EncodedString:payload options:0]; + NSDictionary *decodedPayload = [NSJSONSerialization JSONObjectWithData:payloadData options:0 error:nil]; + if (!decodedPayload) { + return nil; + } + + if (![decodedPayload[kIssuerPayloadKey] isEqualToString:@"kordophone"]) { + return nil; + } + + self = [super init]; + if (self) { + _headerString = header; + _payloadString = payload; + _signatureData = [[NSData alloc] initWithBase64EncodedString:signature options:0]; + + _username = decodedPayload[kUsernamePayloadKey]; + + NSTimeInterval expirationDate = [decodedPayload[kExpirationDatePayloadKey] floatValue]; + _expirationDate = [NSDate dateWithTimeIntervalSince1970:expirationDate]; + } + + return self; +} + +- (NSUInteger)hash +{ + return (_username.hash ^ _expirationDate.hash); +} + +- (NSString *)jwtToken +{ + if (!_jwtToken) { + NSDictionary *header = @{ + @"alg" : @"HS256", + @"typ" : @"jwt" + }; + + NSData *headerData = [NSJSONSerialization dataWithJSONObject:header options:0 error:nil]; + NSString *headerStr = [headerData base64EncodedStringWithOptions:0]; + + NSInteger expirationDate = [_expirationDate timeIntervalSince1970]; + NSDictionary *payload = @{ + kUsernamePayloadKey : _username, + kIssuerPayloadKey : kIssuerPayloadValue, + kExpirationDatePayloadKey : [NSString stringWithFormat:@"%ld", expirationDate] + }; + NSData *payloadData = [NSJSONSerialization dataWithJSONObject:payload options:0 error:nil]; + NSString *payloadStr = [payloadData base64EncodedStringWithOptions:0]; + + NSString *jwtDataStr = [NSString stringWithFormat:@"%@.%@", headerStr, payloadStr]; + NSData *jwtData = [jwtDataStr dataUsingEncoding:NSASCIIStringEncoding]; + + unsigned char signature[CC_SHA256_DIGEST_LENGTH]; + CCHmac(kCCHmacAlgSHA256, SecretKey, sizeof(SecretKey), jwtData.bytes, jwtData.length, signature); + + NSData *signatureData = [NSData dataWithBytes:signature length:CC_SHA256_DIGEST_LENGTH]; + NSString *signatureStr = [signatureData base64EncodedStringWithOptions:0]; + + _jwtToken = [NSString stringWithFormat:@"%@.%@", jwtDataStr, signatureStr]; + } + + return _jwtToken; +} + +- (BOOL)isValid +{ + // Verify expiration date + BOOL expirationDateValid = [_expirationDate timeIntervalSinceNow] > 0; + if (!expirationDateValid) { + MBIMLogInfo(@"Auth token expired."); + return NO; + } + + // Verify signature + NSString *verificationDataStr = [NSString stringWithFormat:@"%@.%@", _headerString, _payloadString]; + NSData *verificationData = [verificationDataStr dataUsingEncoding:NSASCIIStringEncoding]; + + unsigned char computedSignature[CC_SHA256_DIGEST_LENGTH]; + CCHmac(kCCHmacAlgSHA256, SecretKey, sizeof(SecretKey), verificationData.bytes, verificationData.length, computedSignature); + + NSData *computedSignatureData = [NSData dataWithBytes:computedSignature length:CC_SHA256_DIGEST_LENGTH]; + if (![computedSignatureData isEqualToData:_signatureData]) { + MBIMLogInfo(@"Auth token signature verification failed."); + return NO; + } + + return YES; +} + +@end diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index 5f3ef9a..2cbea07 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -11,8 +11,14 @@ #import "MBIMBridge.h" #import "MBIMBridge_Private.h" #import "MBIMBridgeOperation.h" +#import "MBIMAuthToken.h" #import +#import + +@interface HTTPConnection (/* INTERNAL */) +- (BOOL)isAuthenticated; +@end @implementation MBIMHTTPConnection { NSMutableData *_bodyData; @@ -31,7 +37,15 @@ - (BOOL)isPasswordProtected:(NSString *)path { - return [[MBIMBridge sharedInstance] usesAccessControl]; + if ([[MBIMBridge sharedInstance] usesAccessControl]) { + NSURL *url = [NSURL URLWithString:path]; + NSString *endpointName = [url lastPathComponent]; + + Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName]; + return [operationClass requiresAuthentication]; + } + + return NO; } - (NSString *)passwordForUser:(NSString *)username @@ -41,7 +55,23 @@ return bridge.authPassword; } - return @""; + // nil means "user not in system" + return nil; +} + +- (BOOL)isAuthenticated +{ + NSString *authInfo = [request headerField:@"Authorization"]; + if ([authInfo hasPrefix:@"Bearer"]) { + NSArray *bearerAuthTuple = [authInfo componentsSeparatedByString:@" "]; + if ([bearerAuthTuple count] == 2) { + NSString *jwtToken = [bearerAuthTuple objectAtIndex:1]; + MBIMAuthToken *authToken = [[MBIMAuthToken alloc] initWithTokenString:jwtToken]; + return [authToken isValid]; + } + } + + return [super isAuthenticated]; } - (BOOL)useDigestAccessAuthentication diff --git a/kordophone/Bridge/Operations/MBIMAuthenticateOperation.h b/kordophone/Bridge/Operations/MBIMAuthenticateOperation.h new file mode 100644 index 0000000..8709e91 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMAuthenticateOperation.h @@ -0,0 +1,17 @@ +// +// MBIMAuthenticateOperation.h +// MBIMAuthenticateOperation +// +// Created by James Magahern on 7/6/21. +// Copyright © 2021 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMAuthenticateOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMAuthenticateOperation.m b/kordophone/Bridge/Operations/MBIMAuthenticateOperation.m new file mode 100644 index 0000000..0988a4f --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMAuthenticateOperation.m @@ -0,0 +1,72 @@ +// +// MBIMAuthenticateOperation.m +// MBIMAuthenticateOperation +// +// Created by James Magahern on 7/6/21. +// Copyright © 2021 James Magahern. All rights reserved. +// + +#import "MBIMAuthenticateOperation.h" +#import "MBIMBridge.h" +#import "MBIMAuthToken.h" + +@implementation MBIMAuthenticateOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"authenticate"; +} + ++ (BOOL)requiresAuthentication +{ + return NO; +} + +- (void)main +{ + NSObject *response = nil; + + if (self.requestBodyData.length == 0) { + self.serverCompletionBlock([[HTTPErrorResponse alloc] initWithErrorCode:400]); + return; + } + + NSError *error = nil; + NSDictionary *args = [NSJSONSerialization JSONObjectWithData:self.requestBodyData options:0 error:&error]; + if (error || args.count == 0) { + response = [[HTTPErrorResponse alloc] initWithErrorCode:400]; + } else { + do { + NSString *username = [args objectForKey:@"username"]; + NSString *password = [args objectForKey:@"password"]; + + if (!username || !password) { + response = [[HTTPErrorResponse alloc] initWithErrorCode:400]; + break; + } + + if (![MBIMBridge.sharedInstance.authUsername isEqualToString:username]) { + response = [[HTTPErrorResponse alloc] initWithErrorCode:401]; + break; + } + + if (![MBIMBridge.sharedInstance.authPassword isEqualToString:password]) { + response = [[HTTPErrorResponse alloc] initWithErrorCode:401]; + break; + } + + MBIMAuthToken *token = [[MBIMAuthToken alloc] initWithUsername:username]; + + // All systems go + response = [MBIMJSONDataResponse responseWithJSONObject:@{ + @"jwt" : token.jwtToken + }]; + } while (NO); + } + + self.serverCompletionBlock(response); +} + +@end diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.h b/kordophone/Bridge/Operations/MBIMBridgeOperation.h index b07d1bc..936050c 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.h +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.h @@ -18,6 +18,7 @@ typedef void (^MBIMBridgeOperationCompletionBlock)(NSObject * _Nul @interface MBIMBridgeOperation : NSOperation @property (class, nonatomic, readonly) NSString *endpointName; +@property (class, nonatomic, readonly) BOOL requiresAuthentication; // default YES @property (nonatomic, strong) NSData *requestBodyData; @property (nonatomic, readonly) NSURL *requestURL; diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.m b/kordophone/Bridge/Operations/MBIMBridgeOperation.m index 5e1ae26..a64c632 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.m +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.m @@ -55,6 +55,11 @@ return [[self _operationClassMapping] objectForKey:endpointName]; } ++ (BOOL)requiresAuthentication +{ + return YES; +} + - (instancetype)initWithRequestURL:(NSURL *)requestURL completion:(MBIMBridgeOperationCompletionBlock)completionBlock { self = [super init]; From 641e4c53fab578ae925fd2be05e9a47a9ffad323 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 6 Jul 2021 23:41:39 -0700 Subject: [PATCH 31/75] Add Makefile for ez installing --- Makefile | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4f811a4 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +INSTALL_PATH := /usr/share/kordophone + +build/Release/kordophoned: + xcodebuild + +.PHONY: install +install: build/Release/kordophoned + install -d $(INSTALL_PATH) + install build/Release/kordophoned $(INSTALL_PATH) + cp -rf build/Release/CocoaHTTPServer.framework $(INSTALL_PATH) + +clean: + rm -Rf build From 7a3303da0686d1dd39d2029cfacc90e2ac687cdf Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 6 Jul 2021 23:41:51 -0700 Subject: [PATCH 32/75] Auth: Use Set-Cookie for auth token --- kordophone/Bridge/Operations/MBIMAuthenticateOperation.m | 7 ++++++- kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h | 1 + kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m | 8 +++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/kordophone/Bridge/Operations/MBIMAuthenticateOperation.m b/kordophone/Bridge/Operations/MBIMAuthenticateOperation.m index 0988a4f..b8ccd7d 100644 --- a/kordophone/Bridge/Operations/MBIMAuthenticateOperation.m +++ b/kordophone/Bridge/Operations/MBIMAuthenticateOperation.m @@ -60,9 +60,14 @@ MBIMAuthToken *token = [[MBIMAuthToken alloc] initWithUsername:username]; // All systems go - response = [MBIMJSONDataResponse responseWithJSONObject:@{ + MBIMJSONDataResponse *dataResponse = [MBIMJSONDataResponse responseWithJSONObject:@{ @"jwt" : token.jwtToken }]; + + // Send a cookie down so we can use httpOnly cookies + dataResponse.httpHeaders[@"Set-Cookie"] = [NSString stringWithFormat:@"auth_token=%@", token.jwtToken]; + + response = dataResponse; } while (NO); } diff --git a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h index 2dce971..b47d77d 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h +++ b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h @@ -12,6 +12,7 @@ NS_ASSUME_NONNULL_BEGIN @interface MBIMDataResponse : HTTPDataResponse +@property (nonatomic, readonly) NSMutableDictionary *httpHeaders; - (instancetype)initWithData:(NSData *)data contentType:(NSString *)contentType; @end diff --git a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m index 8758de0..cbf7d4f 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m +++ b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m @@ -10,6 +10,7 @@ @implementation MBIMDataResponse { NSString *_contentType; + NSMutableDictionary *_httpHeaders; } - (instancetype)initWithData:(NSData *)data contentType:(NSString *)contentType @@ -17,6 +18,9 @@ self = [super initWithData:data]; if (self) { _contentType = contentType; + _httpHeaders = [@{ + @"Content-Type" : _contentType ?: @"application/octet-stream" + } mutableCopy]; } return self; @@ -24,9 +28,7 @@ - (NSDictionary *)httpHeaders { - return @{ - @"Content-Type" : _contentType ?: @"application/octet-stream" - }; + return _httpHeaders; } @end From e161eedef3dc966028188b7896f4babc46c6ed23 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 25 May 2022 21:27:13 -0700 Subject: [PATCH 33/75] CORS --- kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m index cbf7d4f..7d87d89 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m +++ b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.m @@ -19,7 +19,9 @@ if (self) { _contentType = contentType; _httpHeaders = [@{ - @"Content-Type" : _contentType ?: @"application/octet-stream" + @"Content-Type" : _contentType ?: @"application/octet-stream", + @"Access-Control-Allow-Origin" : @"*", // CORS + @"Access-Control-Allow-Credentials" : @"true" } mutableCopy]; } From ebad248c1c0896af50c3493753a150dac4e66f2d Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 25 May 2022 22:34:19 -0700 Subject: [PATCH 34/75] Adds conversation delete option --- MessagesBridge.xcodeproj/project.pbxproj | 6 +++ .../MBIMDeleteConversationOperation.h | 17 +++++++ .../MBIMDeleteConversationOperation.m | 49 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 kordophone/Bridge/Operations/MBIMDeleteConversationOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMDeleteConversationOperation.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index af6d7d7..0655252 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -81,6 +81,7 @@ 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 */; }; + CDDCF78D283F398C0087ABDF /* MBIMDeleteConversationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.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 */; }; CDE455A421A5308D0041F5DD /* MBIMFetchAttachmentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE455A321A5308D0041F5DD /* MBIMFetchAttachmentOperation.m */; }; @@ -236,6 +237,8 @@ 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 = ""; }; + CDDCF78B283F398C0087ABDF /* MBIMDeleteConversationOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMDeleteConversationOperation.h; sourceTree = ""; }; + CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMDeleteConversationOperation.m; 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 = ""; }; @@ -526,6 +529,8 @@ CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */, CD60205D219B674B0024D9C5 /* MBIMConversationListOperation.h */, CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */, + CDDCF78B283F398C0087ABDF /* MBIMDeleteConversationOperation.h */, + CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.m */, CDE455A221A5308D0041F5DD /* MBIMFetchAttachmentOperation.h */, CDE455A321A5308D0041F5DD /* MBIMFetchAttachmentOperation.m */, CDE4559F21A365AD0041F5DD /* MBIMMarkOperation.h */, @@ -836,6 +841,7 @@ CD2ECEC526953F2A0055E302 /* MBIMAuthToken.m in Sources */, CD83E156219BE10A00F4CCEA /* hooking.m in Sources */, 1AAB32B121F82EB7004A2A72 /* MBIMLogging.m in Sources */, + CDDCF78D283F398C0087ABDF /* MBIMDeleteConversationOperation.m in Sources */, 1AD8936E21EFD986009B599A /* MBIMUploadAttachmentOperation.m in Sources */, CDF6233A219A8A5600690038 /* MBIMBridge.m in Sources */, CDF62335219A895D00690038 /* main.m in Sources */, diff --git a/kordophone/Bridge/Operations/MBIMDeleteConversationOperation.h b/kordophone/Bridge/Operations/MBIMDeleteConversationOperation.h new file mode 100644 index 0000000..df3996f --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMDeleteConversationOperation.h @@ -0,0 +1,17 @@ +// +// MBIMDeleteConversationOperation.h +// kordophoned +// +// Created by James Magahern on 5/25/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMDeleteConversationOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMDeleteConversationOperation.m b/kordophone/Bridge/Operations/MBIMDeleteConversationOperation.m new file mode 100644 index 0000000..2db40cc --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMDeleteConversationOperation.m @@ -0,0 +1,49 @@ +// +// MBIMDeleteConversationOperation.m +// kordophoned +// +// Created by James Magahern on 5/25/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import "MBIMDeleteConversationOperation.h" +#import "IMChat+Encoded.h" + +#import "IMCore_ClassDump.h" + +@implementation MBIMDeleteConversationOperation ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"delete"; +} + +- (void)main +{ + __block NSObject *response = nil; + do { + NSString *guid = [self valueForQueryItemWithName:@"guid"]; + + if (!guid) { + MBIMLogInfo(@"No conversation GUID provided."); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + dispatch_sync([[self class] sharedIMAccessQueue], ^{ + IMChat *chat = [[IMChatRegistry sharedInstance] existingChatWithGUID:guid]; + if (!chat) { + MBIMLogInfo(@"Chat with guid: %@ not found", guid); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + } else { + [chat remove]; + } + }); + + response = [[HTTPErrorResponse alloc] initWithErrorCode:200]; + } while (0); + + self.serverCompletionBlock(response); +} +@end From c7087a394e60112357b343d22abe53f3c7153c02 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 3 Aug 2022 16:52:39 -0700 Subject: [PATCH 35/75] MessagesList: Add support for beforeMessageGUID and beforeDate --- Dumped Classes/IMCore_ClassDump.h | 1 + MessagesBridge.xcodeproj/project.pbxproj | 10 ++++ .../Operations/MBIMMessagesListOperation.m | 55 ++++++++++++++++--- .../Operations/Utilities/MBIMErrorResponse.h | 18 ++++++ .../Operations/Utilities/MBIMErrorResponse.m | 38 +++++++++++++ .../Operations/Utilities/MBIMHTTPUtilities.h | 10 ++++ .../Operations/Utilities/MBIMHTTPUtilities.m | 28 ++++++++++ kordophone/kordophoned-Entitlements.plist | 16 ++++++ 8 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMErrorResponse.h create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMErrorResponse.m create mode 100644 kordophone/kordophoned-Entitlements.plist diff --git a/Dumped Classes/IMCore_ClassDump.h b/Dumped Classes/IMCore_ClassDump.h index 16bee13..dfb2356 100644 --- a/Dumped Classes/IMCore_ClassDump.h +++ b/Dumped Classes/IMCore_ClassDump.h @@ -3457,6 +3457,7 @@ __attribute__((visibility("default"))) @interface IMService : NSObject { } - (id)loadUnreadMessagesWithLimit:(unsigned long long)arg1 fallbackToMessagesUpToGUID:(id)arg2; - (id)loadFrequentRepliesLimit:(unsigned long long)arg1 loadImmediately:(BOOL)arg2; - (id)loadMessagesBeforeAndAfterGUID:(id)arg1 numberOfMessagesToLoadBeforeGUID:(unsigned long long)arg2 numberOfMessagesToLoadAfterGUID:(unsigned long long)arg3 loadImmediately:(BOOL)arg4; +- (id)loadMessagesBeforeAndAfterGUID:(id)arg1 numberOfMessagesToLoadBeforeGUID:(unsigned long long)arg2 numberOfMessagesToLoadAfterGUID:(unsigned long long)arg3 loadImmediately:(BOOL)arg4 threadIdentifier:(id)tid; - (id)loadMessagesUpToGUID:(id)arg1 date:(id)arg2 limit:(unsigned long long)arg3 loadImmediately:(BOOL)arg4; - (id)loadMessagesBeforeDate:(id)arg1 limit:(unsigned long long)arg2 loadImmediately:(BOOL)arg3; - (id)loadMessagesBeforeDate:(id)arg1 limit:(unsigned long long)arg2; diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 0655252..c7f26ac 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -81,6 +81,7 @@ 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 */; }; + CD936A32289B353F0093A1AC /* MBIMErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */; }; CDDCF78D283F398C0087ABDF /* MBIMDeleteConversationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.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 */; }; @@ -237,6 +238,9 @@ 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 = ""; }; + CD936A2F289B31740093A1AC /* kordophoned-Entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "kordophoned-Entitlements.plist"; sourceTree = ""; }; + CD936A30289B353F0093A1AC /* MBIMErrorResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMErrorResponse.h; sourceTree = ""; }; + CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMErrorResponse.m; sourceTree = ""; }; CDDCF78B283F398C0087ABDF /* MBIMDeleteConversationOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMDeleteConversationOperation.h; sourceTree = ""; }; CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMDeleteConversationOperation.m; sourceTree = ""; }; CDE4556221A3578A0041F5DD /* IMChat+Encoded.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IMChat+Encoded.h"; sourceTree = ""; }; @@ -356,6 +360,8 @@ 1AA43E8E219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m */, CDE455A521A531ED0041F5DD /* MBIMDataResponse.h */, CDE455A621A531ED0041F5DD /* MBIMDataResponse.m */, + CD936A30289B353F0093A1AC /* MBIMErrorResponse.h */, + CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */, 1AA43E93219EC38E00EDF1A7 /* MBIMHTTPUtilities.h */, 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */, ); @@ -574,6 +580,7 @@ 1A0C446D219A4BCD00F2AC00 /* Bridge */, CDF62334219A895D00690038 /* main.m */, 1AAB32B221F835BD004A2A72 /* KPServer.pch */, + CD936A2F289B31740093A1AC /* kordophoned-Entitlements.plist */, ); path = kordophone; sourceTree = ""; @@ -856,6 +863,7 @@ CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, CDE4556421A3578A0041F5DD /* IMChat+Encoded.m in Sources */, 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */, + CD936A32289B353F0093A1AC /* MBIMErrorResponse.m in Sources */, CD2ECEC2269539100055E302 /* MBIMAuthenticateOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1124,6 +1132,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = NO; + CODE_SIGN_ENTITLEMENTS = "kordophone/kordophoned-Entitlements.plist"; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; @@ -1140,6 +1149,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = NO; + CODE_SIGN_ENTITLEMENTS = "kordophone/kordophoned-Entitlements.plist"; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m index 73c66b2..4b24271 100644 --- a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -9,9 +9,12 @@ #import "MBIMMessagesListOperation.h" #import "MBIMHTTPUtilities.h" #import "IMMessageItem+Encoded.h" +#import "MBIMErrorResponse.h" #import "IMCore_ClassDump.h" +#define kDefaultMessagesLimit 75 + @implementation MBIMMessagesListOperation + (void)load { [super load]; } @@ -25,11 +28,26 @@ { __block NSObject *response = nil; do { + // Required parameters NSString *guid = [self valueForQueryItemWithName:@"guid"]; + // Optional + NSString *limitValue = [self valueForQueryItemWithName:@"limit"]; + + NSDate *beforeDate = nil; + NSString *beforeDateValue = [self valueForQueryItemWithName:@"beforeDate"]; + if (beforeDateValue) { + beforeDate = [beforeDateValue ISO8601Date]; + if (!beforeDate) { + response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"Unable to decode ISO8601 beforeDate value"]; + break; + } + } + + NSString *beforeMessageGUID = [self valueForQueryItemWithName:@"beforeMessageGUID"]; + if (!guid) { - MBIMLogInfo(@"No query item provided"); - response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"No GUID provided."]; break; } @@ -41,12 +59,33 @@ response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; } else { // Load messages - [chat loadMessagesBeforeDate:[NSDate date] limit:50 loadImmediately:YES]; - - [[chat chatItems] enumerateMessagesWithOptions:0 usingBlock:^(IMMessage *message, BOOL *stop) { - NSDictionary *messageDict = [message mbim_dictionaryRepresentation]; - [messages addObject:messageDict]; - }]; + // (Must be done on main queue for some reason) + dispatch_sync(dispatch_get_main_queue(), ^{ + NSUInteger limit = kDefaultMessagesLimit; + if (limitValue) { + limit = [limitValue integerValue]; + } + + if (beforeMessageGUID) { + if ([chat respondsToSelector:@selector(loadMessagesBeforeAndAfterGUID:numberOfMessagesToLoadBeforeGUID:numberOfMessagesToLoadAfterGUID:loadImmediately:threadIdentifier:)]) { + [chat loadMessagesBeforeAndAfterGUID:beforeMessageGUID numberOfMessagesToLoadBeforeGUID:limit numberOfMessagesToLoadAfterGUID:0 loadImmediately:YES threadIdentifier:nil]; + } else { + [chat loadMessagesBeforeAndAfterGUID:beforeMessageGUID numberOfMessagesToLoadBeforeGUID:limit numberOfMessagesToLoadAfterGUID:0 loadImmediately:YES]; + } + } else { + [chat loadMessagesBeforeDate:beforeDate limit:limit loadImmediately:YES]; + } + + [[chat chatItems] enumerateMessagesWithOptions:0 usingBlock:^(IMMessage *message, BOOL *stop) { + if ([[message guid] isEqual:beforeMessageGUID]) { + *stop = YES; + return; + } + + NSDictionary *messageDict = [message mbim_dictionaryRepresentation]; + [messages addObject:messageDict]; + }]; + }); } }); diff --git a/kordophone/Bridge/Operations/Utilities/MBIMErrorResponse.h b/kordophone/Bridge/Operations/Utilities/MBIMErrorResponse.h new file mode 100644 index 0000000..6893d37 --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMErrorResponse.h @@ -0,0 +1,18 @@ +// +// MBIMErrorResponse.h +// kordophoned +// +// Created by James Magahern on 8/3/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import "HTTPDataResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMErrorResponse : HTTPDataResponse +- (instancetype)initWithErrorCode:(int)httpErrorCode; +- (instancetype)initWithErrorCode:(int)httpErrorCode message:(NSString *)message; +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/Utilities/MBIMErrorResponse.m b/kordophone/Bridge/Operations/Utilities/MBIMErrorResponse.m new file mode 100644 index 0000000..92424a0 --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMErrorResponse.m @@ -0,0 +1,38 @@ +// +// MBIMErrorResponse.m +// kordophoned +// +// Created by James Magahern on 8/3/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import "MBIMErrorResponse.h" + +@implementation MBIMErrorResponse { + int _status; +} + +- (instancetype)initWithErrorCode:(int)httpErrorCode +{ + if (self = [super initWithData:nil]) { + _status = httpErrorCode; + } + + return self; +} + +- (instancetype)initWithErrorCode:(int)httpErrorCode message:(NSString *)message +{ + if (self = [super initWithData:[message dataUsingEncoding:NSUTF8StringEncoding]]) { + _status = httpErrorCode; + } + + return self; +} + +- (NSInteger)status +{ + return _status; +} + +@end diff --git a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h index 7ffc249..de6b8a1 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h +++ b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.h @@ -10,3 +10,13 @@ NSString* MBIMWebServerFormatRFC822(NSDate *date); NSString* MBIMWebServerFormatISO8601(NSDate *date); + +@interface NSDate (MBIMWebServerFormat) +- (NSString *)RFC822StringValue; +- (NSString *)ISO8601StringValue; +@end + +@interface NSString (MBIMWebServerFormat) +- (NSDate *)RFC822Date; +- (NSDate *)ISO8601Date; +@end diff --git a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m index 00e0663..58e4174 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m +++ b/kordophone/Bridge/Operations/Utilities/MBIMHTTPUtilities.m @@ -47,3 +47,31 @@ NSString* MBIMWebServerFormatISO8601(NSDate *date) return string; } + +@implementation NSDate (MBIMWebServerFormat) + +- (NSString *)RFC822StringValue +{ + return MBIMWebServerFormatRFC822(self); +} + +- (NSString *)ISO8601StringValue +{ + return MBIMWebServerFormatISO8601(self); +} + +@end + +@implementation NSString (MBIMWebServerFormat) + +- (NSDate *)RFC822Date +{ + return [_dateFormatterRFC822 dateFromString:self]; +} + +- (NSDate *)ISO8601Date +{ + return [_dateFormatterISO8601 dateFromString:self]; +} + +@end diff --git a/kordophone/kordophoned-Entitlements.plist b/kordophone/kordophoned-Entitlements.plist new file mode 100644 index 0000000..e519577 --- /dev/null +++ b/kordophone/kordophoned-Entitlements.plist @@ -0,0 +1,16 @@ + + + + + com.apple.imagent + + com.apple.private.imagent + + com.apple.private.imcore.imagent + + com.apple.imagent.av + + com.apple.imagent.chat + + + From bd01480ad65658bfceac9b127a6ddd5b92662348 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 3 Aug 2022 16:56:53 -0700 Subject: [PATCH 36/75] Don't build using restricted entitlements by default. --- MessagesBridge.xcodeproj/project.pbxproj | 6 ++---- README.md | 3 +++ ...ments.plist => kordophoned-RestrictedEntitlements.plist} | 0 3 files changed, 5 insertions(+), 4 deletions(-) rename kordophone/{kordophoned-Entitlements.plist => kordophoned-RestrictedEntitlements.plist} (100%) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index c7f26ac..b4d77d1 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -238,7 +238,7 @@ 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 = ""; }; - CD936A2F289B31740093A1AC /* kordophoned-Entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "kordophoned-Entitlements.plist"; sourceTree = ""; }; + CD936A2F289B31740093A1AC /* kordophoned-RestrictedEntitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "kordophoned-RestrictedEntitlements.plist"; sourceTree = ""; }; CD936A30289B353F0093A1AC /* MBIMErrorResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMErrorResponse.h; sourceTree = ""; }; CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMErrorResponse.m; sourceTree = ""; }; CDDCF78B283F398C0087ABDF /* MBIMDeleteConversationOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMDeleteConversationOperation.h; sourceTree = ""; }; @@ -580,7 +580,7 @@ 1A0C446D219A4BCD00F2AC00 /* Bridge */, CDF62334219A895D00690038 /* main.m */, 1AAB32B221F835BD004A2A72 /* KPServer.pch */, - CD936A2F289B31740093A1AC /* kordophoned-Entitlements.plist */, + CD936A2F289B31740093A1AC /* kordophoned-RestrictedEntitlements.plist */, ); path = kordophone; sourceTree = ""; @@ -1132,7 +1132,6 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = NO; - CODE_SIGN_ENTITLEMENTS = "kordophone/kordophoned-Entitlements.plist"; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; @@ -1149,7 +1148,6 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = NO; - CODE_SIGN_ENTITLEMENTS = "kordophone/kordophoned-Entitlements.plist"; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; diff --git a/README.md b/README.md index b08eeed..000dd49 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,9 @@ sudo defaults write /Library/Preferences/com.apple.security.coderequirements Ent Maybe a better thing to do is to DYLD_PRELOAD `imagent` and swizzle `IMDAuditTokenTaskHasEntitlement` to always return YES. +Included in the project is "kordophoned-RestrictedEntitlements.plist", which contains all necessary restricted entitlements. +On production macOS builds, the kernel will kill kordophoned immediately if it's signed using restricted entitlements, so agent hook is a +better option when running on prod machines. By default, the project is configured to ignore kordophoned-RestrictedEntitlements.plist when building. ## Building/linking If you get dyld errors running from the command line, use `install_name_tool` to update the @rpath (where @rpath points to where linked Frameworks like GCDWebServer is). diff --git a/kordophone/kordophoned-Entitlements.plist b/kordophone/kordophoned-RestrictedEntitlements.plist similarity index 100% rename from kordophone/kordophoned-Entitlements.plist rename to kordophone/kordophoned-RestrictedEntitlements.plist From 83ba072a9dc5f3cabe829af20312267c09a5ea48 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 3 Aug 2022 16:58:05 -0700 Subject: [PATCH 37/75] RestrictedEntitlements: Maybe okay for "Debug" to make it easier during development --- MessagesBridge.xcodeproj/project.pbxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index b4d77d1..1bea44c 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -1132,6 +1132,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = NO; + CODE_SIGN_ENTITLEMENTS = "kordophone/kordophoned-RestrictedEntitlements.plist"; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; From cad34253272bf823a53eb1b48a3ae6e7c1d69f57 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 3 Aug 2022 17:13:01 -0700 Subject: [PATCH 38/75] MessagesList: Also adds support for afterMessageGUID --- .../Operations/MBIMMessagesListOperation.m | 59 ++++++++++++++++--- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m index 4b24271..5126825 100644 --- a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -15,6 +15,11 @@ #define kDefaultMessagesLimit 75 +@interface IMChat (MBIMSafeMessagesLoading) +- (void)load:(NSUInteger)number messagesBeforeGUID:(NSString *)beforeMessageGUID; +- (void)load:(NSUInteger)number messagesAfterGUID:(NSString *)afterMessageGUID; +@end + @implementation MBIMMessagesListOperation + (void)load { [super load]; } @@ -45,6 +50,12 @@ } NSString *beforeMessageGUID = [self valueForQueryItemWithName:@"beforeMessageGUID"]; + NSString *afterMessageGUID = [self valueForQueryItemWithName:@"afterMessageGUID"]; + + if (beforeMessageGUID && afterMessageGUID) { + response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"Cannot provide both beforeMessageGUID and afterMessageGUID params."]; + break; + } if (!guid) { response = [[MBIMErrorResponse alloc] initWithErrorCode:500 message:@"No GUID provided."]; @@ -67,23 +78,25 @@ } if (beforeMessageGUID) { - if ([chat respondsToSelector:@selector(loadMessagesBeforeAndAfterGUID:numberOfMessagesToLoadBeforeGUID:numberOfMessagesToLoadAfterGUID:loadImmediately:threadIdentifier:)]) { - [chat loadMessagesBeforeAndAfterGUID:beforeMessageGUID numberOfMessagesToLoadBeforeGUID:limit numberOfMessagesToLoadAfterGUID:0 loadImmediately:YES threadIdentifier:nil]; - } else { - [chat loadMessagesBeforeAndAfterGUID:beforeMessageGUID numberOfMessagesToLoadBeforeGUID:limit numberOfMessagesToLoadAfterGUID:0 loadImmediately:YES]; - } + [chat load:limit messagesBeforeGUID:beforeMessageGUID]; + } else if (afterMessageGUID) { + [chat load:limit messagesAfterGUID:afterMessageGUID]; } else { [chat loadMessagesBeforeDate:beforeDate limit:limit loadImmediately:YES]; } [[chat chatItems] enumerateMessagesWithOptions:0 usingBlock:^(IMMessage *message, BOOL *stop) { + // Assume "beforeMessageGUID" is exclusive if ([[message guid] isEqual:beforeMessageGUID]) { *stop = YES; return; } - NSDictionary *messageDict = [message mbim_dictionaryRepresentation]; - [messages addObject:messageDict]; + // Assume "afterMessageGUID" is exclusive. + if (![[message guid] isEqual:afterMessageGUID]) { + NSDictionary *messageDict = [message mbim_dictionaryRepresentation]; + [messages addObject:messageDict]; + } }]; }); } @@ -96,3 +109,35 @@ } @end + +@implementation IMChat (MBIMSafeMessagesLoading) + +- (id)_safe_loadMessagesBeforeAndAfterGUID:(NSString *)messagesGUID numberOfMessagesToLoadBeforeGUID:(NSUInteger)limitBefore numberOfMessagesToLoadAfterGUID:(NSUInteger)limitAfter loadImmediately:(BOOL)loadImmediately +{ + if ([self respondsToSelector:@selector(loadMessagesBeforeAndAfterGUID: + numberOfMessagesToLoadBeforeGUID: + numberOfMessagesToLoadAfterGUID: + loadImmediately:threadIdentifier:)]) { + return [self loadMessagesBeforeAndAfterGUID:messagesGUID + numberOfMessagesToLoadBeforeGUID:limitBefore + numberOfMessagesToLoadAfterGUID:limitAfter + loadImmediately:YES threadIdentifier:nil]; + } else { + return [self loadMessagesBeforeAndAfterGUID:messagesGUID + numberOfMessagesToLoadBeforeGUID:limitBefore + numberOfMessagesToLoadAfterGUID:limitAfter + loadImmediately:YES]; + } +} + +- (void)load:(NSUInteger)number messagesBeforeGUID:(NSString *)beforeMessageGUID +{ + [self _safe_loadMessagesBeforeAndAfterGUID:beforeMessageGUID numberOfMessagesToLoadBeforeGUID:number numberOfMessagesToLoadAfterGUID:0 loadImmediately:YES]; +} + +- (void)load:(NSUInteger)number messagesAfterGUID:(NSString *)afterMessageGUID +{ + [self _safe_loadMessagesBeforeAndAfterGUID:afterMessageGUID numberOfMessagesToLoadBeforeGUID:0 numberOfMessagesToLoadAfterGUID:number loadImmediately:YES]; +} + +@end From 3ca9abcccde17d83bef7e4c6692f2fa8f4edf798 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 3 Aug 2022 17:27:15 -0700 Subject: [PATCH 39/75] Adds "version" operation --- MessagesBridge.xcodeproj/project.pbxproj | 33 ++++++++++++++--- .../Bridge/Operations/MBIMVersionOperation.h | 17 +++++++++ .../Bridge/Operations/MBIMVersionOperation.m | 35 +++++++++++++++++++ 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 kordophone/Bridge/Operations/MBIMVersionOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMVersionOperation.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 1bea44c..36f1b0b 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -82,6 +82,7 @@ CD83E156219BE10A00F4CCEA /* hooking.m in Sources */ = {isa = PBXBuildFile; fileRef = CD83E155219BE10A00F4CCEA /* hooking.m */; }; CD83E166219BE91600F4CCEA /* agentHook.m in Sources */ = {isa = PBXBuildFile; fileRef = CD83E165219BE91600F4CCEA /* agentHook.m */; }; CD936A32289B353F0093A1AC /* MBIMErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */; }; + CD936A35289B47D60093A1AC /* MBIMVersionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A34289B47D50093A1AC /* MBIMVersionOperation.m */; }; CDDCF78D283F398C0087ABDF /* MBIMDeleteConversationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.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 */; }; @@ -241,6 +242,8 @@ CD936A2F289B31740093A1AC /* kordophoned-RestrictedEntitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "kordophoned-RestrictedEntitlements.plist"; sourceTree = ""; }; CD936A30289B353F0093A1AC /* MBIMErrorResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMErrorResponse.h; sourceTree = ""; }; CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMErrorResponse.m; sourceTree = ""; }; + CD936A33289B47D50093A1AC /* MBIMVersionOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMVersionOperation.h; sourceTree = ""; }; + CD936A34289B47D50093A1AC /* MBIMVersionOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMVersionOperation.m; sourceTree = ""; }; CDDCF78B283F398C0087ABDF /* MBIMDeleteConversationOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMDeleteConversationOperation.h; sourceTree = ""; }; CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMDeleteConversationOperation.m; sourceTree = ""; }; CDE4556221A3578A0041F5DD /* IMChat+Encoded.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IMChat+Encoded.h"; sourceTree = ""; }; @@ -529,10 +532,10 @@ isa = PBXGroup; children = ( 1AA43E90219EBB3400EDF1A7 /* Utilities */, + CD2ECEC0269539100055E302 /* MBIMAuthenticateOperation.h */, + CD2ECEC1269539100055E302 /* MBIMAuthenticateOperation.m */, CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */, CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */, - CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */, - CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */, CD60205D219B674B0024D9C5 /* MBIMConversationListOperation.h */, CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */, CDDCF78B283F398C0087ABDF /* MBIMDeleteConversationOperation.h */, @@ -541,14 +544,16 @@ CDE455A321A5308D0041F5DD /* MBIMFetchAttachmentOperation.m */, CDE4559F21A365AD0041F5DD /* MBIMMarkOperation.h */, CDE455A021A365AD0041F5DD /* MBIMMarkOperation.m */, + CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */, + CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */, CD602060219B68950024D9C5 /* MBIMSendMessageOperation.h */, CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */, CD14F19F219FE7D600E7DD22 /* MBIMUpdatePollOperation.h */, CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */, 1AD8936C21EFD986009B599A /* MBIMUploadAttachmentOperation.h */, 1AD8936D21EFD986009B599A /* MBIMUploadAttachmentOperation.m */, - CD2ECEC0269539100055E302 /* MBIMAuthenticateOperation.h */, - CD2ECEC1269539100055E302 /* MBIMAuthenticateOperation.m */, + CD936A33289B47D50093A1AC /* MBIMVersionOperation.h */, + CD936A34289B47D50093A1AC /* MBIMVersionOperation.m */, ); path = Operations; sourceTree = ""; @@ -689,6 +694,7 @@ isa = PBXNativeTarget; buildConfigurationList = CDF62336219A895D00690038 /* Build configuration list for PBXNativeTarget "kordophoned" */; buildPhases = ( + CD936A36289B48930093A1AC /* Compile Version String */, CDF6232E219A895D00690038 /* Sources */, CDF6232F219A895D00690038 /* Frameworks */, CDF62330219A895D00690038 /* CopyFiles */, @@ -785,6 +791,24 @@ shellPath = /bin/sh; shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nRESULT=$(install_name_tool -delete_rpath $BUILT_PRODUCTS_DIR $BUILT_PRODUCTS_DIR/$EXECUTABLE_NAME 2> /dev/null)\n\ninstall_name_tool -add_rpath $BUILT_PRODUCTS_DIR $BUILT_PRODUCTS_DIR/$EXECUTABLE_NAME\n"; }; + CD936A36289B48930093A1AC /* Compile Version String */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Compile Version String"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\nOUTPUT_FILE=\"$DERIVED_FILE_DIR/MBIMVersion.c\"\nVERSION_STR=`git describe`\n\necho \"const char* MBIMVersion() { return \\\"$VERSION_STR\\\"; }\" > $OUTPUT_FILE\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -859,6 +883,7 @@ CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */, CDE455A121A365AD0041F5DD /* MBIMMarkOperation.m in Sources */, CDE455A721A531ED0041F5DD /* MBIMDataResponse.m in Sources */, + CD936A35289B47D60093A1AC /* MBIMVersionOperation.m in Sources */, CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */, CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, CDE4556421A3578A0041F5DD /* IMChat+Encoded.m in Sources */, diff --git a/kordophone/Bridge/Operations/MBIMVersionOperation.h b/kordophone/Bridge/Operations/MBIMVersionOperation.h new file mode 100644 index 0000000..ec57bf8 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMVersionOperation.h @@ -0,0 +1,17 @@ +// +// MBIMVersionOperation.h +// kordophoned +// +// Created by James Magahern on 8/3/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMVersionOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMVersionOperation.m b/kordophone/Bridge/Operations/MBIMVersionOperation.m new file mode 100644 index 0000000..d7d0a73 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMVersionOperation.m @@ -0,0 +1,35 @@ +// +// MBIMVersionOperation.m +// kordophoned +// +// Created by James Magahern on 8/3/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import "MBIMVersionOperation.h" +#import "MBIMErrorResponse.h" + +#ifdef __clang_analyzer__ +const char* MBIMVersion() { + return "UNKNOWN"; +} +#else +#import "MBIMVersion.c" +#endif + +@implementation MBIMVersionOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"version"; +} + +- (void)main +{ + NSString *versionString = [NSString stringWithUTF8String:MBIMVersion()]; + self.serverCompletionBlock([[MBIMDataResponse alloc] initWithData:[versionString dataUsingEncoding:NSUTF8StringEncoding]]); +} + +@end From e5b78d62f01a5217a7769ec3f8b2c3c915eebac5 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 3 Aug 2022 17:28:23 -0700 Subject: [PATCH 40/75] Adds "status" operation --- MessagesBridge.xcodeproj/project.pbxproj | 6 +++++ .../Bridge/Operations/MBIMStatusOperation.h | 17 +++++++++++++ .../Bridge/Operations/MBIMStatusOperation.m | 25 +++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 kordophone/Bridge/Operations/MBIMStatusOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMStatusOperation.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 36f1b0b..12eff6f 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -83,6 +83,7 @@ CD83E166219BE91600F4CCEA /* agentHook.m in Sources */ = {isa = PBXBuildFile; fileRef = CD83E165219BE91600F4CCEA /* agentHook.m */; }; CD936A32289B353F0093A1AC /* MBIMErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */; }; CD936A35289B47D60093A1AC /* MBIMVersionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A34289B47D50093A1AC /* MBIMVersionOperation.m */; }; + CD936A39289B49FC0093A1AC /* MBIMStatusOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A38289B49FC0093A1AC /* MBIMStatusOperation.m */; }; CDDCF78D283F398C0087ABDF /* MBIMDeleteConversationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.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 */; }; @@ -244,6 +245,8 @@ CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMErrorResponse.m; sourceTree = ""; }; CD936A33289B47D50093A1AC /* MBIMVersionOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMVersionOperation.h; sourceTree = ""; }; CD936A34289B47D50093A1AC /* MBIMVersionOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMVersionOperation.m; sourceTree = ""; }; + CD936A37289B49FC0093A1AC /* MBIMStatusOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMStatusOperation.h; sourceTree = ""; }; + CD936A38289B49FC0093A1AC /* MBIMStatusOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMStatusOperation.m; sourceTree = ""; }; CDDCF78B283F398C0087ABDF /* MBIMDeleteConversationOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMDeleteConversationOperation.h; sourceTree = ""; }; CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMDeleteConversationOperation.m; sourceTree = ""; }; CDE4556221A3578A0041F5DD /* IMChat+Encoded.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IMChat+Encoded.h"; sourceTree = ""; }; @@ -548,6 +551,8 @@ CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */, CD602060219B68950024D9C5 /* MBIMSendMessageOperation.h */, CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */, + CD936A37289B49FC0093A1AC /* MBIMStatusOperation.h */, + CD936A38289B49FC0093A1AC /* MBIMStatusOperation.m */, CD14F19F219FE7D600E7DD22 /* MBIMUpdatePollOperation.h */, CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */, 1AD8936C21EFD986009B599A /* MBIMUploadAttachmentOperation.h */, @@ -881,6 +886,7 @@ CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */, CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */, + CD936A39289B49FC0093A1AC /* MBIMStatusOperation.m in Sources */, CDE455A121A365AD0041F5DD /* MBIMMarkOperation.m in Sources */, CDE455A721A531ED0041F5DD /* MBIMDataResponse.m in Sources */, CD936A35289B47D60093A1AC /* MBIMVersionOperation.m in Sources */, diff --git a/kordophone/Bridge/Operations/MBIMStatusOperation.h b/kordophone/Bridge/Operations/MBIMStatusOperation.h new file mode 100644 index 0000000..758fe7f --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMStatusOperation.h @@ -0,0 +1,17 @@ +// +// MBIMStatusOperation.h +// kordophoned +// +// Created by James Magahern on 8/3/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMStatusOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMStatusOperation.m b/kordophone/Bridge/Operations/MBIMStatusOperation.m new file mode 100644 index 0000000..152ded8 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMStatusOperation.m @@ -0,0 +1,25 @@ +// +// MBIMStatusOperation.m +// kordophoned +// +// Created by James Magahern on 8/3/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import "MBIMStatusOperation.h" + +@implementation MBIMStatusOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"status"; +} + +- (void)main +{ + self.serverCompletionBlock([[MBIMDataResponse alloc] initWithData:[@"OK" dataUsingEncoding:NSUTF8StringEncoding]]); +} + +@end From ba8f76f4bd3c83649142a86abf5a0ae33f53cb02 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 3 Aug 2022 19:55:04 -0700 Subject: [PATCH 41/75] versionoperation: don't require auth --- kordophone/Bridge/Operations/MBIMVersionOperation.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kordophone/Bridge/Operations/MBIMVersionOperation.m b/kordophone/Bridge/Operations/MBIMVersionOperation.m index d7d0a73..e22462c 100644 --- a/kordophone/Bridge/Operations/MBIMVersionOperation.m +++ b/kordophone/Bridge/Operations/MBIMVersionOperation.m @@ -21,6 +21,11 @@ const char* MBIMVersion() { + (void)load { [super load]; } ++ (BOOL)requiresAuthentication +{ + return NO; +} + + (NSString *)endpointName { return @"version"; From 3082c4ab195603bfb2822aa62e4d55da808841db Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 20 Dec 2022 16:29:26 -0800 Subject: [PATCH 42/75] Adds support for image previews Just need to append ?preview=1 to attachment fetch operation. --- Dumped Classes/IMSharedUtilities_ClassDump.h | 20 +++++-- MessagesBridge.xcodeproj/project.pbxproj | 18 ++++++ .../Operations/MBIMFetchAttachmentOperation.m | 58 +++++++++++++++++-- .../Operations/Utilities/MBIMImageUtils.h | 12 ++++ .../Operations/Utilities/MBIMImageUtils.m | 37 ++++++++++++ kordophone/Categories/IMMessageItem+Encoded.m | 11 ++++ 6 files changed, 144 insertions(+), 12 deletions(-) create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMImageUtils.h create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMImageUtils.m diff --git a/Dumped Classes/IMSharedUtilities_ClassDump.h b/Dumped Classes/IMSharedUtilities_ClassDump.h index a49ab41..9945a4f 100644 --- a/Dumped Classes/IMSharedUtilities_ClassDump.h +++ b/Dumped Classes/IMSharedUtilities_ClassDump.h @@ -18,12 +18,18 @@ struct IMFileLocation_t { int _field5; }; -struct IMPreviewConstraints { - double _field1; - struct CGSize _field2; - double _field3; - char _field4; -}; +typedef struct IMPreviewConstraints { + CGFloat maxPxWidth; + CGSize minThumbnailPxSize; + CGFloat scale; + BOOL isSticker; + BOOL generateMetadata; +} IMPreviewConstraints; + +extern IMPreviewConstraints IMPreviewConstraintsFromDictionary(NSDictionary *dictionary); +extern NSDictionary *IMPreviewConstraintsDictionaryFromConstraint(IMPreviewConstraints constraint); +extern BOOL IMPreviewConstraintsEqualToConstraints(IMPreviewConstraints constraints1, IMPreviewConstraints constraints2); +extern IMPreviewConstraints IMPreviewConstraintsZero(void); struct _TidyDoc { int _field1; @@ -155,6 +161,8 @@ struct __va_list_tag { - (void)setObject:(id)arg1 forKey:(id)arg2; @end +extern NSURL* IMAttachmentPreviewFileURL(NSURL *attachmentURL, NSString *extension, BOOL generateIntermediaryDirectories); + @protocol IMPreviewGeneratorProtocol + (BOOL)shouldShadePreview; + (BOOL)shouldScaleUpPreview; diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 12eff6f..1284fcd 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -73,6 +73,10 @@ CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A3219FF22700E7DD22 /* IMMessageItem+Encoded.m */; }; CD14F1AA219FF3B800E7DD22 /* MBIMUpdateQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */; }; CD14F1AD219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */; }; + CD2782BC29527FE500C0C030 /* IMSharedUtilities.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD2782BB29527FE500C0C030 /* IMSharedUtilities.framework */; }; + CD2782BF2952832B00C0C030 /* MBIMImageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2782BE2952832B00C0C030 /* MBIMImageUtils.m */; }; + CD2782FE2952875F00C0C030 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD2782FD2952875F00C0C030 /* CoreGraphics.framework */; }; + CD2783002952876700C0C030 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD2782FF2952876700C0C030 /* ImageIO.framework */; }; CD2ECEC2269539100055E302 /* MBIMAuthenticateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2ECEC1269539100055E302 /* MBIMAuthenticateOperation.m */; }; CD2ECEC526953F2A0055E302 /* MBIMAuthToken.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2ECEC426953F2A0055E302 /* MBIMAuthToken.m */; }; CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; @@ -223,6 +227,11 @@ CD14F1A9219FF3B800E7DD22 /* MBIMUpdateQueue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMUpdateQueue.m; sourceTree = ""; }; CD14F1AB219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMConcurrentHTTPServer.h; sourceTree = ""; }; CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMConcurrentHTTPServer.m; sourceTree = ""; }; + CD2782BB29527FE500C0C030 /* IMSharedUtilities.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IMSharedUtilities.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.Internal.sdk/System/Library/PrivateFrameworks/IMSharedUtilities.framework; sourceTree = DEVELOPER_DIR; }; + CD2782BD2952832B00C0C030 /* MBIMImageUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMImageUtils.h; sourceTree = ""; }; + CD2782BE2952832B00C0C030 /* MBIMImageUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMImageUtils.m; sourceTree = ""; }; + CD2782FD2952875F00C0C030 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + CD2782FF2952876700C0C030 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; CD2ECEC0269539100055E302 /* MBIMAuthenticateOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMAuthenticateOperation.h; sourceTree = ""; }; CD2ECEC1269539100055E302 /* MBIMAuthenticateOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMAuthenticateOperation.m; sourceTree = ""; }; CD2ECEC326953F2A0055E302 /* MBIMAuthToken.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMAuthToken.h; sourceTree = ""; }; @@ -287,8 +296,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CD2782BC29527FE500C0C030 /* IMSharedUtilities.framework in Frameworks */, 1A257CCB23A8681200A4A2C8 /* Security.framework in Frameworks */, + CD2783002952876700C0C030 /* ImageIO.framework in Frameworks */, 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */, + CD2782FE2952875F00C0C030 /* CoreGraphics.framework in Frameworks */, 1A257CC923A867EF00A4A2C8 /* IMCore.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -334,6 +346,9 @@ 1A0C445E219A45B400F2AC00 /* Frameworks */ = { isa = PBXGroup; children = ( + CD2782FF2952876700C0C030 /* ImageIO.framework */, + CD2782FD2952875F00C0C030 /* CoreGraphics.framework */, + CD2782BB29527FE500C0C030 /* IMSharedUtilities.framework */, 1A257CCA23A8681200A4A2C8 /* Security.framework */, 1A257CC823A867EF00A4A2C8 /* IMCore.framework */, ); @@ -370,6 +385,8 @@ CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */, 1AA43E93219EC38E00EDF1A7 /* MBIMHTTPUtilities.h */, 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */, + CD2782BD2952832B00C0C030 /* MBIMImageUtils.h */, + CD2782BE2952832B00C0C030 /* MBIMImageUtils.m */, ); path = Utilities; sourceTree = ""; @@ -893,6 +910,7 @@ CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */, CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */, CDE4556421A3578A0041F5DD /* IMChat+Encoded.m in Sources */, + CD2782BF2952832B00C0C030 /* MBIMImageUtils.m in Sources */, 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */, CD936A32289B353F0093A1AC /* MBIMErrorResponse.m in Sources */, CD2ECEC2269539100055E302 /* MBIMAuthenticateOperation.m in Sources */, diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m index 5bbce09..a21433f 100644 --- a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m @@ -8,8 +8,11 @@ #import "MBIMFetchAttachmentOperation.h" #import "MBIMDataResponse.h" +#import "MBIMImageUtils.h" #import "IMCore_ClassDump.h" +#import "IMSharedUtilities_ClassDump.h" +#import @implementation MBIMFetchAttachmentOperation @@ -24,8 +27,8 @@ { NSObject *response = nil; do { + BOOL preview = [[self valueForQueryItemWithName:@"preview"] boolValue]; NSString *guid = [self valueForQueryItemWithName:@"guid"]; - if (!guid) { MBIMLogInfo(@"No query item provided"); response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; @@ -45,22 +48,65 @@ break; } - NSString *localPath = [transfer localPath]; - NSData *responseData = [NSData dataWithContentsOfFile:localPath]; + NSData *responseData = nil; + NSURL *localURL = [transfer localURL]; + NSString *extension = [[localURL pathExtension] lowercaseString]; + if (preview) { + NSURL *previewURL = IMAttachmentPreviewFileURL(localURL, extension, YES); + if (![[NSFileManager defaultManager] fileExistsAtPath:[previewURL path]]) { + MBIMLogInfo(@"Generating preview image for guid: %@ at %@", guid, [previewURL path]); + + // Fetch preview constraints from transfer + NSDictionary *previewConstraintsDict = [[transfer attributionInfo] objectForKey:@"pgenszc"]; + if (!previewConstraintsDict) { + MBIMLogInfo(@"No preview constraints for attachment guid: %@", guid); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + IMPreviewConstraints constraints = IMPreviewConstraintsFromDictionary(previewConstraintsDict); + + // Generate preview using preview generator manager + NSError *error = nil; + IMPreviewGeneratorManager *generator = [IMPreviewGeneratorManager sharedInstance]; + CGImageRef previewImage = [generator newPreviewFromSourceURL:localURL withPreviewConstraints:constraints error:&error]; + if (error) { + MBIMLogInfo(@"Unable to generate preview for attachment guid: %@", guid); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + responseData = MBIMCGImageJPEGRepresentation(previewImage); + + // Persist JPEG preview to disk + [responseData writeToURL:previewURL atomically:YES]; + } else { + // File exists + MBIMLogInfo(@"Using cached preview image for guid: %@ at %@", guid, [previewURL path]); + responseData = [NSData dataWithContentsOfURL:previewURL]; + } + } else { + responseData = [NSData dataWithContentsOfURL:localURL]; + } + if (!responseData) { - MBIMLogInfo(@"Wasn't able to load data from local path: %@", localPath); + MBIMLogInfo(@"Wasn't able to load data for guid: %@", guid); response = [[HTTPErrorResponse alloc] initWithErrorCode:404]; break; } NSString *mimeType = [transfer mimeType]; + if ([mimeType isEqualToString:@"image/heic"]) { + // TODO: We should convert this to JPEG here. I don't want clients to have to deal with HEIC. + MBIMLogInfo(@"WARNING: Returning HEIC data for attachment %@", guid); + } + // It's unusual, but if this is nil, try to guess the MIME type based on the filename if (!mimeType) { - NSString *extension = [[localPath pathExtension] lowercaseString]; - // XXX: REALLY hacky mimeType = [NSString stringWithFormat:@"image/%@", extension]; } + response = [[MBIMDataResponse alloc] initWithData:responseData contentType:mimeType]; } while (0); diff --git a/kordophone/Bridge/Operations/Utilities/MBIMImageUtils.h b/kordophone/Bridge/Operations/Utilities/MBIMImageUtils.h new file mode 100644 index 0000000..11a0aa4 --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMImageUtils.h @@ -0,0 +1,12 @@ +// +// MBIMImageUtils.h +// kordophoned +// +// Created by James Magahern on 12/20/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import +#import + +extern NSData* MBIMCGImageJPEGRepresentation(CGImageRef imageRef); diff --git a/kordophone/Bridge/Operations/Utilities/MBIMImageUtils.m b/kordophone/Bridge/Operations/Utilities/MBIMImageUtils.m new file mode 100644 index 0000000..1a793fa --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMImageUtils.m @@ -0,0 +1,37 @@ +// +// MBIMImageUtils.m +// kordophoned +// +// Created by James Magahern on 12/20/22. +// Copyright © 2022 James Magahern. All rights reserved. +// + +#import "MBIMImageUtils.h" +#import + +NSData* MBIMCGImageJPEGRepresentation(CGImageRef imageRef) +{ + if (imageRef == NULL) return nil; + + NSNumber *const DPI = @72.0; + NSNumber *const compressionQuality = @0.9; + NSDictionary *properties = @{ + (__bridge NSString *)kCGImagePropertyDPIWidth : DPI, + (__bridge NSString *)kCGImagePropertyDPIHeight : DPI, + (__bridge NSString *)kCGImageDestinationLossyCompressionQuality : compressionQuality, + }; + + bool success = false; + NSMutableData *data = [NSMutableData data]; + if (data) { + CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((CFMutableDataRef)data, CFSTR("public.jpeg"), 1/*count*/, NULL/*options*/); + if (imageDestination != NULL) { + CGImageDestinationAddImage(imageDestination, imageRef, (__bridge CFDictionaryRef)properties); + success = CGImageDestinationFinalize(imageDestination); + CFRelease(imageDestination); + } + } + + return success ? data : nil; +} + diff --git a/kordophone/Categories/IMMessageItem+Encoded.m b/kordophone/Categories/IMMessageItem+Encoded.m index 25b4084..aeaead6 100644 --- a/kordophone/Categories/IMMessageItem+Encoded.m +++ b/kordophone/Categories/IMMessageItem+Encoded.m @@ -21,16 +21,27 @@ if ([self fileTransferGUIDs]) { // Support only images right now + NSMutableDictionary *attachmentMetadatas = [NSMutableDictionary dictionary]; NSMutableArray *filteredFileTransferGUIDs = [NSMutableArray array]; for (NSString *guid in self.fileTransferGUIDs) { + NSMutableDictionary *metadata = [NSMutableDictionary dictionary]; IMFileTransfer *transfer = [[IMFileTransferCenter sharedInstance] transferForGUID:guid]; if ([[transfer mimeType] containsString:@"image"]) { [filteredFileTransferGUIDs addObject:guid]; + + if ([transfer attributionInfo] != nil) { + metadata[@"attributionInfo"] = [transfer attributionInfo]; + } + } + + if (metadata.count) { + attachmentMetadatas[guid] = metadata; } } if ([filteredFileTransferGUIDs count]) { messageDict[@"fileTransferGUIDs"] = filteredFileTransferGUIDs; + messageDict[@"attachmentMetadata"] = attachmentMetadatas; } } From bc9e4f52b4cf6b3d7bffc683e92efb01a25e8821 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 20 Dec 2022 16:43:45 -0800 Subject: [PATCH 43/75] PreviewURL is nil on old macOS for some reason --- kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m index a21433f..1822d70 100644 --- a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m @@ -76,10 +76,13 @@ break; } + // Convert to JPEG. responseData = MBIMCGImageJPEGRepresentation(previewImage); // Persist JPEG preview to disk - [responseData writeToURL:previewURL atomically:YES]; + if (previewURL) { + [responseData writeToURL:previewURL atomically:YES]; + } } else { // File exists MBIMLogInfo(@"Using cached preview image for guid: %@ at %@", guid, [previewURL path]); From 56ae7982c67319707a51e7d0d715c88ac489aaf7 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 12 Jan 2023 17:00:18 -0800 Subject: [PATCH 44/75] Last message preview uses imagent provided description --- Dumped Classes/IMCore_ClassDump.h | 14 ++++++++++++-- kordophone/Categories/IMChat+Encoded.m | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Dumped Classes/IMCore_ClassDump.h b/Dumped Classes/IMCore_ClassDump.h index dfb2356..f74f609 100644 --- a/Dumped Classes/IMCore_ClassDump.h +++ b/Dumped Classes/IMCore_ClassDump.h @@ -3680,6 +3680,16 @@ __attribute__((visibility("default"))) @interface IMService : NSObject { } @end +typedef NS_ENUM(NSInteger, IMMessageDescriptionType) { + IMMessageDescriptionAccessibility, + IMMessageDescriptionAcknowledgement, + IMMessageDescriptionConversationList, + IMMessageDescriptionNotification, + IMMessageDescriptionSiri, + IMMessageDescriptionSPI, +}; + + @interface IMMessage : NSObject { IMHandle *_sender; @@ -3804,8 +3814,8 @@ __attribute__((visibility("default"))) @interface IMService : NSObject { } - (id)_initWithSender:(id)arg1 time:(id)arg2 timeRead:(id)arg3 timeDelivered:(id)arg4 timePlayed:(id)arg5 plainText:(id)arg6 text:(id)arg7 messageSubject:(id)arg8 fileTransferGUIDs:(id)arg9 flags:(unsigned long long)arg10 error:(id)arg11 guid:(id)arg12 messageID:(long long)arg13 subject:(id)arg14 balloonBundleID:(id)arg15 payloadData:(id)arg16 expressiveSendStyleID:(id)arg17 timeExpressiveSendPlayed:(id)arg18 associatedMessageGUID:(id)arg19 associatedMessageType:(long long)arg20 associatedMessageRange:(struct _NSRange)arg21 messageSummaryInfo:(id)arg22; - (id)_copyWithFlags:(unsigned long long)arg1; - (id)copyWithZone:(struct _NSZone *)arg1; -- (id)descriptionForPurpose:(long long)arg1 inChat:(id)arg2; -- (id)descriptionForPurpose:(long long)arg1; +- (id)descriptionForPurpose:(IMMessageDescriptionType)arg1 inChat:(id)arg2; +- (id)descriptionForPurpose:(IMMessageDescriptionType)arg1; - (void)_ovverrideGUIDForTest:(id)arg1; @property(readonly, nonatomic) BOOL isAssociatedMessage; - (id)initWithSender:(id)arg1 time:(id)arg2 text:(id)arg3 messageSubject:(id)arg4 fileTransferGUIDs:(id)arg5 flags:(unsigned long long)arg6 error:(id)arg7 guid:(id)arg8 subject:(id)arg9 associatedMessageGUID:(id)arg10 associatedMessageType:(long long)arg11 associatedMessageRange:(struct _NSRange)arg12 associatedMessageInfo:(id)arg13; diff --git a/kordophone/Categories/IMChat+Encoded.m b/kordophone/Categories/IMChat+Encoded.m index 5bcac46..4d607a6 100644 --- a/kordophone/Categories/IMChat+Encoded.m +++ b/kordophone/Categories/IMChat+Encoded.m @@ -21,7 +21,7 @@ IMMessage *lastMessage = [self lastMessage]; if (lastMessage) { - chatDict[@"lastMessagePreview"] = [[lastMessage text] string]; + chatDict[@"lastMessagePreview"] = [lastMessage descriptionForPurpose:IMMessageDescriptionConversationList]; } NSMutableArray *participantStrings = [NSMutableArray array]; From 2f5d50188b63dfe9a7133ba5cde56d833f53ac0c Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 17 Jan 2023 16:16:23 -0800 Subject: [PATCH 45/75] Adds websocket updates via the /updates endpoint --- MessagesBridge.xcodeproj/project.pbxproj | 6 + kordophone/Bridge/MBIMHTTPConnection.m | 13 ++ kordophone/Bridge/MBIMUpdateQueue.h | 9 +- kordophone/Bridge/MBIMUpdateQueue.m | 141 +++++++++++++----- .../Bridge/Operations/MBIMBridgeOperation.h | 2 + .../Bridge/Operations/MBIMBridgeOperation.m | 14 +- .../Operations/MBIMUpdatePollOperation.m | 4 +- .../Operations/Utilities/MBIMURLUtilities.h | 17 +++ .../Operations/Utilities/MBIMURLUtilities.m | 28 ++++ 9 files changed, 181 insertions(+), 53 deletions(-) create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMURLUtilities.h create mode 100644 kordophone/Bridge/Operations/Utilities/MBIMURLUtilities.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 1284fcd..427a335 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -79,6 +79,7 @@ CD2783002952876700C0C030 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD2782FF2952876700C0C030 /* ImageIO.framework */; }; CD2ECEC2269539100055E302 /* MBIMAuthenticateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2ECEC1269539100055E302 /* MBIMAuthenticateOperation.m */; }; CD2ECEC526953F2A0055E302 /* MBIMAuthToken.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2ECEC426953F2A0055E302 /* MBIMAuthToken.m */; }; + CD3F62B1297769F2004305D9 /* MBIMURLUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = CD3F62B0297769F2004305D9 /* MBIMURLUtilities.m */; }; CD602056219B5DFD0024D9C5 /* MBIMBridgeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */; }; CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */; }; CD60205F219B674B0024D9C5 /* MBIMConversationListOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD60205E219B674B0024D9C5 /* MBIMConversationListOperation.m */; }; @@ -236,6 +237,8 @@ CD2ECEC1269539100055E302 /* MBIMAuthenticateOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMAuthenticateOperation.m; sourceTree = ""; }; CD2ECEC326953F2A0055E302 /* MBIMAuthToken.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMAuthToken.h; sourceTree = ""; }; CD2ECEC426953F2A0055E302 /* MBIMAuthToken.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMAuthToken.m; sourceTree = ""; }; + CD3F62AF297769F2004305D9 /* MBIMURLUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMURLUtilities.h; sourceTree = ""; }; + CD3F62B0297769F2004305D9 /* MBIMURLUtilities.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMURLUtilities.m; sourceTree = ""; }; CD602054219B5DFD0024D9C5 /* MBIMBridgeOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMBridgeOperation.h; sourceTree = ""; }; CD602055219B5DFD0024D9C5 /* MBIMBridgeOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMBridgeOperation.m; sourceTree = ""; }; CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMMessagesListOperation.h; sourceTree = ""; }; @@ -387,6 +390,8 @@ 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */, CD2782BD2952832B00C0C030 /* MBIMImageUtils.h */, CD2782BE2952832B00C0C030 /* MBIMImageUtils.m */, + CD3F62AF297769F2004305D9 /* MBIMURLUtilities.h */, + CD3F62B0297769F2004305D9 /* MBIMURLUtilities.m */, ); path = Utilities; sourceTree = ""; @@ -900,6 +905,7 @@ CDF62335219A895D00690038 /* main.m in Sources */, CD60205C219B623F0024D9C5 /* MBIMMessagesListOperation.m in Sources */, CD14F1AA219FF3B800E7DD22 /* MBIMUpdateQueue.m in Sources */, + CD3F62B1297769F2004305D9 /* MBIMURLUtilities.m in Sources */, CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */, CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */, diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index 2cbea07..a36a444 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -12,6 +12,7 @@ #import "MBIMBridge_Private.h" #import "MBIMBridgeOperation.h" #import "MBIMAuthToken.h" +#import "MBIMUpdateQueue.h" #import #import @@ -107,6 +108,7 @@ if (operationClass != nil) { _currentOperation = [[operationClass alloc] initWithRequestURL:url completion:completion]; _currentOperation.requestBodyData = _bodyData; + _currentOperation.request = self->request; [[[MBIMBridge sharedInstance] operationQueue] addOperation:_currentOperation]; long status = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60.0 * NSEC_PER_SEC))); @@ -124,6 +126,17 @@ return response; } +- (WebSocket *)webSocketForURI:(NSString *)path +{ + NSURL *url = [NSURL URLWithString:path]; + NSString *endpointName = [url lastPathComponent]; + if ([endpointName isEqualToString:@"updates"]) { + return [[MBIMUpdateQueue sharedInstance] vendUpdateWebSocketConsumerForRequest:request socket:asyncSocket]; + } + + return [super webSocketForURI:path]; +} + - (BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path { if ([method isEqualToString:@"POST"]) { diff --git a/kordophone/Bridge/MBIMUpdateQueue.h b/kordophone/Bridge/MBIMUpdateQueue.h index 9cb7a43..4cc1600 100644 --- a/kordophone/Bridge/MBIMUpdateQueue.h +++ b/kordophone/Bridge/MBIMUpdateQueue.h @@ -10,6 +10,9 @@ #import "IMFoundation_ClassDump.h" NS_ASSUME_NONNULL_BEGIN +@class GCDAsyncSocket; +@class HTTPMessage; +@class WebSocket; @interface MBIMUpdateItem : NSObject @property (nonatomic, strong) IMChat *changedChat; @@ -24,11 +27,13 @@ typedef void (^MBIMUpdateConsumer)(NSArray *items); + (instancetype)sharedInstance; -- (void)addConsumer:(MBIMUpdateConsumer)consumer withLastSyncedMessageSeq:(NSInteger)messageSeq; -- (void)removeConsumer:(MBIMUpdateConsumer)consumer; +- (void)addPollingConsumer:(MBIMUpdateConsumer)consumer withLastSyncedMessageSeq:(NSInteger)messageSeq; +- (void)removePollingConsumer:(MBIMUpdateConsumer)consumer; - (void)enqueueUpdateItem:(MBIMUpdateItem *)item; +- (WebSocket *)vendUpdateWebSocketConsumerForRequest:(HTTPMessage *)request socket:(GCDAsyncSocket *)socket; + @end NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/MBIMUpdateQueue.m b/kordophone/Bridge/MBIMUpdateQueue.m index c8636aa..e25b40e 100644 --- a/kordophone/Bridge/MBIMUpdateQueue.m +++ b/kordophone/Bridge/MBIMUpdateQueue.m @@ -9,20 +9,29 @@ #import "MBIMUpdateQueue.h" #import "IMMessageItem+Encoded.h" #import "IMChat+Encoded.h" +#import "MBIMHTTPConnection.h" +#import "MBIMURLUtilities.h" + +#import +#import +#import static const NSUInteger kUpdateItemsCullingLength = 100; -@interface MBIMUpdateItem (/*INTERNAL*/) +@interface MBIMUpdateItem (/*INTERNAL*/) @property (nonatomic, assign) NSUInteger messageSequenceNumber; @end @implementation MBIMUpdateQueue { NSUInteger _messageSequenceNumber; dispatch_queue_t _accessQueue; - NSMutableArray *_consumers; + NSMutableArray *_longPollConsumers; // Maps message sequence number to update item NSMutableDictionary *_updateItemHistory; + + // WebSocket consumers + NSMutableDictionary *_websocketConsumers; } + (instancetype)sharedInstance @@ -41,20 +50,93 @@ static const NSUInteger kUpdateItemsCullingLength = 100; self = [super init]; if (self) { _accessQueue = dispatch_queue_create("net.buzzert.MBIMUpdateQueue", DISPATCH_QUEUE_SERIAL); - _consumers = [[NSMutableArray alloc] init]; _messageSequenceNumber = 0; _updateItemHistory = [[NSMutableDictionary alloc] init]; + _websocketConsumers = [[NSMutableDictionary alloc] init]; + _longPollConsumers = [[NSMutableArray alloc] init]; } return self; } -- (void)addConsumer:(MBIMUpdateConsumer)consumer withLastSyncedMessageSeq:(NSInteger)messageSeq +- (void)addPollingConsumer:(MBIMUpdateConsumer)consumer withLastSyncedMessageSeq:(NSInteger)messageSeq { - __weak NSMutableArray *consumers = _consumers; + if (![self _syncConsumer:consumer fromLastMessageSeq:messageSeq]) { + __weak NSMutableArray *consumers = _longPollConsumers; + dispatch_async(_accessQueue, ^{ + [consumers addObject:consumer]; + }); + } +} + +- (void)removePollingConsumer:(MBIMUpdateConsumer)consumer +{ + __weak NSMutableArray *consumers = _longPollConsumers; + dispatch_async(_accessQueue, ^{ + [consumers removeObject:consumer]; + }); +} + +- (void)enqueueUpdateItem:(MBIMUpdateItem *)item +{ + __weak __auto_type pollingConsumers = _longPollConsumers; + __weak __auto_type websocketConsumers = _websocketConsumers; __weak NSMutableDictionary *updateItemHistory = _updateItemHistory; dispatch_async(_accessQueue, ^{ - if ((messageSeq >= 0) && messageSeq < self->_messageSequenceNumber) { + self->_messageSequenceNumber++; + item.messageSequenceNumber = self->_messageSequenceNumber; + + // Notify polling consumers + for (MBIMUpdateConsumer consumer in pollingConsumers) { + consumer(@[ item ]); + } + [pollingConsumers removeAllObjects]; + + // Notify websocket consumers + for (MBIMUpdateConsumer consumer in [websocketConsumers allValues]) { + consumer(@[ item ]); + } + + [updateItemHistory setObject:item forKey:@(item.messageSequenceNumber)]; + + [self _cullUpdateItems]; + }); +} + +- (WebSocket *)vendUpdateWebSocketConsumerForRequest:(HTTPMessage *)request socket:(GCDAsyncSocket *)gcdSocket +{ + WebSocket *socket = [[WebSocket alloc] initWithRequest:request socket:gcdSocket]; + socket.delegate = self; + + MBIMUpdateConsumer consumer = ^(NSArray *updates) { + NSMutableArray *encodedUpdates = [NSMutableArray array]; + for (MBIMUpdateItem *item in updates) { + NSDictionary *updateDict = [item dictionaryRepresentation]; + [encodedUpdates addObject:updateDict]; + } + + NSData *data = [NSJSONSerialization dataWithJSONObject:encodedUpdates options:0 error:NULL]; + [socket sendData:data]; + }; + + NSString *messageSeqString = [[request url] valueForQueryItemWithName:@"seq"]; + [self _syncConsumer:consumer fromLastMessageSeq:(messageSeqString ? [messageSeqString integerValue] : -1)]; + + __weak __auto_type websocketConsumers = _websocketConsumers; + dispatch_async(_accessQueue, ^{ + NSString *websocketKey = [socket description]; + [websocketConsumers setObject:consumer forKey:websocketKey]; + }); + + return socket; +} + +- (BOOL)_syncConsumer:(MBIMUpdateConsumer)consumer fromLastMessageSeq:(NSInteger)messageSeq +{ + const BOOL needsSync = (messageSeq >= 0) && messageSeq < self->_messageSequenceNumber; + if (needsSync) { + __weak NSMutableDictionary *updateItemHistory = _updateItemHistory; + dispatch_async(_accessQueue, ^{ NSMutableArray *batchedUpdates = [NSMutableArray array]; for (NSUInteger seq = messageSeq + 1; seq <= self->_messageSequenceNumber; seq++) { MBIMUpdateItem *item = [updateItemHistory objectForKey:@(seq)]; @@ -64,37 +146,10 @@ static const NSUInteger kUpdateItemsCullingLength = 100; } consumer(batchedUpdates); - } else { - [consumers addObject:consumer]; - } - }); -} - -- (void)removeConsumer:(MBIMUpdateConsumer)consumer -{ - __weak NSMutableArray *consumers = _consumers; - dispatch_async(_accessQueue, ^{ - [consumers removeObject:consumer]; - }); -} - -- (void)enqueueUpdateItem:(MBIMUpdateItem *)item -{ - __weak NSMutableArray *consumers = _consumers; - __weak NSMutableDictionary *updateItemHistory = _updateItemHistory; - dispatch_async(_accessQueue, ^{ - self->_messageSequenceNumber++; - item.messageSequenceNumber = self->_messageSequenceNumber; - - for (MBIMUpdateConsumer consumer in consumers) { - consumer(@[ item ]); - } - - [consumers removeAllObjects]; - [updateItemHistory setObject:item forKey:@(item.messageSequenceNumber)]; - - [self _cullUpdateItems]; - }); + }); + } + + return needsSync; } - (void)_cullUpdateItems @@ -113,6 +168,18 @@ static const NSUInteger kUpdateItemsCullingLength = 100; }); } +#pragma mark - + +- (void)webSocketDidClose:(WebSocket *)ws +{ + // xxx: not great, but works. + NSString *websocketKey = [ws description]; + __weak __auto_type websocketConsumers = _websocketConsumers; + dispatch_async(_accessQueue, ^{ + [websocketConsumers removeObjectForKey:websocketKey]; + }); +} + @end @implementation MBIMUpdateItem diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.h b/kordophone/Bridge/Operations/MBIMBridgeOperation.h index 936050c..2bea21b 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.h +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.h @@ -7,6 +7,7 @@ // #import +#import #import #import @@ -20,6 +21,7 @@ typedef void (^MBIMBridgeOperationCompletionBlock)(NSObject * _Nul @property (class, nonatomic, readonly) NSString *endpointName; @property (class, nonatomic, readonly) BOOL requiresAuthentication; // default YES +@property (nonatomic, strong) HTTPMessage *request; @property (nonatomic, strong) NSData *requestBodyData; @property (nonatomic, readonly) NSURL *requestURL; @property (nonatomic, readonly) MBIMBridgeOperationCompletionBlock serverCompletionBlock; diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.m b/kordophone/Bridge/Operations/MBIMBridgeOperation.m index a64c632..b716527 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.m +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.m @@ -7,6 +7,7 @@ // #import "MBIMBridgeOperation.h" +#import "MBIMURLUtilities.h" @interface MBIMBridgeOperation (/*INTERNAL*/) @property (nonatomic, strong) NSURL *requestURL; @@ -79,18 +80,7 @@ - (NSString *)valueForQueryItemWithName:(NSString *)queryItemName { - NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:self.requestURL - resolvingAgainstBaseURL:NO]; - - NSString *value = nil; - for (NSURLQueryItem *queryItem in [urlComponents queryItems]) { - if ([[queryItem name] isEqualToString:queryItemName]) { - value = [queryItem value]; - break; - } - } - - return value; + return [[self requestURL] valueForQueryItemWithName:queryItemName]; } @end diff --git a/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m index 939743a..face497 100644 --- a/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m +++ b/kordophone/Bridge/Operations/MBIMUpdatePollOperation.m @@ -40,13 +40,13 @@ weakSelf.serverCompletionBlock(response); }; - [[MBIMUpdateQueue sharedInstance] addConsumer:_updateConsumer withLastSyncedMessageSeq:messageSeq]; + [[MBIMUpdateQueue sharedInstance] addPollingConsumer:_updateConsumer withLastSyncedMessageSeq:messageSeq]; } - (void)cancel { [super cancel]; - [[MBIMUpdateQueue sharedInstance] removeConsumer:_updateConsumer]; + [[MBIMUpdateQueue sharedInstance] removePollingConsumer:_updateConsumer]; } - (NSObject *)cancelAndReturnTimeoutResponse diff --git a/kordophone/Bridge/Operations/Utilities/MBIMURLUtilities.h b/kordophone/Bridge/Operations/Utilities/MBIMURLUtilities.h new file mode 100644 index 0000000..77e5a5a --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMURLUtilities.h @@ -0,0 +1,17 @@ +// +// MBIMURLUtilities.h +// kordophoned +// +// Created by James Magahern on 1/17/23. +// Copyright © 2023 James Magahern. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSURL (MBIMURLUtilities) +- (nullable NSString *)valueForQueryItemWithName:(NSString *)queryItemName; +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/Utilities/MBIMURLUtilities.m b/kordophone/Bridge/Operations/Utilities/MBIMURLUtilities.m new file mode 100644 index 0000000..15ccdee --- /dev/null +++ b/kordophone/Bridge/Operations/Utilities/MBIMURLUtilities.m @@ -0,0 +1,28 @@ +// +// MBIMURLUtilities.m +// kordophoned +// +// Created by James Magahern on 1/17/23. +// Copyright © 2023 James Magahern. All rights reserved. +// + +#import "MBIMURLUtilities.h" + +@implementation NSURL (MBIMURLUtilities) + +- (nullable NSString *)valueForQueryItemWithName:(NSString *)queryItemName +{ + NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:self resolvingAgainstBaseURL:NO]; + + NSString *value = nil; + for (NSURLQueryItem *queryItem in [urlComponents queryItems]) { + if ([[queryItem name] isEqualToString:queryItemName]) { + value = [queryItem value]; + break; + } + } + + return value; +} + +@end From d071e68a56874fdba7c3d3975d3c82f5a1cb598f Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 6 Jul 2023 15:27:12 -0700 Subject: [PATCH 46/75] Security: adds authentication to updates websocket operation --- kordophone/Bridge/MBIMHTTPConnection.m | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index a36a444..e81e45f 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -13,6 +13,7 @@ #import "MBIMBridgeOperation.h" #import "MBIMAuthToken.h" #import "MBIMUpdateQueue.h" +#import "MBIMURLUtilities.h" #import #import @@ -130,7 +131,14 @@ { NSURL *url = [NSURL URLWithString:path]; NSString *endpointName = [url lastPathComponent]; + NSString *authTokenString = [url valueForQueryItemWithName:@"token"]; + MBIMAuthToken *authToken = [[MBIMAuthToken alloc] initWithTokenString:authTokenString]; + if ([endpointName isEqualToString:@"updates"]) { + if (![authToken isValid]) { + return nil; + } + return [[MBIMUpdateQueue sharedInstance] vendUpdateWebSocketConsumerForRequest:request socket:asyncSocket]; } From 37ff0b375f5dbe3467823dee76fd8b122038b95a Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 6 Jul 2023 15:27:31 -0700 Subject: [PATCH 47/75] send: must be performed on main queue --- kordophone/Bridge/Operations/MBIMSendMessageOperation.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index a1d71cb..3e641a9 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -46,7 +46,9 @@ MBIMLogInfo(@"Chat does not exist: %@", chatGUID); result = NO; } else { - [chat sendMessage:reply]; + dispatch_async(dispatch_get_main_queue(), ^{ + [chat sendMessage:reply]; + }); } }); From b92c683a0ec67a4e1bb90c09ca48e9d0e5529efa Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 10 Aug 2023 00:27:52 -0700 Subject: [PATCH 48/75] /conversations: encode last message also --- kordophone/Categories/IMChat+Encoded.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kordophone/Categories/IMChat+Encoded.m b/kordophone/Categories/IMChat+Encoded.m index 4d607a6..d74d966 100644 --- a/kordophone/Categories/IMChat+Encoded.m +++ b/kordophone/Categories/IMChat+Encoded.m @@ -7,6 +7,7 @@ // #import "IMChat+Encoded.h" +#import "IMMessageItem+Encoded.h" #import "MBIMHTTPUtilities.h" @implementation IMChat (Encoded) @@ -22,6 +23,7 @@ IMMessage *lastMessage = [self lastMessage]; if (lastMessage) { chatDict[@"lastMessagePreview"] = [lastMessage descriptionForPurpose:IMMessageDescriptionConversationList]; + chatDict[@"lastMessage"] = [lastMessage mbim_dictionaryRepresentation]; } NSMutableArray *participantStrings = [NSMutableArray array]; From 87d65e294bebcec249ea1b955d9f2df33be30291 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 5 Dec 2023 15:41:07 -0800 Subject: [PATCH 49/75] sendMessage: return guid after sending. This guid is stable --- .../Bridge/Operations/MBIMSendMessageOperation.m | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index 3e641a9..2f28444 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -19,9 +19,9 @@ return @"sendMessage"; } -- (BOOL)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID attachmentGUIDs:(NSArray *)guids +- (IMMessage *)_sendMessage:(NSString *)messageBody toChatWithGUID:(NSString *)chatGUID attachmentGUIDs:(NSArray *)guids { - __block BOOL result = YES; + __block IMMessage *result = nil; dispatch_sync([[self class] sharedIMAccessQueue], ^{ IMChat *chat = [[IMChatRegistry sharedInstance] existingChatWithGUID:chatGUID]; @@ -44,8 +44,9 @@ if (!chat) { MBIMLogInfo(@"Chat does not exist: %@", chatGUID); - result = NO; } else { + result = reply; + dispatch_async(dispatch_get_main_queue(), ^{ [chat sendMessage:reply]; }); @@ -78,9 +79,11 @@ transferGUIDs = @[]; } - BOOL result = [self _sendMessage:messageBody toChatWithGUID:guid attachmentGUIDs:transferGUIDs]; + IMMessage *result = [self _sendMessage:messageBody toChatWithGUID:guid attachmentGUIDs:transferGUIDs]; if (result) { - response = [[HTTPErrorResponse alloc] initWithErrorCode:200]; + response = [MBIMJSONDataResponse responseWithJSONObject:@{ + @"guid" : [result guid] + }]; } self.serverCompletionBlock(response); From 147dc15d1d105398bfd764ec4816a475d13887fb Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 2 Jan 2024 18:14:31 -0800 Subject: [PATCH 50/75] SendOperation: Return whole message, not just GUID. --- kordophone/Bridge/Operations/MBIMSendMessageOperation.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index 2f28444..7221913 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -9,6 +9,7 @@ #import "MBIMSendMessageOperation.h" #import "IMCore_ClassDump.h" +#import "IMMessageItem+Encoded.h" @implementation MBIMSendMessageOperation @@ -81,9 +82,7 @@ IMMessage *result = [self _sendMessage:messageBody toChatWithGUID:guid attachmentGUIDs:transferGUIDs]; if (result) { - response = [MBIMJSONDataResponse responseWithJSONObject:@{ - @"guid" : [result guid] - }]; + response = [MBIMJSONDataResponse responseWithJSONObject:[result mbim_dictionaryRepresentation]]; } self.serverCompletionBlock(response); From c65803845b2ef3c6a8285ad8a7f2d44f58142265 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sun, 7 Jan 2024 18:11:59 -0800 Subject: [PATCH 51/75] FetchAttachment: need to check for some edge cases wrt preview generation --- .../Operations/MBIMFetchAttachmentOperation.m | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m index 1822d70..be39d9f 100644 --- a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m @@ -52,20 +52,34 @@ NSURL *localURL = [transfer localURL]; NSString *extension = [[localURL pathExtension] lowercaseString]; if (preview) { + IMPreviewConstraints constraints = IMPreviewConstraintsZero(); + + // Fetch preview constraints from transfer + NSDictionary *previewConstraintsDict = [[transfer attributionInfo] objectForKey:@"pgenszc"]; + if (previewConstraintsDict) { + constraints = IMPreviewConstraintsFromDictionary(previewConstraintsDict); + } else { + // Or, make a guess. + constraints.maxPxWidth = 500.0; + constraints.scale = 1.0; + } + NSURL *previewURL = IMAttachmentPreviewFileURL(localURL, extension, YES); + if (!previewURL) { + // I'm not sure why this sometimes returns nil... + MBIMLogInfo(@"Unable to generate attachment preview cache URL for %@, making one up.", localURL); + + NSURL *temporaryAttachmentCache = [[[NSFileManager defaultManager] temporaryDirectory] URLByAppendingPathComponent:@"kordophone_attachment_cache"]; + temporaryAttachmentCache = [temporaryAttachmentCache URLByAppendingPathComponent:guid]; + + [[NSFileManager defaultManager] createDirectoryAtURL:temporaryAttachmentCache withIntermediateDirectories:YES attributes:nil error:nil]; + + previewURL = [temporaryAttachmentCache URLByAppendingPathComponent:[localURL lastPathComponent]]; + } + if (![[NSFileManager defaultManager] fileExistsAtPath:[previewURL path]]) { MBIMLogInfo(@"Generating preview image for guid: %@ at %@", guid, [previewURL path]); - // Fetch preview constraints from transfer - NSDictionary *previewConstraintsDict = [[transfer attributionInfo] objectForKey:@"pgenszc"]; - if (!previewConstraintsDict) { - MBIMLogInfo(@"No preview constraints for attachment guid: %@", guid); - response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; - break; - } - - IMPreviewConstraints constraints = IMPreviewConstraintsFromDictionary(previewConstraintsDict); - // Generate preview using preview generator manager NSError *error = nil; IMPreviewGeneratorManager *generator = [IMPreviewGeneratorManager sharedInstance]; From 72527088cc5970933ad0912bc8994c8883d61eca Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sun, 7 Jan 2024 18:12:17 -0800 Subject: [PATCH 52/75] logging: Use os log if running in launchd --- kordophone/Utilities/MBIMLogging.m | 69 ++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/kordophone/Utilities/MBIMLogging.m b/kordophone/Utilities/MBIMLogging.m index d089e26..899b070 100644 --- a/kordophone/Utilities/MBIMLogging.m +++ b/kordophone/Utilities/MBIMLogging.m @@ -7,38 +7,69 @@ // #import "MBIMLogging.h" +#import #define ESC(inner) "\033[" inner "m" #define CLR ESC("0") #define BLD "1;" #define RED "31;" -extern void __MBIMLogCommon(MBIMLogLevel level, NSString *format, ...) +static os_log_t MBIMOSLog(void) { static dispatch_once_t onceToken; - static NSDateFormatter *dateFormatter = nil; + static os_log_t customLog = NULL; dispatch_once(&onceToken, ^{ - dateFormatter = [[NSDateFormatter alloc] init]; - dateFormatter.dateFormat = @"Y-MM-d HH:mm:ss"; + customLog = os_log_create("net.buzzert.kordophoned", "General"); }); - + + return customLog; +} + +extern void __MBIMLogCommon(MBIMLogLevel level, NSString *format, ...) +{ va_list args; va_start(args, format); NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; va_end(args); - - const char *c_fmt = "%s"; - if (level == ML_NOTIFY) { - // BOLD - c_fmt = ESC(BLD) "%s"; - } else if (level == ML_ERROR) { - c_fmt = ESC(RED) "%s"; - } else if (level == ML_FATAL) { - c_fmt = ESC(BLD RED) "%s"; + + if (getenv("NSRunningFromLaunchd") != NULL) { + // Running with launchd, use oslog. + os_log_t mbimlog = MBIMOSLog(); + + switch (level) { + case ML_INFO: + os_log_debug(mbimlog, "%@", message); + break; + case ML_NOTIFY: + os_log_info(mbimlog, "%@", message); + break; + case ML_FATAL: + case ML_ERROR: + os_log_error(mbimlog, "%@", message); + break; + } + } else { + // Otherwise, write to stdout. + static dispatch_once_t onceToken; + static NSDateFormatter *dateFormatter = nil; + dispatch_once(&onceToken, ^{ + dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.dateFormat = @"Y-MM-d HH:mm:ss"; + }); + + const char *c_fmt = "%s"; + if (level == ML_NOTIFY) { + // BOLD + c_fmt = ESC(BLD) "%s"; + } else if (level == ML_ERROR) { + c_fmt = ESC(RED) "%s"; + } else if (level == ML_FATAL) { + c_fmt = ESC(BLD RED) "%s"; + } + + NSString *dateStr = [dateFormatter stringFromDate:[NSDate date]]; + fprintf(stdout, "%s: ", [dateStr UTF8String]); + fprintf(stdout, c_fmt, [message UTF8String]); + fprintf(stdout, CLR "\n"); } - - NSString *dateStr = [dateFormatter stringFromDate:[NSDate date]]; - fprintf(stdout, "%s: ", [dateStr UTF8String]); - fprintf(stdout, c_fmt, [message UTF8String]); - fprintf(stdout, CLR "\n"); } From 413fe338cabd9d04f1f7580e82ba6f6d4a3e79b5 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sun, 7 Jan 2024 18:14:50 -0800 Subject: [PATCH 53/75] Logging: these need to be public oslogs --- kordophone/Utilities/MBIMLogging.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kordophone/Utilities/MBIMLogging.m b/kordophone/Utilities/MBIMLogging.m index 899b070..1f227ca 100644 --- a/kordophone/Utilities/MBIMLogging.m +++ b/kordophone/Utilities/MBIMLogging.m @@ -38,14 +38,14 @@ extern void __MBIMLogCommon(MBIMLogLevel level, NSString *format, ...) switch (level) { case ML_INFO: - os_log_debug(mbimlog, "%@", message); + os_log_debug(mbimlog, "%{public}@", message); break; case ML_NOTIFY: - os_log_info(mbimlog, "%@", message); + os_log_info(mbimlog, "%{public}@", message); break; case ML_FATAL: case ML_ERROR: - os_log_error(mbimlog, "%@", message); + os_log_error(mbimlog, "%{public}@", message); break; } } else { From 58c84f6472be2acfd30f329c16444aa8180d13dd Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sat, 23 Mar 2024 16:49:33 -0700 Subject: [PATCH 54/75] MBIMFetchAttachmentOperation: Add cache headers --- kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m index be39d9f..0135d1a 100644 --- a/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMFetchAttachmentOperation.m @@ -124,7 +124,9 @@ mimeType = [NSString stringWithFormat:@"image/%@", extension]; } - response = [[MBIMDataResponse alloc] initWithData:responseData contentType:mimeType]; + MBIMDataResponse *dataResponse = [[MBIMDataResponse alloc] initWithData:responseData contentType:mimeType]; + dataResponse.httpHeaders[@"Cache-Control"] = @"public, immutable, max-age=31536000"; + response = dataResponse; } while (0); self.serverCompletionBlock(response); From b7312bccb9157bc7f6a57db3afc0d6823ca6a668 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Tue, 1 Oct 2024 19:52:21 -0700 Subject: [PATCH 55/75] adds /resolveHandle for resolving handles --- Dumped Classes/IMCore_ClassDump.h | 87 ++++++++++++ MessagesBridge.xcodeproj/project.pbxproj | 6 + .../Operations/MBIMResolveHandleOperation.h | 17 +++ .../Operations/MBIMResolveHandleOperation.m | 134 ++++++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 kordophone/Bridge/Operations/MBIMResolveHandleOperation.h create mode 100644 kordophone/Bridge/Operations/MBIMResolveHandleOperation.m diff --git a/Dumped Classes/IMCore_ClassDump.h b/Dumped Classes/IMCore_ClassDump.h index f74f609..cddcbd0 100644 --- a/Dumped Classes/IMCore_ClassDump.h +++ b/Dumped Classes/IMCore_ClassDump.h @@ -4090,6 +4090,30 @@ typedef NS_ENUM(NSInteger, IMMessageDescriptionType) { @property(readonly) unsigned long long hash; @property(readonly) Class superclass; +- (IMChat *)chatWithHandle:(IMHandle *)handle; +- (IMChat *)chatWithHandle:(IMHandle *)handle lastAddressedHandle:( NSString *)lastAddressedHandle lastAddressedSIMID:( NSString *)lastAddressedSIMID; +- (IMChat *)chatWithHandles:(NSArray *)handles; +- (IMChat *)chatWithHandles:(NSArray *)handles lastAddressedHandle:( NSString *)lastAddressedHandle lastAddressedSIMID:( NSString *)lastAddressedSIMID; +- (IMChat *)chatWithHandles:(NSArray *)handles displayName:( NSString *)displayName joinedChatsOnly:(BOOL)joinedChatsOnly; +- (IMChat *)chatWithHandles:(NSArray *)handles displayName:( NSString *)displayName joinedChatsOnly:(BOOL)joinedChatsOnly lastAddressedHandle:( NSString *)lastAddressedHandle lastAddressedSIMID:( NSString *)lastAddressedSIMID; + +- (NSArray *)allGUIDsForChat:(IMChat *)chat; +- ( IMChat *)existingChatWithHandle:(IMHandle *)handle; +- ( IMChat *)existingChatWithHandle:(IMHandle *)handle allowAlternativeService:(BOOL)allowAlternativeService; +- ( IMChat *)existingChatWithHandles:(NSArray *)handles; +- ( IMChat *)existingChatWithHandles:(NSArray *)handles allowAlternativeService:(BOOL)allowAlternativeService; +- ( IMChat *)existingChatWithHandles:(NSArray *)handles allowAlternativeService:(BOOL)allowAlternativeService groupID:(NSString *)groupID; +- ( IMChat *)existingChatWithHandles:(NSArray *)handles allowAlternativeService:(BOOL)allowAlternativeService groupID:( NSString *)groupID displayName:( NSString *)displayName joinedChatsOnly:(BOOL)joinedChatsOnly; +// - ( IMChat *)existingChatWithGUID:(NSString *)guid; +- ( IMChat *)existingChatWithPinningIdentifier:(NSString *)pinningIdentifier; +- ( IMChat *)existingChatWithDeviceIndependentID:(NSString *)deviceIndependentID; +// - ( IMChat *)existingChatWithChatIdentifier:(NSString *)identifier; +- ( IMChat *)existingChatWithPersonID:(NSString *)personID; +// - ( IMChat *)existingChatWithGroupID:(NSString *)groupID; +// - ( IMChat *)existingChatWithDisplayName:(NSString *)displayName; +- ( IMChat *)existingChatWithAddresses:(NSArray *)addresses allowAlternativeService:(BOOL)allowAlternativeService bestHandles:(NSArray * __autoreleasing*)outBestHandles; +- ( IMChat *)existingChatWithContacts:(NSSet /* */ *)contacts bestHandles:(NSArray * __autoreleasing * )outBestHandles; + @end @interface IMSimulatedChat : IMChat // @@ -4985,3 +5009,66 @@ typedef NS_ENUM(NSInteger, IMMessageDescriptionType) { - (struct __CFArray *)copyDDResultArrayByScanningStringForURLs; @end +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FZIDType) { + FZUnknownIDType = -1, + FZPhoneNumberBasedID = 0, + FZEmailBasedID = 1, + FZDSBasedID = 2, + FZBusinessBasedID = 3, + FZTemporaryBasedID = 4, + FZPseudonymBasedID = 5, + FZHardwareBasedID = 6, + FZSIPBasedID = 7, +}; + +@interface NSString (FezAdditions) + +- (FZIDType) _FZIDType; +- (FZIDType) _FZBestGuessFZIDType; + +- (NSString *) _IDFromFZIDType:(FZIDType)IDType; +- (NSString *) _stripFZIDPrefix; + +- (NSString *) _URIFromFZIDType:(FZIDType)IDType; +- (NSString *) _bestGuessURI; + +@end + +extern BOOL IMStringIsEmail( NSString * string ); +extern BOOL IMStringIsPhoneNumber( NSString * string ); +extern BOOL IMStringIsBusinessID( NSString * string ); +extern BOOL IMStringIsTemporaryID( NSString * string ); +extern BOOL IMStringIsPseudonymID( NSString * string ); +extern BOOL IMStringIsHardwareID( NSString * string ); +extern BOOL IMStringIsSIPID( NSString * string ); + +enum { + IMChatServiceForSendingAvailabilityErrorNone = 0, + IMChatServiceForSendingAvailabilityErrorTooManyRecipients = 1, + IMChatServiceForSendingAvailabilityErrorIMessageRequired = 2, + IMChatServiceForSendingAvailabilityErrorMMSRequired = 3, + IMChatServiceForSendingAvailabilityErrorNoAvailableServices = 4, + IMChatServiceForSendingAvailabilityErrorSpamFiltered = 5, +}; +typedef int8_t IMChatServiceForSendingAvailabilityError; + +extern void IMChatCalculateServiceForSendingNewComposeMaybeForce(NSArray *canonicalIDSAddresses, + NSString* _Nullable senderLastAddressedHandle, + NSString* _Nullable senderLastAddressedSIMID, + BOOL forceMMS, + BOOL hasEmailRecipients, + BOOL lastSentMessageWasNotDelivered, + BOOL conversationWasDowngraded, + BOOL hasConversationHistory, + IMService * _Nullable previousService, + void(^ _Nonnull completion)(BOOL allAddressesiMessageCapable, + NSDictionary * _Nullable perRecipientAvailability, + BOOL checkedServer, + IMChatServiceForSendingAvailabilityError error)); + +extern NSString *IMCopyIDForPhoneNumber(NSString *phoneNumber, NSString *_Nullable countryCode, BOOL useNetworkCountryCode) NS_RETURNS_RETAINED; +extern NSString *IMCopyIDForEmailAddress(NSString *emailAddress) NS_RETURNS_RETAINED; + +NS_ASSUME_NONNULL_END diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 427a335..faa70c7 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -94,6 +94,7 @@ CDE455A121A365AD0041F5DD /* MBIMMarkOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE455A021A365AD0041F5DD /* MBIMMarkOperation.m */; }; CDE455A421A5308D0041F5DD /* MBIMFetchAttachmentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE455A321A5308D0041F5DD /* MBIMFetchAttachmentOperation.m */; }; CDE455A721A531ED0041F5DD /* MBIMDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = CDE455A621A531ED0041F5DD /* MBIMDataResponse.m */; }; + CDEFF9FE2CACC7A700063C52 /* MBIMResolveHandleOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDEFF9FD2CACC7A700063C52 /* MBIMResolveHandleOperation.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 */; }; @@ -269,6 +270,8 @@ CDE455A321A5308D0041F5DD /* MBIMFetchAttachmentOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMFetchAttachmentOperation.m; sourceTree = ""; }; CDE455A521A531ED0041F5DD /* MBIMDataResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMDataResponse.h; sourceTree = ""; }; CDE455A621A531ED0041F5DD /* MBIMDataResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMDataResponse.m; sourceTree = ""; }; + CDEFF9FC2CACC7A700063C52 /* MBIMResolveHandleOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMResolveHandleOperation.h; sourceTree = ""; }; + CDEFF9FD2CACC7A700063C52 /* MBIMResolveHandleOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMResolveHandleOperation.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 = ""; }; /* End PBXFileReference section */ @@ -571,6 +574,8 @@ CDE455A021A365AD0041F5DD /* MBIMMarkOperation.m */, CD60205A219B623F0024D9C5 /* MBIMMessagesListOperation.h */, CD60205B219B623F0024D9C5 /* MBIMMessagesListOperation.m */, + CDEFF9FC2CACC7A700063C52 /* MBIMResolveHandleOperation.h */, + CDEFF9FD2CACC7A700063C52 /* MBIMResolveHandleOperation.m */, CD602060219B68950024D9C5 /* MBIMSendMessageOperation.h */, CD602061219B68950024D9C5 /* MBIMSendMessageOperation.m */, CD936A37289B49FC0093A1AC /* MBIMStatusOperation.h */, @@ -910,6 +915,7 @@ CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */, CD936A39289B49FC0093A1AC /* MBIMStatusOperation.m in Sources */, + CDEFF9FE2CACC7A700063C52 /* MBIMResolveHandleOperation.m in Sources */, CDE455A121A365AD0041F5DD /* MBIMMarkOperation.m in Sources */, CDE455A721A531ED0041F5DD /* MBIMDataResponse.m in Sources */, CD936A35289B47D60093A1AC /* MBIMVersionOperation.m in Sources */, diff --git a/kordophone/Bridge/Operations/MBIMResolveHandleOperation.h b/kordophone/Bridge/Operations/MBIMResolveHandleOperation.h new file mode 100644 index 0000000..02ecbae --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMResolveHandleOperation.h @@ -0,0 +1,17 @@ +// +// MBIMResolveHandleOperation.h +// kordophoned +// +// Created by James Magahern on 10/1/24. +// Copyright © 2024 James Magahern. All rights reserved. +// + +#import "MBIMBridgeOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMResolveHandleOperation : MBIMBridgeOperation + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/Operations/MBIMResolveHandleOperation.m b/kordophone/Bridge/Operations/MBIMResolveHandleOperation.m new file mode 100644 index 0000000..a4f2609 --- /dev/null +++ b/kordophone/Bridge/Operations/MBIMResolveHandleOperation.m @@ -0,0 +1,134 @@ +// +// MBIMResolveHandleOperation.m +// kordophoned +// +// Created by James Magahern on 10/1/24. +// Copyright © 2024 James Magahern. All rights reserved. +// + +#import "MBIMResolveHandleOperation.h" + +#import "IMCore_ClassDump.h" +#import "IMMessageItem+Encoded.h" + +/* + # Response: + Dictionary { + "resolvedHandle": + "status": valid | invalid | unknown, + "existingChat": chatGUID | null + } + + # IMHandle: + Dictionary { + "id" : resolvedID + "name" : fullName | null + } + */ + +@interface NSNumber (IDSStatusUtility) +- (NSString *)_idsStatusDescription; +@end + +@implementation NSNumber (IDSStatusUtility) +- (NSString *)_idsStatusDescription +{ + switch ([self unsignedIntegerValue]) { + case 1: return @"valid"; + case 2: return @"invalid"; + default: + return @"unknown"; + } +} +@end + +@interface IMHandle (Encoded) +- (NSDictionary *)mbim_dictionaryRepresentation; +@end + +@implementation IMHandle (Encoded) +- (NSDictionary *)mbim_dictionaryRepresentation +{ + return @{ + @"id" : [self ID], + @"name" : [self name] ?: [NSNull null], + }; +} +@end + +@implementation MBIMResolveHandleOperation + ++ (void)load { [super load]; } + ++ (NSString *)endpointName +{ + return @"resolveHandle"; +} + +- (void)main +{ + NSString *specifiedIdentifier = [[self valueForQueryItemWithName:@"id"] _stripFZIDPrefix]; + if (!specifiedIdentifier) { + MBIMLogError(@"No handle ID provided."); + HTTPErrorResponse *response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + self.serverCompletionBlock(response); + + return; + } + + if (IMStringIsPhoneNumber(specifiedIdentifier)) { + // Phone numbers will require a country code guess here. + // Passing nil, I presume, will make some kind of guess for the country code (useNetworkCountryCode). + specifiedIdentifier = IMCopyIDForPhoneNumber(specifiedIdentifier, nil, YES); + } + + NSString *canonicalAddress = [specifiedIdentifier _bestGuessURI]; + + IMAccount *iMessageAccount = [[IMAccountController sharedInstance] bestAccountForService:[IMServiceImpl iMessageService]]; + IMHandle *loginHandle = [iMessageAccount loginIMHandle]; + + NSString *lastAddressedHandle = [[[loginHandle ID] _stripFZIDPrefix] _bestGuessURI]; + IMChatCalculateServiceForSendingNewComposeMaybeForce(@[ canonicalAddress ], lastAddressedHandle, nil, NO, IMStringIsEmail(canonicalAddress), NO, NO, NO, [iMessageAccount service], ^(BOOL allAddressesiMessageCapable, NSDictionary * _Nullable perRecipientAvailability, BOOL checkedServer, IMChatServiceForSendingAvailabilityError error) + { + NSError *encodingError = nil; + NSObject *response = nil; + + do { + // Assume we have returned just one key here. + NSString *resolvedHandleID = [[perRecipientAvailability allKeys] firstObject]; + if (!resolvedHandleID) { + MBIMLogError(@"Unexpected missing handle id"); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + IMHandle *resolvedHandle = [iMessageAccount imHandleWithID:resolvedHandleID]; + if (!resolvedHandle) { + MBIMLogError(@"Couldn't resolve handle"); + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + break; + } + + NSString *handleStatus = [[perRecipientAvailability objectForKey:resolvedHandleID] _idsStatusDescription]; + + IMChat *existingChat = [[IMChatRegistry sharedInstance] existingChatForIMHandle:resolvedHandle]; + + NSDictionary *responseDict = @{ + @"resolvedHandle" : [resolvedHandle mbim_dictionaryRepresentation], + @"status" : handleStatus, + @"existingChat" : [existingChat guid] ?: [NSNull null], + }; + + NSData *data = [NSJSONSerialization dataWithJSONObject:responseDict options:0 error:&encodingError]; + if (encodingError) { + response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; + } else { + response = [[MBIMDataResponse alloc] initWithData:data contentType:@"application/json"]; + } + } while (0); + + self.serverCompletionBlock(response); + }); +} + +@end From 030e86e205d558cb23fd1e8807d53034c942a8fa Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 29 Mar 2024 17:08:04 -0700 Subject: [PATCH 56/75] uploadAttachment: [Security] sanitize incoming filename --- .../Bridge/Operations/MBIMUploadAttachmentOperation.m | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m index 3ec8a64..832b5c1 100644 --- a/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m +++ b/kordophone/Bridge/Operations/MBIMUploadAttachmentOperation.m @@ -38,7 +38,14 @@ break; } - NSString *localPath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename]; + // Sanitize filename + NSCharacterSet *dotCharacter = [NSCharacterSet characterSetWithCharactersInString:@"."]; + NSCharacterSet *illegalFileNameCharacters = [NSCharacterSet characterSetWithCharactersInString:@"/\\?%*|\"<>"]; + NSString *sanitizedFilename = [[[filename componentsSeparatedByCharactersInSet:illegalFileNameCharacters] + componentsJoinedByString:@"-"] + stringByTrimmingCharactersInSet:dotCharacter]; + + NSString *localPath = [NSTemporaryDirectory() stringByAppendingPathComponent:sanitizedFilename]; NSURL *localURL = [NSURL fileURLWithPath:localPath]; BOOL success = [attachmentData writeToURL:localURL atomically:NO]; if (!success) { From 9007b4503fa8f2acb7eae0f2124071f363637c8d Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 24 Oct 2024 22:27:19 -0700 Subject: [PATCH 57/75] JSON encoding error for super long messages --- Makefile | 1 + kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m | 4 +++- kordophone/Categories/IMChat+Encoded.m | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4f811a4..e3b73f4 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ INSTALL_PATH := /usr/share/kordophone +.PHONY: build/Release/kordophoned build/Release/kordophoned: xcodebuild diff --git a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m index 41bd25a..d404a3e 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m +++ b/kordophone/Bridge/Operations/Utilities/MBIMJSONDataResponse.m @@ -12,8 +12,10 @@ + (instancetype)responseWithJSONObject:(id)object { - NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL]; + NSError *error = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 error:&error]; if (data == nil) { + NSLog(@"JSON encoding error: %@", error); return nil; } diff --git a/kordophone/Categories/IMChat+Encoded.m b/kordophone/Categories/IMChat+Encoded.m index d74d966..7cdad49 100644 --- a/kordophone/Categories/IMChat+Encoded.m +++ b/kordophone/Categories/IMChat+Encoded.m @@ -22,7 +22,8 @@ IMMessage *lastMessage = [self lastMessage]; if (lastMessage) { - chatDict[@"lastMessagePreview"] = [lastMessage descriptionForPurpose:IMMessageDescriptionConversationList]; + NSString *lastMessagePreview = [lastMessage descriptionForPurpose:IMMessageDescriptionConversationList]; + chatDict[@"lastMessagePreview"] = [lastMessagePreview substringToIndex:MIN(128, [lastMessagePreview length])]; chatDict[@"lastMessage"] = [lastMessage mbim_dictionaryRepresentation]; } From d0e1f51b6b0e1a3d8c620910b84354fb5c477dd1 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Wed, 2 Oct 2024 17:18:44 -0700 Subject: [PATCH 58/75] adds some clues about how to implement tapbacks --- Dumped Classes/IMCore_ClassDump.h | 73 ++++++++++++++++++- .../Operations/MBIMSendMessageOperation.m | 31 ++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/Dumped Classes/IMCore_ClassDump.h b/Dumped Classes/IMCore_ClassDump.h index cddcbd0..af26ec0 100644 --- a/Dumped Classes/IMCore_ClassDump.h +++ b/Dumped Classes/IMCore_ClassDump.h @@ -1754,10 +1754,13 @@ __attribute__((visibility("default"))) @interface IMService : NSObject { } @property(nonatomic) BOOL chatInScrutinyMode; // @synthesize chatInScrutinyMode=_chatInScrutinyMode; @property(readonly, nonatomic) NSArray *messageEditChatItems; // @synthesize messageEditChatItems=_messageEditChatItems; @property(retain, nonatomic, setter=_setVisibleAssociatedMessageChatItems:) NSArray *visibleAssociatedMessageChatItems; // @synthesize visibleAssociatedMessageChatItems=_visibleAssociatedMessageChatItems; -@property(nonatomic) struct _NSRange messagePartRange; // @synthesize messagePartRange=_messagePartRange; @property(nonatomic) long long index; // @synthesize index=_index; @property(readonly, copy, nonatomic) NSAttributedString *text; // @synthesize text=_text; +@property (nonatomic, copy, readonly) NSString *threadIdentifier; +@property(nonatomic) struct _NSRange messagePartRange; // @synthesize messagePartRange=_messagePartRange; + + - (BOOL)canSendMessageAcknowledgment; - (void)_setMessageEditChatItems:(id)arg1; - (id)_initWithItem:(id)arg1 text:(id)arg2 index:(long long)arg3 messagePartRange:(struct _NSRange)arg4 visibleAssociatedMessageChatItems:(id)arg5; @@ -3689,6 +3692,58 @@ typedef NS_ENUM(NSInteger, IMMessageDescriptionType) { IMMessageDescriptionSPI, }; +typedef NS_ENUM(int64_t, IMAssociatedMessageType) { + IMAssociatedMessageTypeUnspecified = 0, + + IMAssociatedMessageTypeBreadcrumbUnconsumed = 2, + IMAssociatedMessageTypeBreadcrumbConsumed = 3, + IMAssociatedMessageTypeSticker = 1000, + IMAssociatedMessageTypeEmojiSticker = 1001, + + IMAssociatedMessageTypeAcknowledgmentHeart = 2000, + IMAssociatedMessageTypeAcknowledgmentThumbsUp = 2001, + IMAssociatedMessageTypeAcknowledgmentThumbsDown = 2002, + IMAssociatedMessageTypeAcknowledgmentHa = 2003, + IMAssociatedMessageTypeAcknowledgmentExclamation = 2004, + IMAssociatedMessageTypeAcknowledgmentQuestionMark = 2005, + + IMAssociatedMessageTypeAcknowledgmentHeartRemoved = 3000, + IMAssociatedMessageTypeAcknowledgmentThumbsUpRemoved = 3001, + IMAssociatedMessageTypeAcknowledgmentThumbsDownRemoved = 3002, + IMAssociatedMessageTypeAcknowledgmentHaRemoved = 3003, + IMAssociatedMessageTypeAcknowledgmentExclamationRemoved = 3004, + IMAssociatedMessageTypeAcknowledgmentQuestionMarkRemoved = 3005, +}; + +extern NSString * const IMMessageSummaryInfoSummary; +extern NSString * const IMMessageSummaryInfoContentType; +extern NSString * const IMMessageSummaryInfoPluginBundleID; +extern NSString * const IMMessageSummaryInfoPluginDisplayName; +extern NSString * const IMMessageSummaryInfoAssociatedBalloonBundleID; +extern NSString * const IMMessageSummaryInfoSourceApplicationID; +extern NSString * const IMMessageSummaryInfoUpdatedDateWithServerTime; +extern NSString * const IMMessageSummaryInfoHasBeenRetried; +extern NSString * const IMMessageSummaryInfoTapbackRepresentationKey; +extern NSString * const IMMessageSummaryInfoStickerRepositioningKey; +extern NSString * const IMMessageSummaryInfoTranscriptSharingMessageTypeKey; +extern NSString * const IMMessageSummaryInfoTranscriptSharingMessageFirstItemKey; +extern NSString * const IMMessageSummaryInfoEditedPartIndexes; +extern NSString * const IMMessageSummaryInfoRetractedPartIndexes; +extern NSString * const IMMessageSummaryInfoOriginalTextRangesByPartIndex; +extern NSString * const IMMessageSummaryInfoOriginalTextRangeLocationSubKey; +extern NSString * const IMMessageSummaryInfoOriginalTextRangeLengthSubKey; +extern NSString * const IMMessageSummaryInfoEditDeliveryFailedForPartIndexes; +extern NSString * const IMMessageSummaryInfoRetractDeliveryFailedForPartIndexes; +extern NSString * const IMMessageSummaryInfoEditUnsupportedByHandleIDs; +extern NSString * const IMMessageSummaryInfoTranslatedText; +extern NSString * const IMMessageSummaryInfoDetectedLanguage; +extern NSString * const IMMessageSummaryInfoCMMState; +extern NSString * const IMMessageSummaryInfoCMMAssetOffset; +extern NSString * const IMMessageItemErrorDomain; +extern NSString * const IMMessageSentDistributedNotification; +extern NSString * const IMMessageSentDistributedNotificationUserInfoMessageGUIDKey; +extern NSString * const IMMessageSentDistributedNotificationUserInfoSucessKey; + @interface IMMessage : NSObject { @@ -3745,6 +3800,22 @@ typedef NS_ENUM(NSInteger, IMMessageDescriptionType) { + (id)breadcrumbMessageWithText:(id)arg1 associatedMessageGUID:(id)arg2 balloonBundleID:(id)arg3 fileTransferGUIDs:(id)arg4 payloadData:(id)arg5; + (id)editedMessageWithOriginalMessage:(id)arg1 originalPrefixedGUID:(id)arg2 newBody:(id)arg3; + (id)instantMessageWithAssociatedMessageContent:(id)arg1 flags:(unsigned long long)arg2 associatedMessageGUID:(id)arg3 associatedMessageType:(long long)arg4 associatedMessageRange:(struct _NSRange)arg5 messageSummaryInfo:(id)arg6; + ++ (instancetype)instantMessageWithAssociatedMessageContent:(NSAttributedString *) content + flags:(IMMessageFlags)flags + associatedMessageGUID:(NSString*) associatedMessageGUID + associatedMessageType:(IMAssociatedMessageType) associatedMessageType + associatedMessageRange:(NSRange) associatedMessageRange + messageSummaryInfo:(NSDictionary*) messageSummaryInfo + threadIdentifier:(NSString *)threadIdentifier; + ++ (instancetype)breadcrumbMessageWithText:(NSAttributedString *)text + associatedMessageGUID:(NSString *)messageGUID + balloonBundleID:(NSString *)balloonBundleID + fileTransferGUIDs:(NSArray *)fileTransferGUIDs + payloadData:(NSData *)payloadData + threadIdentifier:(NSString *)threadIdentifier; + @property(nonatomic) unsigned long long sortID; // @synthesize sortID=_sortID; @property(nonatomic) BOOL isSOS; // @synthesize isSOS=_isSOS; @property(retain, nonatomic) NSString *notificationIDSTokenURI; // @synthesize notificationIDSTokenURI=_notificationIDSTokenURI; diff --git a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m index 7221913..85b7b82 100644 --- a/kordophone/Bridge/Operations/MBIMSendMessageOperation.m +++ b/kordophone/Bridge/Operations/MBIMSendMessageOperation.m @@ -57,6 +57,26 @@ return result; } +#if 0 +- (NSDictionary *)adjustMessageSummaryInfoForSending:(NSDictionary *)messageSummaryInfo +{ + NSMutableDictionary *adjustedInfo = [messageSummaryInfo mutableCopy]; + if (!adjustedInfo) { + adjustedInfo = [NSMutableDictionary dictionary]; + } + + if ([fullText length] > 50) { + summary = [[summary substringToIndex:[summary rangeOfComposedCharacterSequenceAtIndex:kMaxSummaryLength].location] stringByAppendingString:@"…"]; + adjustedInfo[IMMessageSummaryInfoSummary] = summary; + } + + + adjustedInfo[IMMessageSummaryInfoTapbackRepresentationKey] = @"Loved"; + + return adjustedInfo; +} +#endif + - (void)main { NSObject *response = [[HTTPErrorResponse alloc] initWithErrorCode:500]; @@ -75,6 +95,17 @@ return; } + // tapbacks +#if 0 + IMMessage *acknowledgment = [IMMessage instantMessageWithAssociatedMessageContent: /* [NSString stringWithFormat:@"%@ \"%%@\"", tapbackAction] */ + flags:0 + associatedMessageGUID:guid + associatedMessageType:IMAssociatedMessageTypeAcknowledgmentHeart + associatedMessageRange:[imMessage messagePartRange] + messageSummaryInfo:[self adjustMessageSummaryInfoForSending:message] + threadIdentifier:[imMessage threadIdentifier]]; +#endif + NSArray *transferGUIDs = [args objectForKey:@"fileTransferGUIDs"]; if (!transferGUIDs) { transferGUIDs = @[]; From 95c2e855dd2b0aedcbbc250c89023594c4497b4c Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 9 May 2025 22:25:57 -0700 Subject: [PATCH 59/75] some better logging around websocket connections --- kordophone/Bridge/MBIMHTTPConnection.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index e81e45f..c7fc2d0 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -132,13 +132,17 @@ NSURL *url = [NSURL URLWithString:path]; NSString *endpointName = [url lastPathComponent]; NSString *authTokenString = [url valueForQueryItemWithName:@"token"]; - MBIMAuthToken *authToken = [[MBIMAuthToken alloc] initWithTokenString:authTokenString]; + MBIMAuthToken *queryAuthToken = [[MBIMAuthToken alloc] initWithTokenString:authTokenString]; + NSLog(@"Websocket for URI: %@ | authenticated request: %@", path, [self isAuthenticated] ? @"YES" : @"NO"); if ([endpointName isEqualToString:@"updates"]) { - if (![authToken isValid]) { + if (![self isAuthenticated] && ![queryAuthToken isValid]) { + NSLog(@"Websocket: auth invalid, rejecting."); + NSLog(@"Query Token: %@, raw: %@", queryAuthToken, authTokenString); return nil; } + NSLog(@"Vending websocket for consumer"); return [[MBIMUpdateQueue sharedInstance] vendUpdateWebSocketConsumerForRequest:request socket:asyncSocket]; } From 7339b49759030f6a90783b9cd4b5481219819750 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 9 May 2025 23:39:16 -0700 Subject: [PATCH 60/75] Encoding: need to include associated chat item guids. Beginning to understand associated chat items (reactions, etc). --- Dumped Classes/IMSharedUtilities_ClassDump.h | 1 + kordophone/Categories/IMChat+Encoded.m | 7 +++ kordophone/Categories/IMMessageItem+Encoded.m | 43 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/Dumped Classes/IMSharedUtilities_ClassDump.h b/Dumped Classes/IMSharedUtilities_ClassDump.h index 9945a4f..f3f25b5 100644 --- a/Dumped Classes/IMSharedUtilities_ClassDump.h +++ b/Dumped Classes/IMSharedUtilities_ClassDump.h @@ -1704,3 +1704,4 @@ extern NSURL* IMAttachmentPreviewFileURL(NSURL *attachmentURL, NSString *extensi - (id)initWithSerializedError_im:(struct NSDictionary *)arg1; @end +extern NSString *IMAssociatedMessageDecodeGUID(NSString* guid); diff --git a/kordophone/Categories/IMChat+Encoded.m b/kordophone/Categories/IMChat+Encoded.m index 7cdad49..c852d94 100644 --- a/kordophone/Categories/IMChat+Encoded.m +++ b/kordophone/Categories/IMChat+Encoded.m @@ -20,6 +20,13 @@ chatDict[@"date"] = MBIMWebServerFormatISO8601([self lastFinishedMessageDate]); chatDict[@"unreadCount"] = @([self unreadMessageCount]); + // NOTE: -[IMChat lastMessage] != -[[IMChat chatItems] lastMessage]. + // This means the messages we get back from the message list operation might be different from this here, which means we + // can't reliably use `lastMessage.guid` as a sync anchor. + // + // Ideally, everything should move to use chat items instead of messages so we can handle associated message items (reactions). + // When that happens, we should use `lastFinishedMessageItem` here instead of `lastMessage`, and avoid the db hit. + // IMMessage *lastMessage = [self lastMessage]; if (lastMessage) { NSString *lastMessagePreview = [lastMessage descriptionForPurpose:IMMessageDescriptionConversationList]; diff --git a/kordophone/Categories/IMMessageItem+Encoded.m b/kordophone/Categories/IMMessageItem+Encoded.m index aeaead6..a4edf11 100644 --- a/kordophone/Categories/IMMessageItem+Encoded.m +++ b/kordophone/Categories/IMMessageItem+Encoded.m @@ -9,6 +9,40 @@ #import "IMMessageItem+Encoded.h" #import "MBIMHTTPUtilities.h" +static NSString* IMAssociatedMessageTypeValue(IMAssociatedMessageType type) { + switch (type) { + case IMAssociatedMessageTypeAcknowledgmentHeart: + return @"heart"; + case IMAssociatedMessageTypeAcknowledgmentThumbsUp: + return @"thumbsUp"; + case IMAssociatedMessageTypeAcknowledgmentThumbsDown: + return @"thumbsDown"; + case IMAssociatedMessageTypeAcknowledgmentHa: + return @"ha"; + case IMAssociatedMessageTypeAcknowledgmentExclamation: + return @"exclamation"; + case IMAssociatedMessageTypeAcknowledgmentQuestionMark: + return @"questionMark"; + + case IMAssociatedMessageTypeAcknowledgmentHeartRemoved: + return @"removed heart"; + case IMAssociatedMessageTypeAcknowledgmentThumbsUpRemoved: + return @"removed thumbsUp"; + case IMAssociatedMessageTypeAcknowledgmentThumbsDownRemoved: + return @"removed thumbsDown"; + case IMAssociatedMessageTypeAcknowledgmentHaRemoved: + return @"removed ha"; + case IMAssociatedMessageTypeAcknowledgmentExclamationRemoved: + return @"removed exclamation"; + case IMAssociatedMessageTypeAcknowledgmentQuestionMarkRemoved: + return @"removed questionMark"; + + case IMAssociatedMessageTypeUnspecified: + default: + return @"unknown"; + } +} + @implementation IMMessage (Encoded) - (NSDictionary *)mbim_dictionaryRepresentation @@ -19,6 +53,15 @@ messageDict[@"sender"] = ([self isFromMe] ? nil : [[self sender] displayID]); // TODO: nil sender is still a weird way to represent this... messageDict[@"guid"] = [self guid]; + if ([self associatedMessageGUID]) { + NSString *encodedAssociatedMessageGUID = [self associatedMessageGUID]; + messageDict[@"associatedMessageGUID"] = encodedAssociatedMessageGUID; + messageDict[@"associatedMessageType"] = IMAssociatedMessageTypeValue([self associatedMessageType]); + + NSString *decodedAssociatedChatItemGUID = IMAssociatedMessageDecodeGUID(encodedAssociatedMessageGUID); + if (decodedAssociatedChatItemGUID) messageDict[@"associatedChatItemGUID"] = decodedAssociatedChatItemGUID; + } + if ([self fileTransferGUIDs]) { // Support only images right now NSMutableDictionary *attachmentMetadatas = [NSMutableDictionary dictionary]; From 1a5bb874dc5430b7c768a669e9a230c16c1193b3 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 13:17:31 -0700 Subject: [PATCH 61/75] rpath manipulation: This may not be necessary anymore --- MessagesBridge.xcodeproj/project.pbxproj | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index faa70c7..e63364a 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -730,7 +730,6 @@ CDF6232E219A895D00690038 /* Sources */, CDF6232F219A895D00690038 /* Frameworks */, CDF62330219A895D00690038 /* CopyFiles */, - 1AAB32AD21F8245D004A2A72 /* Add current directory to rpath */, ); buildRules = ( ); @@ -805,24 +804,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1AAB32AD21F8245D004A2A72 /* Add current directory to rpath */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Add current directory to rpath"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nRESULT=$(install_name_tool -delete_rpath $BUILT_PRODUCTS_DIR $BUILT_PRODUCTS_DIR/$EXECUTABLE_NAME 2> /dev/null)\n\ninstall_name_tool -add_rpath $BUILT_PRODUCTS_DIR $BUILT_PRODUCTS_DIR/$EXECUTABLE_NAME\n"; - }; CD936A36289B48930093A1AC /* Compile Version String */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; From 78eb9461095282ecadd8e0284db8ea3d4646fd56 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 13:26:15 -0700 Subject: [PATCH 62/75] prototype of ping pong websocket (ai generated) --- MessagesBridge.xcodeproj/project.pbxproj | 6 + kordophone/Bridge/MBIMPingPongWebSocket.h | 17 ++ kordophone/Bridge/MBIMPingPongWebSocket.m | 242 ++++++++++++++++++++++ kordophone/Bridge/MBIMUpdateQueue.m | 3 +- 4 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 kordophone/Bridge/MBIMPingPongWebSocket.h create mode 100644 kordophone/Bridge/MBIMPingPongWebSocket.m diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index e63364a..996e108 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -89,6 +89,7 @@ CD936A32289B353F0093A1AC /* MBIMErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A31289B353F0093A1AC /* MBIMErrorResponse.m */; }; CD936A35289B47D60093A1AC /* MBIMVersionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A34289B47D50093A1AC /* MBIMVersionOperation.m */; }; CD936A39289B49FC0093A1AC /* MBIMStatusOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A38289B49FC0093A1AC /* MBIMStatusOperation.m */; }; + CDA64B472DFCBF3000E9B07E /* MBIMPingPongWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA64B462DFCBF3000E9B07E /* MBIMPingPongWebSocket.m */; }; CDDCF78D283F398C0087ABDF /* MBIMDeleteConversationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.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 */; }; @@ -260,6 +261,8 @@ CD936A34289B47D50093A1AC /* MBIMVersionOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMVersionOperation.m; sourceTree = ""; }; CD936A37289B49FC0093A1AC /* MBIMStatusOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMStatusOperation.h; sourceTree = ""; }; CD936A38289B49FC0093A1AC /* MBIMStatusOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMStatusOperation.m; sourceTree = ""; }; + CDA64B452DFCBF3000E9B07E /* MBIMPingPongWebSocket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMPingPongWebSocket.h; sourceTree = ""; }; + CDA64B462DFCBF3000E9B07E /* MBIMPingPongWebSocket.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMPingPongWebSocket.m; sourceTree = ""; }; CDDCF78B283F398C0087ABDF /* MBIMDeleteConversationOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMDeleteConversationOperation.h; sourceTree = ""; }; CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMDeleteConversationOperation.m; sourceTree = ""; }; CDE4556221A3578A0041F5DD /* IMChat+Encoded.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IMChat+Encoded.h"; sourceTree = ""; }; @@ -376,6 +379,8 @@ CD14F1AC219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m */, 1ACFCFE2219EB45300E2C237 /* MBIMHTTPConnection.h */, 1ACFCFE3219EB45300E2C237 /* MBIMHTTPConnection.m */, + CDA64B452DFCBF3000E9B07E /* MBIMPingPongWebSocket.h */, + CDA64B462DFCBF3000E9B07E /* MBIMPingPongWebSocket.m */, ); path = Bridge; sourceTree = ""; @@ -877,6 +882,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CDA64B472DFCBF3000E9B07E /* MBIMPingPongWebSocket.m in Sources */, CD14F1AD219FFAE100E7DD22 /* MBIMConcurrentHTTPServer.m in Sources */, 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */, CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.h b/kordophone/Bridge/MBIMPingPongWebSocket.h new file mode 100644 index 0000000..66a3734 --- /dev/null +++ b/kordophone/Bridge/MBIMPingPongWebSocket.h @@ -0,0 +1,17 @@ +// +// MBIMPingPongWebSocket.h +// kordophoned +// +// Created by James Magahern on 6/13/25. +// Copyright © 2025 James Magahern. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MBIMPingPongWebSocket : WebSocket + +@end + +NS_ASSUME_NONNULL_END diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.m b/kordophone/Bridge/MBIMPingPongWebSocket.m new file mode 100644 index 0000000..223edfc --- /dev/null +++ b/kordophone/Bridge/MBIMPingPongWebSocket.m @@ -0,0 +1,242 @@ +// +// MBIMPingPongWebSocket.m +// kordophoned +// +// Created by James Magahern on 6/13/25. +// Copyright © 2025 James Magahern. All rights reserved. +// + +#import "MBIMPingPongWebSocket.h" +#import "GCDAsyncSocket.h" + +// WebSocket opcodes (from the base class) +#define TIMEOUT_NONE -1 +#define TIMEOUT_REQUEST_BODY 10 + +#define TAG_HTTP_REQUEST_BODY 100 +#define TAG_HTTP_RESPONSE_HEADERS 200 +#define TAG_HTTP_RESPONSE_BODY 201 + +#define TAG_PREFIX 300 +#define TAG_MSG_PLUS_SUFFIX 301 +#define TAG_MSG_WITH_LENGTH 302 +#define TAG_MSG_MASKING_KEY 303 +#define TAG_PAYLOAD_PREFIX 304 +#define TAG_PAYLOAD_LENGTH 305 +#define TAG_PAYLOAD_LENGTH16 306 +#define TAG_PAYLOAD_LENGTH64 307 + +#define WS_OP_CONTINUATION_FRAME 0 +#define WS_OP_TEXT_FRAME 1 +#define WS_OP_BINARY_FRAME 2 +#define WS_OP_CONNECTION_CLOSE 8 +#define WS_OP_PING 9 +#define WS_OP_PONG 10 + +// Additional tags for ping/pong handling +#define TAG_PING_PAYLOAD 400 +#define TAG_PONG_SENT 401 + +@interface WebSocket () +- (void)socket:(GCDAsyncSocket *)asyncSocket didReadData:(NSData *)data withTag:(long)tag; +@end + +@implementation MBIMPingPongWebSocket +{ + NSData *pendingPingPayload; +} + +#pragma mark - Ping/Pong Frame Construction + +- (NSData *)createPongFrameWithPayload:(NSData *)pingPayload { + NSMutableData *frame = [NSMutableData data]; + + // First byte: FIN (1) + RSV (000) + Opcode (1010 = 0xA for Pong) + uint8_t firstByte = 0x8A; // 10001010 in binary + [frame appendBytes:&firstByte length:1]; + + // Second byte: MASK (0) + Payload Length + NSUInteger payloadLength = [pingPayload length]; + + if (payloadLength <= 125) { + // Short payload length (0-125 bytes) + uint8_t secondByte = (uint8_t)payloadLength; // MASK bit is 0 for server-to-client + [frame appendBytes:&secondByte length:1]; + } + else if (payloadLength <= 65535) { + // Medium payload length (126-65535 bytes) + uint8_t secondByte = 126; + [frame appendBytes:&secondByte length:1]; + + // Add 16-bit length in network byte order (big-endian) + uint16_t extendedLength = htons((uint16_t)payloadLength); + [frame appendBytes:&extendedLength length:2]; + } + else { + // Large payload length (65536+ bytes) - rarely needed for pings + uint8_t secondByte = 127; + [frame appendBytes:&secondByte length:1]; + + // Add 64-bit length in network byte order (big-endian) + uint64_t extendedLength = OSSwapHostToBigInt64(payloadLength); + [frame appendBytes:&extendedLength length:8]; + } + + // Append the payload (copied exactly from ping) + if (payloadLength > 0) { + [frame appendData:pingPayload]; + } + + return [frame copy]; +} + +- (void)sendPongWithPayload:(NSData *)payload socket:(GCDAsyncSocket *)asyncSocket { + NSData *pongFrame = [self createPongFrameWithPayload:payload]; + + // Send the pong frame directly through the socket + [asyncSocket writeData:pongFrame withTimeout:TIMEOUT_NONE tag:TAG_PONG_SENT]; + + NSLog(@"Sent pong frame with payload length: %lu", (unsigned long)[payload length]); +} + +#pragma mark - Override AsyncSocket Delegate + +- (void)socket:(GCDAsyncSocket *)asyncSocket didReadData:(NSData *)data withTag:(long)tag { + NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; // sheesh. + + // Handle our custom ping/pong tags + if (tag == TAG_PING_PAYLOAD) { + // We've read the ping payload, now send the pong response + [self sendPongWithPayload:data socket:asyncSocket]; + + // Continue reading the next frame + [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX]; + return; + } + + if (tag == TAG_PONG_SENT) { + // Pong was sent successfully, continue normal operation + return; + } + + // For TAG_PAYLOAD_PREFIX, we need to intercept and handle ping frames + if (tag == TAG_PAYLOAD_PREFIX) { + UInt8 *pFrame = (UInt8 *)[data bytes]; + UInt8 frame = *pFrame; + + // Check if this is a valid WebSocket frame + if (![self isValidWebSocketFrame:frame]) { + [self didClose]; + return; + } + + NSUInteger opcode = frame & 0x0F; + + // Handle ping frames specially + if (opcode == WS_OP_PING) { + // Read the payload length byte next + [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH]; + return; + } + + // Handle pong frames (just log and continue) + if (opcode == WS_OP_PONG) { + NSLog(@"Received pong frame"); + // Read the payload length byte next, but we'll ignore pong payloads + [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH]; + return; + } + } + + // For TAG_PAYLOAD_LENGTH, check if we're handling a ping + if (tag == TAG_PAYLOAD_LENGTH) { + UInt8 frame = *(UInt8 *)[data bytes]; + BOOL masked = (frame & 0x80) != 0; + NSUInteger length = frame & 0x7F; + + // If we were processing a ping frame, handle the payload reading + if (nextOpCode == WS_OP_PING) { + if (length <= 125) { + if (masked) { + // Read masking key first, then payload + [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; + } + // Read ping payload + [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; + return; + } + else if (length == 126) { + [asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16]; + return; + } + else { + [asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64]; + return; + } + } + + // If we were processing a pong frame, just skip it + if (nextOpCode == WS_OP_PONG) { + if (length <= 125) { + if (masked) { + [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; + } + // Skip pong payload and continue to next frame + [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX]; + return; + } + else if (length == 126) { + [asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16]; + return; + } + else { + [asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64]; + return; + } + } + } + + // Handle masking key reading for ping frames + if (tag == TAG_MSG_MASKING_KEY && nextOpCode == WS_OP_PING) { + // Store the masking key and read the actual payload + pendingPingPayload = [data copy]; + // The payload length was already determined, read it + // Note: This is a simplified version - you'd need to track the actual length + return; + } + + // For all other cases, call the parent implementation + [super socket:asyncSocket didReadData:data withTag:tag]; +} + +#pragma mark - Helper Methods + +// Expose the isValidWebSocketFrame method since it's private in the parent +- (BOOL)isValidWebSocketFrame:(UInt8)frame { + NSUInteger rsv = frame & 0x70; + NSUInteger opcode = frame & 0x0F; + if (rsv || (3 <= opcode && opcode <= 7) || (0xB <= opcode && opcode <= 0xF)) { + return NO; + } + return YES; +} + +// Override didReceiveMessage to add logging +- (void)didReceiveMessage:(NSString *)msg { + NSLog(@"Received message: %@", msg); + [super didReceiveMessage:msg]; +} + +// Override didOpen to add logging +- (void)didOpen { + NSLog(@"WebSocket opened with ping/pong support"); + [super didOpen]; +} + +- (void)didClose { + NSLog(@"WebSocket closed"); + [super didClose]; +} + +@end + diff --git a/kordophone/Bridge/MBIMUpdateQueue.m b/kordophone/Bridge/MBIMUpdateQueue.m index e25b40e..3dafdf9 100644 --- a/kordophone/Bridge/MBIMUpdateQueue.m +++ b/kordophone/Bridge/MBIMUpdateQueue.m @@ -11,6 +11,7 @@ #import "IMChat+Encoded.h" #import "MBIMHTTPConnection.h" #import "MBIMURLUtilities.h" +#import "MBIMPingPongWebSocket.h" #import #import @@ -105,7 +106,7 @@ static const NSUInteger kUpdateItemsCullingLength = 100; - (WebSocket *)vendUpdateWebSocketConsumerForRequest:(HTTPMessage *)request socket:(GCDAsyncSocket *)gcdSocket { - WebSocket *socket = [[WebSocket alloc] initWithRequest:request socket:gcdSocket]; + WebSocket *socket = [[MBIMPingPongWebSocket alloc] initWithRequest:request socket:gcdSocket]; socket.delegate = self; MBIMUpdateConsumer consumer = ^(NSArray *updates) { From 7352efbcfd53c494c6a5bfa3184b3289f7bced53 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 13:35:42 -0700 Subject: [PATCH 63/75] Switch to statically linking CocoaHTTPServer --- MessagesBridge.xcodeproj/project.pbxproj | 48 +++---------------- kordophone/Bridge/MBIMBridge.m | 2 +- kordophone/Bridge/MBIMConcurrentHTTPServer.h | 2 +- kordophone/Bridge/MBIMHTTPConnection.h | 2 +- kordophone/Bridge/MBIMHTTPConnection.m | 2 +- kordophone/Bridge/MBIMPingPongWebSocket.h | 2 +- kordophone/Bridge/MBIMUpdateQueue.m | 6 +-- .../Bridge/Operations/MBIMBridgeOperation.h | 6 +-- .../Operations/Utilities/MBIMDataResponse.h | 2 +- 9 files changed, 18 insertions(+), 54 deletions(-) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 996e108..24692bb 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -66,7 +66,7 @@ 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF19219EB2AC00E2C237 /* DDASLLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDA219EB2AC00E2C237 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */; }; 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */; }; + 1ACFCFDF219EB31400E2C237 /* libCocoaHTTPServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* libCocoaHTTPServer.a */; }; 1AD8936E21EFD986009B599A /* MBIMUploadAttachmentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AD8936D21EFD986009B599A /* MBIMUploadAttachmentOperation.m */; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F1A0219FE7D600E7DD22 /* MBIMUpdatePollOperation.m */; }; @@ -157,7 +157,7 @@ 1AAB32AF21F82EB7004A2A72 /* MBIMLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBIMLogging.h; sourceTree = ""; }; 1AAB32B021F82EB7004A2A72 /* MBIMLogging.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBIMLogging.m; sourceTree = ""; }; 1AAB32B221F835BD004A2A72 /* KPServer.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KPServer.pch; sourceTree = ""; }; - 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CocoaHTTPServer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1ACFCDE2219EB28A00E2C237 /* libCocoaHTTPServer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCocoaHTTPServer.a; sourceTree = BUILT_PRODUCTS_DIR; }; 1ACFCDFC219EB2AB00E2C237 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 1ACFCDFE219EB2AB00E2C237 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.markdown; sourceTree = ""; }; 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPConnection.h; sourceTree = ""; }; @@ -308,7 +308,7 @@ CD2782BC29527FE500C0C030 /* IMSharedUtilities.framework in Frameworks */, 1A257CCB23A8681200A4A2C8 /* Security.framework in Frameworks */, CD2783002952876700C0C030 /* ImageIO.framework in Frameworks */, - 1ACFCFDF219EB31400E2C237 /* CocoaHTTPServer.framework in Frameworks */, + 1ACFCFDF219EB31400E2C237 /* libCocoaHTTPServer.a in Frameworks */, CD2782FE2952875F00C0C030 /* CoreGraphics.framework in Frameworks */, 1A257CC923A867EF00A4A2C8 /* IMCore.framework in Frameworks */, ); @@ -337,7 +337,7 @@ CDF62332219A895D00690038 /* kordophoned */, CD83E161219BE91500F4CCEA /* libagentHook.dylib */, CD14F18B219E2DB400E7DD22 /* Tests.xctest */, - 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */, + 1ACFCDE2219EB28A00E2C237 /* libCocoaHTTPServer.a */, ); name = Products; sourceTree = ""; @@ -680,8 +680,6 @@ buildPhases = ( 1ACFCDDD219EB28A00E2C237 /* Sources */, 1ACFCDDE219EB28A00E2C237 /* Frameworks */, - 1ACFCDDF219EB28A00E2C237 /* Headers */, - 1ACFCDE0219EB28A00E2C237 /* Resources */, ); buildRules = ( ); @@ -689,8 +687,8 @@ ); name = CocoaHTTPServer; productName = CocoaHTTPServer; - productReference = 1ACFCDE2219EB28A00E2C237 /* CocoaHTTPServer.framework */; - productType = "com.apple.product-type.framework"; + productReference = 1ACFCDE2219EB28A00E2C237 /* libCocoaHTTPServer.a */; + productType = "com.apple.product-type.library.static"; }; CD14F18A219E2DB400E7DD22 /* Tests */ = { isa = PBXNativeTarget; @@ -1057,27 +1055,10 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); MTL_ENABLE_DEBUG_INFO = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.github.CocoaHTTPServer; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; }; name = Debug; }; @@ -1085,26 +1066,9 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.github.CocoaHTTPServer; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; }; name = Release; }; diff --git a/kordophone/Bridge/MBIMBridge.m b/kordophone/Bridge/MBIMBridge.m index f1cbe26..95315f5 100644 --- a/kordophone/Bridge/MBIMBridge.m +++ b/kordophone/Bridge/MBIMBridge.m @@ -14,7 +14,7 @@ #import "MBIMUpdateQueue.h" #import "hooking.h" -#import +#import "HTTPServer.h" #import "IMCore_ClassDump.h" #import "IMFoundation_ClassDump.h" diff --git a/kordophone/Bridge/MBIMConcurrentHTTPServer.h b/kordophone/Bridge/MBIMConcurrentHTTPServer.h index e19cc43..dc41b4d 100644 --- a/kordophone/Bridge/MBIMConcurrentHTTPServer.h +++ b/kordophone/Bridge/MBIMConcurrentHTTPServer.h @@ -6,7 +6,7 @@ // Copyright © 2018 James Magahern. All rights reserved. // -#import +#import "HTTPServer.h" NS_ASSUME_NONNULL_BEGIN diff --git a/kordophone/Bridge/MBIMHTTPConnection.h b/kordophone/Bridge/MBIMHTTPConnection.h index de4f094..703f3c7 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.h +++ b/kordophone/Bridge/MBIMHTTPConnection.h @@ -6,7 +6,7 @@ // Copyright © 2018 James Magahern. All rights reserved. // -#import +#import "HTTPConnection.h" @interface MBIMHTTPConnection : HTTPConnection diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index c7fc2d0..5507df8 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -16,7 +16,7 @@ #import "MBIMURLUtilities.h" #import -#import +#import "HTTPMessage.h" @interface HTTPConnection (/* INTERNAL */) - (BOOL)isAuthenticated; diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.h b/kordophone/Bridge/MBIMPingPongWebSocket.h index 66a3734..54f3989 100644 --- a/kordophone/Bridge/MBIMPingPongWebSocket.h +++ b/kordophone/Bridge/MBIMPingPongWebSocket.h @@ -6,7 +6,7 @@ // Copyright © 2025 James Magahern. All rights reserved. // -#import +#import "WebSocket.h" NS_ASSUME_NONNULL_BEGIN diff --git a/kordophone/Bridge/MBIMUpdateQueue.m b/kordophone/Bridge/MBIMUpdateQueue.m index 3dafdf9..e9b62eb 100644 --- a/kordophone/Bridge/MBIMUpdateQueue.m +++ b/kordophone/Bridge/MBIMUpdateQueue.m @@ -13,9 +13,9 @@ #import "MBIMURLUtilities.h" #import "MBIMPingPongWebSocket.h" -#import -#import -#import +#import "GCDAsyncSocket.h" +#import "HTTPMessage.h" +#import "WebSocket.h" static const NSUInteger kUpdateItemsCullingLength = 100; diff --git a/kordophone/Bridge/Operations/MBIMBridgeOperation.h b/kordophone/Bridge/Operations/MBIMBridgeOperation.h index 2bea21b..595d090 100644 --- a/kordophone/Bridge/Operations/MBIMBridgeOperation.h +++ b/kordophone/Bridge/Operations/MBIMBridgeOperation.h @@ -7,9 +7,9 @@ // #import -#import -#import -#import +#import "HTTPMessage.h" +#import "HTTPResponse.h" +#import "HTTPErrorResponse.h" #import "MBIMJSONDataResponse.h" diff --git a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h index b47d77d..cf7ded9 100644 --- a/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h +++ b/kordophone/Bridge/Operations/Utilities/MBIMDataResponse.h @@ -7,7 +7,7 @@ // #import -#import +#import "HTTPDataResponse.h" NS_ASSUME_NONNULL_BEGIN From f040b9582724b426cd11c71aba97b6d0f18edd07 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 13:57:06 -0700 Subject: [PATCH 64/75] static link categories --- MessagesBridge.xcodeproj/project.pbxproj | 74 ++---------------------- 1 file changed, 6 insertions(+), 68 deletions(-) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 24692bb..2dbfd03 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -14,58 +14,31 @@ 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */; }; 1AAB32B121F82EB7004A2A72 /* MBIMLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AAB32B021F82EB7004A2A72 /* MBIMLogging.m */; }; 1AAB32B421F837BB004A2A72 /* hookAgent.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = CD83E1B5219BF78E00F4CCEA /* hookAgent.sh */; }; - 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE01219EB2AB00E2C237 /* HTTPLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE02219EB2AB00E2C237 /* HTTPMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2D219EB2AC00E2C237 /* WebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE03219EB2AB00E2C237 /* WebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2E219EB2AC00E2C237 /* HTTPAuthenticationRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE04219EB2AB00E2C237 /* HTTPAuthenticationRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2F219EB2AC00E2C237 /* HTTPAsyncFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE06219EB2AB00E2C237 /* HTTPAsyncFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF30219EB2AC00E2C237 /* HTTPErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE07219EB2AB00E2C237 /* HTTPErrorResponse.m */; }; 1ACFCF31219EB2AC00E2C237 /* HTTPDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE08219EB2AB00E2C237 /* HTTPDataResponse.m */; }; - 1ACFCF32219EB2AC00E2C237 /* HTTPRedirectResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE09219EB2AB00E2C237 /* HTTPRedirectResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF33219EB2AC00E2C237 /* HTTPDynamicFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0A219EB2AB00E2C237 /* HTTPDynamicFileResponse.m */; }; 1ACFCF34219EB2AC00E2C237 /* HTTPFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0B219EB2AB00E2C237 /* HTTPFileResponse.m */; }; 1ACFCF35219EB2AC00E2C237 /* HTTPAsyncFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0C219EB2AB00E2C237 /* HTTPAsyncFileResponse.m */; }; 1ACFCF36219EB2AC00E2C237 /* HTTPRedirectResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0D219EB2AB00E2C237 /* HTTPRedirectResponse.m */; }; - 1ACFCF37219EB2AC00E2C237 /* HTTPDataResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE0E219EB2AB00E2C237 /* HTTPDataResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF38219EB2AC00E2C237 /* HTTPErrorResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE0F219EB2AB00E2C237 /* HTTPErrorResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF39219EB2AC00E2C237 /* HTTPFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE10219EB2AB00E2C237 /* HTTPFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF3A219EB2AC00E2C237 /* HTTPDynamicFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE11219EB2AB00E2C237 /* HTTPDynamicFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF3B219EB2AC00E2C237 /* HTTPServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE12219EB2AB00E2C237 /* HTTPServer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF3C219EB2AC00E2C237 /* HTTPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE13219EB2AB00E2C237 /* HTTPMessage.m */; }; 1ACFCF3D219EB2AC00E2C237 /* HTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE14219EB2AB00E2C237 /* HTTPConnection.m */; }; 1ACFCF3E219EB2AC00E2C237 /* WebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE15219EB2AB00E2C237 /* WebSocket.m */; }; - 1ACFCF3F219EB2AC00E2C237 /* HTTPResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE16219EB2AB00E2C237 /* HTTPResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF40219EB2AC00E2C237 /* MultipartFormDataParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE18219EB2AB00E2C237 /* MultipartFormDataParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF41219EB2AC00E2C237 /* MultipartMessageHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE19219EB2AB00E2C237 /* MultipartMessageHeader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF42219EB2AC00E2C237 /* MultipartMessageHeaderField.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1A219EB2AB00E2C237 /* MultipartMessageHeaderField.m */; }; 1ACFCF43219EB2AC00E2C237 /* MultipartFormDataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1B219EB2AB00E2C237 /* MultipartFormDataParser.m */; }; 1ACFCF44219EB2AC00E2C237 /* MultipartMessageHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1C219EB2AB00E2C237 /* MultipartMessageHeader.m */; }; - 1ACFCF45219EB2AC00E2C237 /* MultipartMessageHeaderField.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE1D219EB2AB00E2C237 /* MultipartMessageHeaderField.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF46219EB2AC00E2C237 /* HTTPAuthenticationRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1E219EB2AB00E2C237 /* HTTPAuthenticationRequest.m */; }; 1ACFCF47219EB2AC00E2C237 /* DDNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE20219EB2AB00E2C237 /* DDNumber.m */; }; 1ACFCF48219EB2AC00E2C237 /* DDData.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE21219EB2AB00E2C237 /* DDData.m */; }; - 1ACFCF49219EB2AC00E2C237 /* DDRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE22219EB2AB00E2C237 /* DDRange.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF4A219EB2AC00E2C237 /* DDNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE23219EB2AB00E2C237 /* DDNumber.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF4B219EB2AC00E2C237 /* DDRange.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE24219EB2AB00E2C237 /* DDRange.m */; }; - 1ACFCF4C219EB2AC00E2C237 /* DDData.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE25219EB2AB00E2C237 /* DDData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF4D219EB2AC00E2C237 /* HTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE26219EB2AB00E2C237 /* HTTPServer.m */; }; 1ACFCFCA219EB2AC00E2C237 /* DDTTYLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF09219EB2AC00E2C237 /* DDTTYLogger.m */; }; - 1ACFCFCB219EB2AC00E2C237 /* DDLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0A219EB2AC00E2C237 /* DDLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCFCC219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0B219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFCD219EB2AC00E2C237 /* DDASLLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF0C219EB2AC00E2C237 /* DDASLLogger.m */; }; - 1ACFCFCE219EB2AC00E2C237 /* DDFileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0D219EB2AC00E2C237 /* DDFileLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCFCF219EB2AC00E2C237 /* ContextFilterLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0F219EB2AC00E2C237 /* ContextFilterLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCFD0219EB2AC00E2C237 /* DispatchQueueLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF10219EB2AC00E2C237 /* DispatchQueueLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFD1219EB2AC00E2C237 /* ContextFilterLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF11219EB2AC00E2C237 /* ContextFilterLogFormatter.m */; }; 1ACFCFD2219EB2AC00E2C237 /* DispatchQueueLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF12219EB2AC00E2C237 /* DispatchQueueLogFormatter.m */; }; 1ACFCFD4219EB2AC00E2C237 /* DDLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF14219EB2AC00E2C237 /* DDLog.m */; }; - 1ACFCFD6219EB2AC00E2C237 /* DDTTYLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF16219EB2AC00E2C237 /* DDTTYLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFD7219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF17219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m */; }; 1ACFCFD8219EB2AC00E2C237 /* DDFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF18219EB2AC00E2C237 /* DDFileLogger.m */; }; - 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF19219EB2AC00E2C237 /* DDASLLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDA219EB2AC00E2C237 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */; }; - 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDF219EB31400E2C237 /* libCocoaHTTPServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* libCocoaHTTPServer.a */; }; 1AD8936E21EFD986009B599A /* MBIMUploadAttachmentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AD8936D21EFD986009B599A /* MBIMUploadAttachmentOperation.m */; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; @@ -90,6 +63,9 @@ CD936A35289B47D60093A1AC /* MBIMVersionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A34289B47D50093A1AC /* MBIMVersionOperation.m */; }; CD936A39289B49FC0093A1AC /* MBIMStatusOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A38289B49FC0093A1AC /* MBIMStatusOperation.m */; }; CDA64B472DFCBF3000E9B07E /* MBIMPingPongWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA64B462DFCBF3000E9B07E /* MBIMPingPongWebSocket.m */; }; + CDA64B482DFCC7FA00E9B07E /* DDData.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE21219EB2AB00E2C237 /* DDData.m */; }; + CDA64B492DFCC80100E9B07E /* DDNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE20219EB2AB00E2C237 /* DDNumber.m */; }; + CDA64B4A2DFCC80D00E9B07E /* DDRange.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE24219EB2AB00E2C237 /* DDRange.m */; }; CDDCF78D283F398C0087ABDF /* MBIMDeleteConversationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.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 */; }; @@ -630,40 +606,6 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 1ACFCDDF219EB28A00E2C237 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 1ACFCFCB219EB2AC00E2C237 /* DDLog.h in Headers */, - 1ACFCF40219EB2AC00E2C237 /* MultipartFormDataParser.h in Headers */, - 1ACFCF2F219EB2AC00E2C237 /* HTTPAsyncFileResponse.h in Headers */, - 1ACFCF37219EB2AC00E2C237 /* HTTPDataResponse.h in Headers */, - 1ACFCF45219EB2AC00E2C237 /* MultipartMessageHeaderField.h in Headers */, - 1ACFCF3A219EB2AC00E2C237 /* HTTPDynamicFileResponse.h in Headers */, - 1ACFCFCC219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h in Headers */, - 1ACFCFD6219EB2AC00E2C237 /* DDTTYLogger.h in Headers */, - 1ACFCF4C219EB2AC00E2C237 /* DDData.h in Headers */, - 1ACFCF2D219EB2AC00E2C237 /* WebSocket.h in Headers */, - 1ACFCF49219EB2AC00E2C237 /* DDRange.h in Headers */, - 1ACFCF32219EB2AC00E2C237 /* HTTPRedirectResponse.h in Headers */, - 1ACFCF2E219EB2AC00E2C237 /* HTTPAuthenticationRequest.h in Headers */, - 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */, - 1ACFCF4A219EB2AC00E2C237 /* DDNumber.h in Headers */, - 1ACFCF3F219EB2AC00E2C237 /* HTTPResponse.h in Headers */, - 1ACFCF39219EB2AC00E2C237 /* HTTPFileResponse.h in Headers */, - 1ACFCFCF219EB2AC00E2C237 /* ContextFilterLogFormatter.h in Headers */, - 1ACFCF3B219EB2AC00E2C237 /* HTTPServer.h in Headers */, - 1ACFCF41219EB2AC00E2C237 /* MultipartMessageHeader.h in Headers */, - 1ACFCF38219EB2AC00E2C237 /* HTTPErrorResponse.h in Headers */, - 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */, - 1ACFCFD0219EB2AC00E2C237 /* DispatchQueueLogFormatter.h in Headers */, - 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */, - 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */, - 1ACFCFCE219EB2AC00E2C237 /* DDFileLogger.h in Headers */, - 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; CD83E15D219BE91500F4CCEA /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -790,13 +732,6 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 1ACFCDE0219EB28A00E2C237 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; CD14F189219E2DB400E7DD22 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -885,6 +820,7 @@ 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */, CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */, + CDA64B482DFCC7FA00E9B07E /* DDData.m in Sources */, CDE455A421A5308D0041F5DD /* MBIMFetchAttachmentOperation.m in Sources */, CD2ECEC526953F2A0055E302 /* MBIMAuthToken.m in Sources */, CD83E156219BE10A00F4CCEA /* hooking.m in Sources */, @@ -898,6 +834,7 @@ CD3F62B1297769F2004305D9 /* MBIMURLUtilities.m in Sources */, CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */, CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, + CDA64B4A2DFCC80D00E9B07E /* DDRange.m in Sources */, CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */, CD936A39289B49FC0093A1AC /* MBIMStatusOperation.m in Sources */, CDEFF9FE2CACC7A700063C52 /* MBIMResolveHandleOperation.m in Sources */, @@ -911,6 +848,7 @@ 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */, CD936A32289B353F0093A1AC /* MBIMErrorResponse.m in Sources */, CD2ECEC2269539100055E302 /* MBIMAuthenticateOperation.m in Sources */, + CDA64B492DFCC80100E9B07E /* DDNumber.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 283e6c2218240cffc31726b5f0bf741102ffedb7 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 14:35:26 -0700 Subject: [PATCH 65/75] Revert "static link categories" This reverts commit f040b9582724b426cd11c71aba97b6d0f18edd07. --- MessagesBridge.xcodeproj/project.pbxproj | 74 ++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 6 deletions(-) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 2dbfd03..24692bb 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -14,31 +14,58 @@ 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */; }; 1AAB32B121F82EB7004A2A72 /* MBIMLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AAB32B021F82EB7004A2A72 /* MBIMLogging.m */; }; 1AAB32B421F837BB004A2A72 /* hookAgent.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = CD83E1B5219BF78E00F4CCEA /* hookAgent.sh */; }; + 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE01219EB2AB00E2C237 /* HTTPLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE02219EB2AB00E2C237 /* HTTPMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2D219EB2AC00E2C237 /* WebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE03219EB2AB00E2C237 /* WebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2E219EB2AC00E2C237 /* HTTPAuthenticationRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE04219EB2AB00E2C237 /* HTTPAuthenticationRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF2F219EB2AC00E2C237 /* HTTPAsyncFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE06219EB2AB00E2C237 /* HTTPAsyncFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF30219EB2AC00E2C237 /* HTTPErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE07219EB2AB00E2C237 /* HTTPErrorResponse.m */; }; 1ACFCF31219EB2AC00E2C237 /* HTTPDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE08219EB2AB00E2C237 /* HTTPDataResponse.m */; }; + 1ACFCF32219EB2AC00E2C237 /* HTTPRedirectResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE09219EB2AB00E2C237 /* HTTPRedirectResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF33219EB2AC00E2C237 /* HTTPDynamicFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0A219EB2AB00E2C237 /* HTTPDynamicFileResponse.m */; }; 1ACFCF34219EB2AC00E2C237 /* HTTPFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0B219EB2AB00E2C237 /* HTTPFileResponse.m */; }; 1ACFCF35219EB2AC00E2C237 /* HTTPAsyncFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0C219EB2AB00E2C237 /* HTTPAsyncFileResponse.m */; }; 1ACFCF36219EB2AC00E2C237 /* HTTPRedirectResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0D219EB2AB00E2C237 /* HTTPRedirectResponse.m */; }; + 1ACFCF37219EB2AC00E2C237 /* HTTPDataResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE0E219EB2AB00E2C237 /* HTTPDataResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF38219EB2AC00E2C237 /* HTTPErrorResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE0F219EB2AB00E2C237 /* HTTPErrorResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF39219EB2AC00E2C237 /* HTTPFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE10219EB2AB00E2C237 /* HTTPFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF3A219EB2AC00E2C237 /* HTTPDynamicFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE11219EB2AB00E2C237 /* HTTPDynamicFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF3B219EB2AC00E2C237 /* HTTPServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE12219EB2AB00E2C237 /* HTTPServer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF3C219EB2AC00E2C237 /* HTTPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE13219EB2AB00E2C237 /* HTTPMessage.m */; }; 1ACFCF3D219EB2AC00E2C237 /* HTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE14219EB2AB00E2C237 /* HTTPConnection.m */; }; 1ACFCF3E219EB2AC00E2C237 /* WebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE15219EB2AB00E2C237 /* WebSocket.m */; }; + 1ACFCF3F219EB2AC00E2C237 /* HTTPResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE16219EB2AB00E2C237 /* HTTPResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF40219EB2AC00E2C237 /* MultipartFormDataParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE18219EB2AB00E2C237 /* MultipartFormDataParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF41219EB2AC00E2C237 /* MultipartMessageHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE19219EB2AB00E2C237 /* MultipartMessageHeader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF42219EB2AC00E2C237 /* MultipartMessageHeaderField.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1A219EB2AB00E2C237 /* MultipartMessageHeaderField.m */; }; 1ACFCF43219EB2AC00E2C237 /* MultipartFormDataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1B219EB2AB00E2C237 /* MultipartFormDataParser.m */; }; 1ACFCF44219EB2AC00E2C237 /* MultipartMessageHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1C219EB2AB00E2C237 /* MultipartMessageHeader.m */; }; + 1ACFCF45219EB2AC00E2C237 /* MultipartMessageHeaderField.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE1D219EB2AB00E2C237 /* MultipartMessageHeaderField.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF46219EB2AC00E2C237 /* HTTPAuthenticationRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1E219EB2AB00E2C237 /* HTTPAuthenticationRequest.m */; }; 1ACFCF47219EB2AC00E2C237 /* DDNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE20219EB2AB00E2C237 /* DDNumber.m */; }; 1ACFCF48219EB2AC00E2C237 /* DDData.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE21219EB2AB00E2C237 /* DDData.m */; }; + 1ACFCF49219EB2AC00E2C237 /* DDRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE22219EB2AB00E2C237 /* DDRange.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCF4A219EB2AC00E2C237 /* DDNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE23219EB2AB00E2C237 /* DDNumber.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF4B219EB2AC00E2C237 /* DDRange.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE24219EB2AB00E2C237 /* DDRange.m */; }; + 1ACFCF4C219EB2AC00E2C237 /* DDData.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE25219EB2AB00E2C237 /* DDData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF4D219EB2AC00E2C237 /* HTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE26219EB2AB00E2C237 /* HTTPServer.m */; }; 1ACFCFCA219EB2AC00E2C237 /* DDTTYLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF09219EB2AC00E2C237 /* DDTTYLogger.m */; }; + 1ACFCFCB219EB2AC00E2C237 /* DDLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0A219EB2AC00E2C237 /* DDLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFCC219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0B219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFCD219EB2AC00E2C237 /* DDASLLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF0C219EB2AC00E2C237 /* DDASLLogger.m */; }; + 1ACFCFCE219EB2AC00E2C237 /* DDFileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0D219EB2AC00E2C237 /* DDFileLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFCF219EB2AC00E2C237 /* ContextFilterLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0F219EB2AC00E2C237 /* ContextFilterLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1ACFCFD0219EB2AC00E2C237 /* DispatchQueueLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF10219EB2AC00E2C237 /* DispatchQueueLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFD1219EB2AC00E2C237 /* ContextFilterLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF11219EB2AC00E2C237 /* ContextFilterLogFormatter.m */; }; 1ACFCFD2219EB2AC00E2C237 /* DispatchQueueLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF12219EB2AC00E2C237 /* DispatchQueueLogFormatter.m */; }; 1ACFCFD4219EB2AC00E2C237 /* DDLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF14219EB2AC00E2C237 /* DDLog.m */; }; + 1ACFCFD6219EB2AC00E2C237 /* DDTTYLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF16219EB2AC00E2C237 /* DDTTYLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFD7219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF17219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m */; }; 1ACFCFD8219EB2AC00E2C237 /* DDFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF18219EB2AC00E2C237 /* DDFileLogger.m */; }; + 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF19219EB2AC00E2C237 /* DDASLLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDA219EB2AC00E2C237 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */; }; + 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDF219EB31400E2C237 /* libCocoaHTTPServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* libCocoaHTTPServer.a */; }; 1AD8936E21EFD986009B599A /* MBIMUploadAttachmentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AD8936D21EFD986009B599A /* MBIMUploadAttachmentOperation.m */; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; @@ -63,9 +90,6 @@ CD936A35289B47D60093A1AC /* MBIMVersionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A34289B47D50093A1AC /* MBIMVersionOperation.m */; }; CD936A39289B49FC0093A1AC /* MBIMStatusOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CD936A38289B49FC0093A1AC /* MBIMStatusOperation.m */; }; CDA64B472DFCBF3000E9B07E /* MBIMPingPongWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA64B462DFCBF3000E9B07E /* MBIMPingPongWebSocket.m */; }; - CDA64B482DFCC7FA00E9B07E /* DDData.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE21219EB2AB00E2C237 /* DDData.m */; }; - CDA64B492DFCC80100E9B07E /* DDNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE20219EB2AB00E2C237 /* DDNumber.m */; }; - CDA64B4A2DFCC80D00E9B07E /* DDRange.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE24219EB2AB00E2C237 /* DDRange.m */; }; CDDCF78D283F398C0087ABDF /* MBIMDeleteConversationOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CDDCF78C283F398C0087ABDF /* MBIMDeleteConversationOperation.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 */; }; @@ -606,6 +630,40 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 1ACFCDDF219EB28A00E2C237 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 1ACFCFCB219EB2AC00E2C237 /* DDLog.h in Headers */, + 1ACFCF40219EB2AC00E2C237 /* MultipartFormDataParser.h in Headers */, + 1ACFCF2F219EB2AC00E2C237 /* HTTPAsyncFileResponse.h in Headers */, + 1ACFCF37219EB2AC00E2C237 /* HTTPDataResponse.h in Headers */, + 1ACFCF45219EB2AC00E2C237 /* MultipartMessageHeaderField.h in Headers */, + 1ACFCF3A219EB2AC00E2C237 /* HTTPDynamicFileResponse.h in Headers */, + 1ACFCFCC219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h in Headers */, + 1ACFCFD6219EB2AC00E2C237 /* DDTTYLogger.h in Headers */, + 1ACFCF4C219EB2AC00E2C237 /* DDData.h in Headers */, + 1ACFCF2D219EB2AC00E2C237 /* WebSocket.h in Headers */, + 1ACFCF49219EB2AC00E2C237 /* DDRange.h in Headers */, + 1ACFCF32219EB2AC00E2C237 /* HTTPRedirectResponse.h in Headers */, + 1ACFCF2E219EB2AC00E2C237 /* HTTPAuthenticationRequest.h in Headers */, + 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */, + 1ACFCF4A219EB2AC00E2C237 /* DDNumber.h in Headers */, + 1ACFCF3F219EB2AC00E2C237 /* HTTPResponse.h in Headers */, + 1ACFCF39219EB2AC00E2C237 /* HTTPFileResponse.h in Headers */, + 1ACFCFCF219EB2AC00E2C237 /* ContextFilterLogFormatter.h in Headers */, + 1ACFCF3B219EB2AC00E2C237 /* HTTPServer.h in Headers */, + 1ACFCF41219EB2AC00E2C237 /* MultipartMessageHeader.h in Headers */, + 1ACFCF38219EB2AC00E2C237 /* HTTPErrorResponse.h in Headers */, + 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */, + 1ACFCFD0219EB2AC00E2C237 /* DispatchQueueLogFormatter.h in Headers */, + 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */, + 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */, + 1ACFCFCE219EB2AC00E2C237 /* DDFileLogger.h in Headers */, + 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD83E15D219BE91500F4CCEA /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -732,6 +790,13 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 1ACFCDE0219EB28A00E2C237 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; CD14F189219E2DB400E7DD22 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -820,7 +885,6 @@ 1AA43E91219EBC2C00EDF1A7 /* MBIMHTTPConnection.m in Sources */, CDF62339219A8A5600690038 /* MBIMBridge.h in Sources */, 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */, - CDA64B482DFCC7FA00E9B07E /* DDData.m in Sources */, CDE455A421A5308D0041F5DD /* MBIMFetchAttachmentOperation.m in Sources */, CD2ECEC526953F2A0055E302 /* MBIMAuthToken.m in Sources */, CD83E156219BE10A00F4CCEA /* hooking.m in Sources */, @@ -834,7 +898,6 @@ CD3F62B1297769F2004305D9 /* MBIMURLUtilities.m in Sources */, CD14F1A4219FF22700E7DD22 /* IMMessageItem+Encoded.m in Sources */, CD602062219B68950024D9C5 /* MBIMSendMessageOperation.m in Sources */, - CDA64B4A2DFCC80D00E9B07E /* DDRange.m in Sources */, CD14F1A1219FE7D600E7DD22 /* MBIMUpdatePollOperation.m in Sources */, CD936A39289B49FC0093A1AC /* MBIMStatusOperation.m in Sources */, CDEFF9FE2CACC7A700063C52 /* MBIMResolveHandleOperation.m in Sources */, @@ -848,7 +911,6 @@ 1AA43E8F219EBB2D00EDF1A7 /* MBIMJSONDataResponse.m in Sources */, CD936A32289B353F0093A1AC /* MBIMErrorResponse.m in Sources */, CD2ECEC2269539100055E302 /* MBIMAuthenticateOperation.m in Sources */, - CDA64B492DFCC80100E9B07E /* DDNumber.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From e97edc10b7134e9aaa6847ccad0fcfcca6a1cdb9 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 14:36:00 -0700 Subject: [PATCH 66/75] Apparently need -ObjC for loading categories from a static library. --- MessagesBridge.xcodeproj/project.pbxproj | 70 +----------------------- 1 file changed, 2 insertions(+), 68 deletions(-) diff --git a/MessagesBridge.xcodeproj/project.pbxproj b/MessagesBridge.xcodeproj/project.pbxproj index 24692bb..b43992c 100644 --- a/MessagesBridge.xcodeproj/project.pbxproj +++ b/MessagesBridge.xcodeproj/project.pbxproj @@ -14,58 +14,31 @@ 1AA43E95219EC38E00EDF1A7 /* MBIMHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AA43E94219EC38E00EDF1A7 /* MBIMHTTPUtilities.m */; }; 1AAB32B121F82EB7004A2A72 /* MBIMLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AAB32B021F82EB7004A2A72 /* MBIMLogging.m */; }; 1AAB32B421F837BB004A2A72 /* hookAgent.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = CD83E1B5219BF78E00F4CCEA /* hookAgent.sh */; }; - 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE00219EB2AB00E2C237 /* HTTPConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE01219EB2AB00E2C237 /* HTTPLogging.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE02219EB2AB00E2C237 /* HTTPMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2D219EB2AC00E2C237 /* WebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE03219EB2AB00E2C237 /* WebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2E219EB2AC00E2C237 /* HTTPAuthenticationRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE04219EB2AB00E2C237 /* HTTPAuthenticationRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF2F219EB2AC00E2C237 /* HTTPAsyncFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE06219EB2AB00E2C237 /* HTTPAsyncFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF30219EB2AC00E2C237 /* HTTPErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE07219EB2AB00E2C237 /* HTTPErrorResponse.m */; }; 1ACFCF31219EB2AC00E2C237 /* HTTPDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE08219EB2AB00E2C237 /* HTTPDataResponse.m */; }; - 1ACFCF32219EB2AC00E2C237 /* HTTPRedirectResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE09219EB2AB00E2C237 /* HTTPRedirectResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF33219EB2AC00E2C237 /* HTTPDynamicFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0A219EB2AB00E2C237 /* HTTPDynamicFileResponse.m */; }; 1ACFCF34219EB2AC00E2C237 /* HTTPFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0B219EB2AB00E2C237 /* HTTPFileResponse.m */; }; 1ACFCF35219EB2AC00E2C237 /* HTTPAsyncFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0C219EB2AB00E2C237 /* HTTPAsyncFileResponse.m */; }; 1ACFCF36219EB2AC00E2C237 /* HTTPRedirectResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE0D219EB2AB00E2C237 /* HTTPRedirectResponse.m */; }; - 1ACFCF37219EB2AC00E2C237 /* HTTPDataResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE0E219EB2AB00E2C237 /* HTTPDataResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF38219EB2AC00E2C237 /* HTTPErrorResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE0F219EB2AB00E2C237 /* HTTPErrorResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF39219EB2AC00E2C237 /* HTTPFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE10219EB2AB00E2C237 /* HTTPFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF3A219EB2AC00E2C237 /* HTTPDynamicFileResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE11219EB2AB00E2C237 /* HTTPDynamicFileResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF3B219EB2AC00E2C237 /* HTTPServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE12219EB2AB00E2C237 /* HTTPServer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF3C219EB2AC00E2C237 /* HTTPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE13219EB2AB00E2C237 /* HTTPMessage.m */; }; 1ACFCF3D219EB2AC00E2C237 /* HTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE14219EB2AB00E2C237 /* HTTPConnection.m */; }; 1ACFCF3E219EB2AC00E2C237 /* WebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE15219EB2AB00E2C237 /* WebSocket.m */; }; - 1ACFCF3F219EB2AC00E2C237 /* HTTPResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE16219EB2AB00E2C237 /* HTTPResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF40219EB2AC00E2C237 /* MultipartFormDataParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE18219EB2AB00E2C237 /* MultipartFormDataParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF41219EB2AC00E2C237 /* MultipartMessageHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE19219EB2AB00E2C237 /* MultipartMessageHeader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF42219EB2AC00E2C237 /* MultipartMessageHeaderField.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1A219EB2AB00E2C237 /* MultipartMessageHeaderField.m */; }; 1ACFCF43219EB2AC00E2C237 /* MultipartFormDataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1B219EB2AB00E2C237 /* MultipartFormDataParser.m */; }; 1ACFCF44219EB2AC00E2C237 /* MultipartMessageHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1C219EB2AB00E2C237 /* MultipartMessageHeader.m */; }; - 1ACFCF45219EB2AC00E2C237 /* MultipartMessageHeaderField.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE1D219EB2AB00E2C237 /* MultipartMessageHeaderField.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF46219EB2AC00E2C237 /* HTTPAuthenticationRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE1E219EB2AB00E2C237 /* HTTPAuthenticationRequest.m */; }; 1ACFCF47219EB2AC00E2C237 /* DDNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE20219EB2AB00E2C237 /* DDNumber.m */; }; 1ACFCF48219EB2AC00E2C237 /* DDData.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE21219EB2AB00E2C237 /* DDData.m */; }; - 1ACFCF49219EB2AC00E2C237 /* DDRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE22219EB2AB00E2C237 /* DDRange.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCF4A219EB2AC00E2C237 /* DDNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE23219EB2AB00E2C237 /* DDNumber.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF4B219EB2AC00E2C237 /* DDRange.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE24219EB2AB00E2C237 /* DDRange.m */; }; - 1ACFCF4C219EB2AC00E2C237 /* DDData.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCE25219EB2AB00E2C237 /* DDData.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCF4D219EB2AC00E2C237 /* HTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCE26219EB2AB00E2C237 /* HTTPServer.m */; }; 1ACFCFCA219EB2AC00E2C237 /* DDTTYLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF09219EB2AC00E2C237 /* DDTTYLogger.m */; }; - 1ACFCFCB219EB2AC00E2C237 /* DDLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0A219EB2AC00E2C237 /* DDLog.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCFCC219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0B219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFCD219EB2AC00E2C237 /* DDASLLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF0C219EB2AC00E2C237 /* DDASLLogger.m */; }; - 1ACFCFCE219EB2AC00E2C237 /* DDFileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0D219EB2AC00E2C237 /* DDFileLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCFCF219EB2AC00E2C237 /* ContextFilterLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF0F219EB2AC00E2C237 /* ContextFilterLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1ACFCFD0219EB2AC00E2C237 /* DispatchQueueLogFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF10219EB2AC00E2C237 /* DispatchQueueLogFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFD1219EB2AC00E2C237 /* ContextFilterLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF11219EB2AC00E2C237 /* ContextFilterLogFormatter.m */; }; 1ACFCFD2219EB2AC00E2C237 /* DispatchQueueLogFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF12219EB2AC00E2C237 /* DispatchQueueLogFormatter.m */; }; 1ACFCFD4219EB2AC00E2C237 /* DDLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF14219EB2AC00E2C237 /* DDLog.m */; }; - 1ACFCFD6219EB2AC00E2C237 /* DDTTYLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF16219EB2AC00E2C237 /* DDTTYLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFD7219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF17219EB2AC00E2C237 /* DDAbstractDatabaseLogger.m */; }; 1ACFCFD8219EB2AC00E2C237 /* DDFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF18219EB2AC00E2C237 /* DDFileLogger.m */; }; - 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF19219EB2AC00E2C237 /* DDASLLogger.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDA219EB2AC00E2C237 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 1ACFCF1B219EB2AC00E2C237 /* GCDAsyncSocket.m */; }; - 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 1ACFCF1D219EB2AC00E2C237 /* GCDAsyncSocket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1ACFCFDF219EB31400E2C237 /* libCocoaHTTPServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1ACFCDE2219EB28A00E2C237 /* libCocoaHTTPServer.a */; }; 1AD8936E21EFD986009B599A /* MBIMUploadAttachmentOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1AD8936D21EFD986009B599A /* MBIMUploadAttachmentOperation.m */; }; CD14F18E219E2DB400E7DD22 /* CryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CD14F18D219E2DB400E7DD22 /* CryptoTests.m */; }; @@ -630,40 +603,6 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 1ACFCDDF219EB28A00E2C237 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 1ACFCFCB219EB2AC00E2C237 /* DDLog.h in Headers */, - 1ACFCF40219EB2AC00E2C237 /* MultipartFormDataParser.h in Headers */, - 1ACFCF2F219EB2AC00E2C237 /* HTTPAsyncFileResponse.h in Headers */, - 1ACFCF37219EB2AC00E2C237 /* HTTPDataResponse.h in Headers */, - 1ACFCF45219EB2AC00E2C237 /* MultipartMessageHeaderField.h in Headers */, - 1ACFCF3A219EB2AC00E2C237 /* HTTPDynamicFileResponse.h in Headers */, - 1ACFCFCC219EB2AC00E2C237 /* DDAbstractDatabaseLogger.h in Headers */, - 1ACFCFD6219EB2AC00E2C237 /* DDTTYLogger.h in Headers */, - 1ACFCF4C219EB2AC00E2C237 /* DDData.h in Headers */, - 1ACFCF2D219EB2AC00E2C237 /* WebSocket.h in Headers */, - 1ACFCF49219EB2AC00E2C237 /* DDRange.h in Headers */, - 1ACFCF32219EB2AC00E2C237 /* HTTPRedirectResponse.h in Headers */, - 1ACFCF2E219EB2AC00E2C237 /* HTTPAuthenticationRequest.h in Headers */, - 1ACFCFDC219EB2AC00E2C237 /* GCDAsyncSocket.h in Headers */, - 1ACFCF4A219EB2AC00E2C237 /* DDNumber.h in Headers */, - 1ACFCF3F219EB2AC00E2C237 /* HTTPResponse.h in Headers */, - 1ACFCF39219EB2AC00E2C237 /* HTTPFileResponse.h in Headers */, - 1ACFCFCF219EB2AC00E2C237 /* ContextFilterLogFormatter.h in Headers */, - 1ACFCF3B219EB2AC00E2C237 /* HTTPServer.h in Headers */, - 1ACFCF41219EB2AC00E2C237 /* MultipartMessageHeader.h in Headers */, - 1ACFCF38219EB2AC00E2C237 /* HTTPErrorResponse.h in Headers */, - 1ACFCF2B219EB2AC00E2C237 /* HTTPLogging.h in Headers */, - 1ACFCFD0219EB2AC00E2C237 /* DispatchQueueLogFormatter.h in Headers */, - 1ACFCF2C219EB2AC00E2C237 /* HTTPMessage.h in Headers */, - 1ACFCFD9219EB2AC00E2C237 /* DDASLLogger.h in Headers */, - 1ACFCFCE219EB2AC00E2C237 /* DDFileLogger.h in Headers */, - 1ACFCF2A219EB2AC00E2C237 /* HTTPConnection.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; CD83E15D219BE91500F4CCEA /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -790,13 +729,6 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 1ACFCDE0219EB28A00E2C237 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; CD14F189219E2DB400E7DD22 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1148,6 +1080,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SYSTEM_FRAMEWORK_SEARCH_PATHS = ( @@ -1164,6 +1097,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_PREFIX_HEADER = kordophone/KPServer.pch; + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; SYSTEM_FRAMEWORK_SEARCH_PATHS = ( From 1dc6f0ec1b4f3758053733ca14705bd3f133c71c Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 14:39:24 -0700 Subject: [PATCH 67/75] add logging --- kordophone/Bridge/MBIMPingPongWebSocket.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.m b/kordophone/Bridge/MBIMPingPongWebSocket.m index 223edfc..1802c3b 100644 --- a/kordophone/Bridge/MBIMPingPongWebSocket.m +++ b/kordophone/Bridge/MBIMPingPongWebSocket.m @@ -104,6 +104,8 @@ - (void)socket:(GCDAsyncSocket *)asyncSocket didReadData:(NSData *)data withTag:(long)tag { NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; // sheesh. + NSLog(@"tag: %ld, nextOpCode: %ld", tag, nextOpCode); + // Handle our custom ping/pong tags if (tag == TAG_PING_PAYLOAD) { // We've read the ping payload, now send the pong response From a9c2f5d93e1a5927e7033440395e4ea4d85b6ec3 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 14:44:03 -0700 Subject: [PATCH 68/75] pingpong: need to handle the first part of the frame first --- kordophone/Bridge/MBIMPingPongWebSocket.m | 130 +++++++--------------- 1 file changed, 38 insertions(+), 92 deletions(-) diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.m b/kordophone/Bridge/MBIMPingPongWebSocket.m index 1802c3b..3e36fae 100644 --- a/kordophone/Bridge/MBIMPingPongWebSocket.m +++ b/kordophone/Bridge/MBIMPingPongWebSocket.m @@ -101,116 +101,62 @@ #pragma mark - Override AsyncSocket Delegate -- (void)socket:(GCDAsyncSocket *)asyncSocket didReadData:(NSData *)data withTag:(long)tag { +- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { + BOOL nextFrameMasked = [[self valueForKey:@"nextFrameMasked"] boolValue]; NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; // sheesh. - NSLog(@"tag: %ld, nextOpCode: %ld", tag, nextOpCode); + NSLog(@"tag: %ld, nextOpCode: %lu", tag, (unsigned long)nextOpCode); - // Handle our custom ping/pong tags + // Handle our custom ping payload tag if (tag == TAG_PING_PAYLOAD) { // We've read the ping payload, now send the pong response - [self sendPongWithPayload:data socket:asyncSocket]; + NSData *payload = data; + + // If the frame was masked, we need to unmask it + if (nextFrameMasked && pendingPingPayload) { + NSMutableData *unmaskedPayload = [data mutableCopy]; + UInt8 *payloadBytes = [unmaskedPayload mutableBytes]; + UInt8 *maskBytes = (UInt8 *)[pendingPingPayload bytes]; + + for (NSUInteger i = 0; i < [data length]; i++) { + payloadBytes[i] ^= maskBytes[i % 4]; + } + payload = [unmaskedPayload copy]; + } + + [self sendPongWithPayload:payload socket:sock]; // Continue reading the next frame [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX]; return; } - if (tag == TAG_PONG_SENT) { - // Pong was sent successfully, continue normal operation - return; - } + // Let the parent handle the frame parsing logic first + [super socket:sock didReadData:data withTag:tag]; - // For TAG_PAYLOAD_PREFIX, we need to intercept and handle ping frames - if (tag == TAG_PAYLOAD_PREFIX) { - UInt8 *pFrame = (UInt8 *)[data bytes]; - UInt8 frame = *pFrame; - - // Check if this is a valid WebSocket frame - if (![self isValidWebSocketFrame:frame]) { - [self didClose]; - return; - } - - NSUInteger opcode = frame & 0x0F; - - // Handle ping frames specially - if (opcode == WS_OP_PING) { - // Read the payload length byte next - [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH]; - return; - } - - // Handle pong frames (just log and continue) - if (opcode == WS_OP_PONG) { - NSLog(@"Received pong frame"); - // Read the payload length byte next, but we'll ignore pong payloads - [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH]; - return; - } - } - - // For TAG_PAYLOAD_LENGTH, check if we're handling a ping - if (tag == TAG_PAYLOAD_LENGTH) { - UInt8 frame = *(UInt8 *)[data bytes]; - BOOL masked = (frame & 0x80) != 0; - NSUInteger length = frame & 0x7F; - - // If we were processing a ping frame, handle the payload reading + // After the parent has processed, check if we need to handle ping/pong + if (tag == TAG_MSG_WITH_LENGTH) { + // The parent just finished reading a complete message if (nextOpCode == WS_OP_PING) { - if (length <= 125) { - if (masked) { - // Read masking key first, then payload - [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; - } - // Read ping payload - [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; - return; - } - else if (length == 126) { - [asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16]; - return; - } - else { - [asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64]; - return; - } + // This was a ping frame - the parent would have tried to process it as text + // We need to send a pong response + NSData *payload = data; + + // If the frame was masked, unmask it (parent already did this) + [self sendPongWithPayload:payload socket:sock]; + + // Don't call didReceiveMessage for ping frames + return; } - - // If we were processing a pong frame, just skip it - if (nextOpCode == WS_OP_PONG) { - if (length <= 125) { - if (masked) { - [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; - } - // Skip pong payload and continue to next frame - [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX]; - return; - } - else if (length == 126) { - [asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16]; - return; - } - else { - [asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64]; - return; - } + else if (nextOpCode == WS_OP_PONG) { + // This was a pong frame - just log it and continue + NSLog(@"Received pong frame with payload length: %lu", (unsigned long)[data length]); + return; } } - - // Handle masking key reading for ping frames - if (tag == TAG_MSG_MASKING_KEY && nextOpCode == WS_OP_PING) { - // Store the masking key and read the actual payload - pendingPingPayload = [data copy]; - // The payload length was already determined, read it - // Note: This is a simplified version - you'd need to track the actual length - return; - } - - // For all other cases, call the parent implementation - [super socket:asyncSocket didReadData:data withTag:tag]; } + #pragma mark - Helper Methods // Expose the isValidWebSocketFrame method since it's private in the parent From e1ec2370533e5ff6b0b9b07e7bb15cfc1b9a5247 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 14:47:47 -0700 Subject: [PATCH 69/75] now actually handle pong --- kordophone/Bridge/MBIMPingPongWebSocket.m | 83 ++++++++++++++++------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.m b/kordophone/Bridge/MBIMPingPongWebSocket.m index 3e36fae..b36fba8 100644 --- a/kordophone/Bridge/MBIMPingPongWebSocket.m +++ b/kordophone/Bridge/MBIMPingPongWebSocket.m @@ -102,8 +102,10 @@ #pragma mark - Override AsyncSocket Delegate - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { + // xxx: sheesh: really need to get off of CococaHTTPServer. + NSData *maskingKey = [self valueForKey:@"maskingKey"]; BOOL nextFrameMasked = [[self valueForKey:@"nextFrameMasked"] boolValue]; - NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; // sheesh. + NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; NSLog(@"tag: %ld, nextOpCode: %lu", tag, (unsigned long)nextOpCode); @@ -113,10 +115,10 @@ NSData *payload = data; // If the frame was masked, we need to unmask it - if (nextFrameMasked && pendingPingPayload) { + if (nextFrameMasked && maskingKey) { NSMutableData *unmaskedPayload = [data mutableCopy]; UInt8 *payloadBytes = [unmaskedPayload mutableBytes]; - UInt8 *maskBytes = (UInt8 *)[pendingPingPayload bytes]; + UInt8 *maskBytes = (UInt8 *)[maskingKey bytes]; for (NSUInteger i = 0; i < [data length]; i++) { payloadBytes[i] ^= maskBytes[i % 4]; @@ -131,29 +133,60 @@ return; } - // Let the parent handle the frame parsing logic first - [super socket:sock didReadData:data withTag:tag]; - - // After the parent has processed, check if we need to handle ping/pong - if (tag == TAG_MSG_WITH_LENGTH) { - // The parent just finished reading a complete message - if (nextOpCode == WS_OP_PING) { - // This was a ping frame - the parent would have tried to process it as text - // We need to send a pong response - NSData *payload = data; - - // If the frame was masked, unmask it (parent already did this) - [self sendPongWithPayload:payload socket:sock]; - - // Don't call didReceiveMessage for ping frames - return; - } - else if (nextOpCode == WS_OP_PONG) { - // This was a pong frame - just log it and continue - NSLog(@"Received pong frame with payload length: %lu", (unsigned long)[data length]); - return; - } + // Intercept after masking key is read for ping/pong frames + if (tag == TAG_MSG_MASKING_KEY && (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG)) { + // Store the masking key + maskingKey = [data copy]; + // We need to determine the payload length and read it + // The parent class should have stored this somewhere, but we'll need to track it + // For now, let's assume short payload and read what was scheduled + return; } + + // Intercept the payload length phase for ping/pong frames + if (tag == TAG_PAYLOAD_LENGTH && (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG)) { + UInt8 frame = *(UInt8 *)[data bytes]; + BOOL masked = (frame & 0x80) != 0; + NSUInteger length = frame & 0x7F; + nextFrameMasked = masked; + + if (length <= 125) { + if (nextFrameMasked) { + [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; + } + [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; + } + else if (length == 126) { + [asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16]; + } + else { + [asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64]; + } + return; + } + + // Handle extended length for ping/pong + if ((tag == TAG_PAYLOAD_LENGTH16 || tag == TAG_PAYLOAD_LENGTH64) && (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG)) { + NSUInteger length = 0; + if (tag == TAG_PAYLOAD_LENGTH16) { + UInt8 *pFrame = (UInt8 *)[data bytes]; + length = ((NSUInteger)pFrame[0] << 8) | (NSUInteger)pFrame[1]; + } else { + // For 64-bit length, this is complex - for now just close + [self didClose]; + return; + } + + if (nextFrameMasked) { + [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; + } + [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; + return; + } + + // For all other cases, call the parent implementation + [super socket:sock didReadData:data withTag:tag]; + } From d7064351038b1cca5bb5dfc5f567a9485fbe502d Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 14:50:13 -0700 Subject: [PATCH 70/75] pingpong prevent superclass from handling rest of ping frame --- kordophone/Bridge/MBIMPingPongWebSocket.m | 81 ++++++++++++----------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.m b/kordophone/Bridge/MBIMPingPongWebSocket.m index b36fba8..02004c3 100644 --- a/kordophone/Bridge/MBIMPingPongWebSocket.m +++ b/kordophone/Bridge/MBIMPingPongWebSocket.m @@ -126,6 +126,7 @@ payload = [unmaskedPayload copy]; } + NSLog(@"Sending pong response to ping with payload length: %lu", (unsigned long)[payload length]); [self sendPongWithPayload:payload socket:sock]; // Continue reading the next frame @@ -133,60 +134,64 @@ return; } - // Intercept after masking key is read for ping/pong frames - if (tag == TAG_MSG_MASKING_KEY && (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG)) { - // Store the masking key - maskingKey = [data copy]; - // We need to determine the payload length and read it - // The parent class should have stored this somewhere, but we'll need to track it - // For now, let's assume short payload and read what was scheduled + // Let parent handle TAG_PAYLOAD_PREFIX first to set nextOpCode + if (tag == TAG_PAYLOAD_PREFIX) { + [super socket:sock didReadData:data withTag:tag]; return; } - // Intercept the payload length phase for ping/pong frames - if (tag == TAG_PAYLOAD_LENGTH && (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG)) { - UInt8 frame = *(UInt8 *)[data bytes]; - BOOL masked = (frame & 0x80) != 0; - NSUInteger length = frame & 0x7F; - nextFrameMasked = masked; + // Now intercept ping/pong handling after nextOpCode is set + if (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG) { + if (tag == TAG_PAYLOAD_LENGTH) { + UInt8 frame = *(UInt8 *)[data bytes]; + BOOL masked = (frame & 0x80) != 0; + NSUInteger length = frame & 0x7F; + nextFrameMasked = masked; + + NSLog(@"Processing ping/pong frame, masked: %d, length: %lu", masked, (unsigned long)length); + + if (length <= 125) { + if (nextFrameMasked) { + [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; + } + [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; + } + else if (length == 126) { + [asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16]; + } + else { + [asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64]; + } + return; + } - if (length <= 125) { + if (tag == TAG_MSG_MASKING_KEY) { + // Store the masking key + maskingKey = [data copy]; + NSLog(@"Stored masking key for ping/pong frame"); + return; + } + + if (tag == TAG_PAYLOAD_LENGTH16) { + UInt8 *pFrame = (UInt8 *)[data bytes]; + NSUInteger length = ((NSUInteger)pFrame[0] << 8) | (NSUInteger)pFrame[1]; + if (nextFrameMasked) { [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; } [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; - } - else if (length == 126) { - [asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16]; - } - else { - [asyncSocket readDataToLength:8 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH64]; - } - return; - } - - // Handle extended length for ping/pong - if ((tag == TAG_PAYLOAD_LENGTH16 || tag == TAG_PAYLOAD_LENGTH64) && (nextOpCode == WS_OP_PING || nextOpCode == WS_OP_PONG)) { - NSUInteger length = 0; - if (tag == TAG_PAYLOAD_LENGTH16) { - UInt8 *pFrame = (UInt8 *)[data bytes]; - length = ((NSUInteger)pFrame[0] << 8) | (NSUInteger)pFrame[1]; - } else { - // For 64-bit length, this is complex - for now just close - [self didClose]; return; } - if (nextFrameMasked) { - [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; + if (tag == TAG_PAYLOAD_LENGTH64) { + // For 64-bit length, this is too complex for ping frames - just close + [self didClose]; + return; } - [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; - return; } // For all other cases, call the parent implementation [super socket:sock didReadData:data withTag:tag]; - } From 3f03937ca46d162dbd3670fb4a346a301eccfb9b Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 14:54:51 -0700 Subject: [PATCH 71/75] guessing at this point --- kordophone/Bridge/MBIMPingPongWebSocket.m | 52 +++++++++++------------ 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.m b/kordophone/Bridge/MBIMPingPongWebSocket.m index 02004c3..244fe65 100644 --- a/kordophone/Bridge/MBIMPingPongWebSocket.m +++ b/kordophone/Bridge/MBIMPingPongWebSocket.m @@ -43,7 +43,7 @@ @implementation MBIMPingPongWebSocket { - NSData *pendingPingPayload; + NSUInteger currentPayloadLength; } #pragma mark - Ping/Pong Frame Construction @@ -90,7 +90,7 @@ return [frame copy]; } -- (void)sendPongWithPayload:(NSData *)payload socket:(GCDAsyncSocket *)asyncSocket { +- (void)sendPongWithPayload:(NSData *)payload { NSData *pongFrame = [self createPongFrameWithPayload:payload]; // Send the pong frame directly through the socket @@ -101,12 +101,12 @@ #pragma mark - Override AsyncSocket Delegate -- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { +- (void)socket:(GCDAsyncSocket *)asyncSocket didReadData:(NSData *)data withTag:(long)tag { // xxx: sheesh: really need to get off of CococaHTTPServer. NSData *maskingKey = [self valueForKey:@"maskingKey"]; BOOL nextFrameMasked = [[self valueForKey:@"nextFrameMasked"] boolValue]; NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; - + NSLog(@"tag: %ld, nextOpCode: %lu", tag, (unsigned long)nextOpCode); // Handle our custom ping payload tag @@ -127,7 +127,7 @@ } NSLog(@"Sending pong response to ping with payload length: %lu", (unsigned long)[payload length]); - [self sendPongWithPayload:payload socket:sock]; + [self sendPongWithPayload:payload]; // Continue reading the next frame [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX]; @@ -136,7 +136,7 @@ // Let parent handle TAG_PAYLOAD_PREFIX first to set nextOpCode if (tag == TAG_PAYLOAD_PREFIX) { - [super socket:sock didReadData:data withTag:tag]; + [super socket:asyncSocket didReadData:data withTag:tag]; return; } @@ -147,14 +147,21 @@ BOOL masked = (frame & 0x80) != 0; NSUInteger length = frame & 0x7F; nextFrameMasked = masked; + currentPayloadLength = length; NSLog(@"Processing ping/pong frame, masked: %d, length: %lu", masked, (unsigned long)length); if (length <= 125) { if (nextFrameMasked) { [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; + } else if (length > 0) { + [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; + } else { + // Empty payload, no masking - handle immediately + NSLog(@"Handling empty unmasked ping payload"); + [self sendPongWithPayload:[NSData data]]; + [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX]; } - [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; } else if (length == 126) { [asyncSocket readDataToLength:2 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_LENGTH16]; @@ -169,6 +176,16 @@ // Store the masking key maskingKey = [data copy]; NSLog(@"Stored masking key for ping/pong frame"); + + // Now read the payload (or handle empty payload) + if (currentPayloadLength > 0) { + [asyncSocket readDataToLength:currentPayloadLength withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; + } else { + // Empty payload - send pong immediately + NSLog(@"Sending pong for empty masked ping payload"); + [self sendPongWithPayload:[NSData data]]; + [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX]; + } return; } @@ -191,10 +208,9 @@ } // For all other cases, call the parent implementation - [super socket:sock didReadData:data withTag:tag]; + [super socket:asyncSocket didReadData:data withTag:tag]; } - #pragma mark - Helper Methods // Expose the isValidWebSocketFrame method since it's private in the parent @@ -207,22 +223,4 @@ return YES; } -// Override didReceiveMessage to add logging -- (void)didReceiveMessage:(NSString *)msg { - NSLog(@"Received message: %@", msg); - [super didReceiveMessage:msg]; -} - -// Override didOpen to add logging -- (void)didOpen { - NSLog(@"WebSocket opened with ping/pong support"); - [super didOpen]; -} - -- (void)didClose { - NSLog(@"WebSocket closed"); - [super didClose]; -} - @end - From 7cceb5b92d286cbecba74b07d000bd460e4cc90e Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 14:56:40 -0700 Subject: [PATCH 72/75] remove logging from pingpong --- kordophone/Bridge/MBIMPingPongWebSocket.m | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/kordophone/Bridge/MBIMPingPongWebSocket.m b/kordophone/Bridge/MBIMPingPongWebSocket.m index 244fe65..e6efcf1 100644 --- a/kordophone/Bridge/MBIMPingPongWebSocket.m +++ b/kordophone/Bridge/MBIMPingPongWebSocket.m @@ -95,8 +95,6 @@ // Send the pong frame directly through the socket [asyncSocket writeData:pongFrame withTimeout:TIMEOUT_NONE tag:TAG_PONG_SENT]; - - NSLog(@"Sent pong frame with payload length: %lu", (unsigned long)[payload length]); } #pragma mark - Override AsyncSocket Delegate @@ -106,8 +104,6 @@ NSData *maskingKey = [self valueForKey:@"maskingKey"]; BOOL nextFrameMasked = [[self valueForKey:@"nextFrameMasked"] boolValue]; NSUInteger nextOpCode = [[self valueForKey:@"nextOpCode"] unsignedIntValue]; - - NSLog(@"tag: %ld, nextOpCode: %lu", tag, (unsigned long)nextOpCode); // Handle our custom ping payload tag if (tag == TAG_PING_PAYLOAD) { @@ -126,7 +122,6 @@ payload = [unmaskedPayload copy]; } - NSLog(@"Sending pong response to ping with payload length: %lu", (unsigned long)[payload length]); [self sendPongWithPayload:payload]; // Continue reading the next frame @@ -149,8 +144,6 @@ nextFrameMasked = masked; currentPayloadLength = length; - NSLog(@"Processing ping/pong frame, masked: %d, length: %lu", masked, (unsigned long)length); - if (length <= 125) { if (nextFrameMasked) { [asyncSocket readDataToLength:4 withTimeout:TIMEOUT_NONE tag:TAG_MSG_MASKING_KEY]; @@ -158,7 +151,6 @@ [asyncSocket readDataToLength:length withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; } else { // Empty payload, no masking - handle immediately - NSLog(@"Handling empty unmasked ping payload"); [self sendPongWithPayload:[NSData data]]; [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX]; } @@ -175,14 +167,12 @@ if (tag == TAG_MSG_MASKING_KEY) { // Store the masking key maskingKey = [data copy]; - NSLog(@"Stored masking key for ping/pong frame"); // Now read the payload (or handle empty payload) if (currentPayloadLength > 0) { [asyncSocket readDataToLength:currentPayloadLength withTimeout:TIMEOUT_NONE tag:TAG_PING_PAYLOAD]; } else { // Empty payload - send pong immediately - NSLog(@"Sending pong for empty masked ping payload"); [self sendPongWithPayload:[NSData data]]; [asyncSocket readDataToLength:1 withTimeout:TIMEOUT_NONE tag:TAG_PAYLOAD_PREFIX]; } From aace2a8dfcf05fddc0771ba9f1e49e1b1cd4db3d Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 17:42:05 -0700 Subject: [PATCH 73/75] messagelist: actually implement before/after properly --- .../Operations/MBIMMessagesListOperation.m | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m index 5126825..d7609fc 100644 --- a/kordophone/Bridge/Operations/MBIMMessagesListOperation.m +++ b/kordophone/Bridge/Operations/MBIMMessagesListOperation.m @@ -85,15 +85,21 @@ [chat loadMessagesBeforeDate:beforeDate limit:limit loadImmediately:YES]; } + IMMessage *beforeMessage = beforeMessageGUID ? [chat messageForGUID:beforeMessageGUID] : nil; + IMMessage *afterMessage = afterMessageGUID ? [chat messageForGUID:afterMessageGUID] : nil; + [[chat chatItems] enumerateMessagesWithOptions:0 usingBlock:^(IMMessage *message, BOOL *stop) { - // Assume "beforeMessageGUID" is exclusive - if ([[message guid] isEqual:beforeMessageGUID]) { - *stop = YES; - return; + BOOL includeMessage = YES; + NSDate *messageDate = [message time]; + if (beforeMessage && [[beforeMessage time] compare:messageDate] != NSOrderedDescending) { + includeMessage = NO; } - // Assume "afterMessageGUID" is exclusive. - if (![[message guid] isEqual:afterMessageGUID]) { + if (afterMessage && [[afterMessage time] compare:messageDate] != NSOrderedAscending) { + includeMessage = NO; + } + + if (includeMessage) { NSDictionary *messageDict = [message mbim_dictionaryRepresentation]; [messages addObject:messageDict]; } From bb04bc4352e7e7e2c84b4d629fa00b5291f5d902 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 13 Jun 2025 17:42:42 -0700 Subject: [PATCH 74/75] Remove this install step now that we static link --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index e3b73f4..c18ec34 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,6 @@ build/Release/kordophoned: install: build/Release/kordophoned install -d $(INSTALL_PATH) install build/Release/kordophoned $(INSTALL_PATH) - cp -rf build/Release/CocoaHTTPServer.framework $(INSTALL_PATH) clean: rm -Rf build From 800090542d91beae40bc81fc41b67ba61c47da77 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 16 Jun 2025 19:18:14 -0700 Subject: [PATCH 75/75] updates: should really return 401 for bad auth instead of 404 --- kordophone/Bridge/MBIMHTTPConnection.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kordophone/Bridge/MBIMHTTPConnection.m b/kordophone/Bridge/MBIMHTTPConnection.m index 5507df8..86ed2a0 100644 --- a/kordophone/Bridge/MBIMHTTPConnection.m +++ b/kordophone/Bridge/MBIMHTTPConnection.m @@ -17,6 +17,7 @@ #import #import "HTTPMessage.h" +#import "GCDAsyncSocket.h" @interface HTTPConnection (/* INTERNAL */) - (BOOL)isAuthenticated; @@ -139,6 +140,14 @@ if (![self isAuthenticated] && ![queryAuthToken isValid]) { NSLog(@"Websocket: auth invalid, rejecting."); NSLog(@"Query Token: %@, raw: %@", queryAuthToken, authTokenString); + + + // Respond with 401 unauthorized + HTTPMessage *response = [[HTTPMessage alloc] initResponseWithStatusCode:401 description:nil version:HTTPVersion1_1]; + [response setHeaderField:@"Content-Length" value:@"0"]; + + NSData *responseData = [self preprocessErrorResponse:response]; + [asyncSocket writeData:responseData withTimeout:30 tag:90]; return nil; }