diff --git a/AltKit/NSError+ALTServerError.h b/AltKit/NSError+ALTServerError.h index db0979b4..46b36fb0 100644 --- a/AltKit/NSError+ALTServerError.h +++ b/AltKit/NSError+ALTServerError.h @@ -9,6 +9,7 @@ #import extern NSErrorDomain const AltServerErrorDomain; +extern NSErrorDomain const AltServerInstallationErrorDomain; typedef NS_ERROR_ENUM(AltServerErrorDomain, ALTServerError) { @@ -23,6 +24,8 @@ typedef NS_ERROR_ENUM(AltServerErrorDomain, ALTServerError) ALTServerErrorInvalidResponse, ALTServerErrorInvalidApp, + ALTServerErrorInstallationFailed, + ALTServerErrorMaximumFreeAppLimitReached, }; NS_ASSUME_NONNULL_BEGIN diff --git a/AltKit/NSError+ALTServerError.m b/AltKit/NSError+ALTServerError.m index ce780618..96160d90 100644 --- a/AltKit/NSError+ALTServerError.m +++ b/AltKit/NSError+ALTServerError.m @@ -9,6 +9,56 @@ #import "NSError+ALTServerError.h" NSErrorDomain const AltServerErrorDomain = @"com.rileytestut.AltServer"; +NSErrorDomain const AltServerInstallationErrorDomain = @"com.rileytestut.AltServer.Installation"; @implementation NSError (ALTServerError) + ++ (void)load +{ + [NSError setUserInfoValueProviderForDomain:AltServerErrorDomain provider:^id _Nullable(NSError * _Nonnull error, NSErrorUserInfoKey _Nonnull userInfoKey) { + if ([userInfoKey isEqualToString:NSLocalizedFailureReasonErrorKey]) + { + return [error alt_localizedDescription]; + } + + return nil; + }]; +} + +- (nullable NSString *)alt_localizedDescription +{ + switch ((ALTServerError)self.code) + { + case ALTServerErrorUnknown: + return NSLocalizedString(@"An unknown error occured.", @""); + + case ALTServerErrorConnectionFailed: + return NSLocalizedString(@"Could not connect to AltServer.", @""); + + case ALTServerErrorLostConnection: + return NSLocalizedString(@"Lost connection to AltServer.", @""); + + case ALTServerErrorDeviceNotFound: + return NSLocalizedString(@"AltServer could not locate this device", @""); + + case ALTServerErrorDeviceWriteFailed: + return NSLocalizedString(@"Failed to write app data to phone.", @""); + + case ALTServerErrorInvalidRequest: + return NSLocalizedString(@"AltServer received an invalid request.", @""); + + case ALTServerErrorInvalidResponse: + return NSLocalizedString(@"AltServer sent an invalid response.", @""); + + case ALTServerErrorInvalidApp: + return NSLocalizedString(@"The app is invalid.", @""); + + case ALTServerErrorInstallationFailed: + return NSLocalizedString(@"An error occured while installing the app.", @""); + + case ALTServerErrorMaximumFreeAppLimitReached: + return NSLocalizedString(@"You have reached the limit of 3 apps per device.", @""); + } +} + @end diff --git a/AltServer/Devices/ALTDeviceManager.mm b/AltServer/Devices/ALTDeviceManager.mm index a4693bd0..4ed7ebd8 100644 --- a/AltServer/Devices/ALTDeviceManager.mm +++ b/AltServer/Devices/ALTDeviceManager.mm @@ -15,16 +15,14 @@ #include #include -void ALTDeviceManagerDidFinishAppInstallation(const char *notification, void *udid); void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *udid); NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; @interface ALTDeviceManager () -@property (nonatomic, readonly) NSMutableDictionary *installationCompletionHandlers; +@property (nonatomic, readonly) NSMutableDictionary *installationCompletionHandlers; @property (nonatomic, readonly) NSMutableDictionary *installationProgress; -@property (nonatomic, readonly) NSMutableDictionary *installationClients; @property (nonatomic, readonly) dispatch_queue_t installationQueue; @end @@ -49,7 +47,6 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; { _installationCompletionHandlers = [NSMutableDictionary dictionary]; _installationProgress = [NSMutableDictionary dictionary]; - _installationClients = [NSMutableDictionary dictionary]; _installationQueue = dispatch_queue_create("com.rileytestut.AltServer.InstallationQueue", DISPATCH_QUEUE_SERIAL); } @@ -75,7 +72,7 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; lockdownd_service_descriptor_t service = NULL; void (^finish)(NSError *error) = ^(NSError *error) { - np_client_free(np); + instproxy_client_free(ipc); afc_client_free(afc); lockdownd_client_free(client); @@ -138,28 +135,6 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); } - /* Connect to Notification Proxy */ - if ((lockdownd_start_service(client, "com.apple.mobile.notification_proxy", &service) != LOCKDOWN_E_SUCCESS) || service == NULL) - { - return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); - } - - if (np_client_new(device, service, &np) != NP_E_SUCCESS) - { - return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); - } - - np_set_notify_callback(np, ALTDeviceManagerDidFinishAppInstallation, uuidString); - - const char *notifications[2] = { NP_APP_INSTALLED, NULL }; - np_observe_notifications(np, notifications); - - if (service) - { - lockdownd_service_descriptor_free(service); - service = NULL; - } - /* Connect to Installation Proxy */ if ((lockdownd_start_service(client, "com.apple.mobile.installation_proxy", &service) != LOCKDOWN_E_SUCCESS) || service == NULL) { @@ -177,18 +152,12 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; service = NULL; } - lockdownd_service_descriptor_free(service); - service = NULL; - /* Connect to AFC service */ if ((lockdownd_start_service(client, "com.apple.afc", &service) != LOCKDOWN_E_SUCCESS) || service == NULL) { return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); } - lockdownd_client_free(client); - client = NULL; - if (afc_client_new(device, service, &afc) != AFC_E_SUCCESS) { return finish([NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); @@ -239,12 +208,11 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; NSProgress *installationProgress = [NSProgress progressWithTotalUnitCount:100 parent:progress pendingUnitCount:1]; - NSValue *value = [NSValue valueWithPointer:(const void *)np]; + NSProgress *installationProgress = [NSProgress progressWithTotalUnitCount:100 parent:progress pendingUnitCount:1]; - self.installationClients[UUID] = value; self.installationProgress[UUID] = installationProgress; - self.installationCompletionHandlers[UUID] = ^{ - finish(nil); + self.installationCompletionHandlers[UUID] = ^(NSError *error) { + finish(error); if (temporaryDirectoryURL != nil) { @@ -470,29 +438,6 @@ NSErrorDomain const ALTDeviceErrorDomain = @"com.rileytestut.ALTDeviceError"; #pragma mark - Callbacks - -void ALTDeviceManagerDidFinishAppInstallation(const char *notification, void *uuid) -{ - NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:[NSString stringWithUTF8String:(const char *)uuid]]; - - void (^completionHandler)(void) = ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID]; - if (completionHandler != nil) - { - completionHandler(); - - ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID] = nil; - ALTDeviceManager.sharedManager.installationProgress[UUID] = nil; - } - - NSValue *value = ALTDeviceManager.sharedManager.installationClients[UUID]; - if (value != nil) - { - np_client_t np = (np_client_t)value.pointerValue; - np_set_notify_callback(np, NULL, uuid); - - ALTDeviceManager.sharedManager.installationClients[UUID] = nil; - } -} - void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *uuid) { NSUUID *UUID = [[NSUUID alloc] initWithUUIDString:[NSString stringWithUTF8String:(const char *)uuid]]; @@ -506,7 +451,46 @@ void ALTDeviceManagerUpdateStatus(plist_t command, plist_t status, void *uuid) int percent = -1; instproxy_status_get_percent_complete(status, &percent); - if (progress.completedUnitCount < percent) + char *name = NULL; + char *description = NULL; + uint64_t code = 0; + instproxy_status_get_error(status, &name, &description, &code); + + if ((percent == -1 && progress.completedUnitCount > 0) || code != 0) + { + void (^completionHandler)(NSError *) = ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID]; + if (completionHandler != nil) + { + if (code != 0) + { + NSLog(@"Error installing app. %@ (%@). %@", @(code), @(name), @(description)); + + NSError *error = nil; + + if (code == 3892346913) + { + error = [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorMaximumFreeAppLimitReached userInfo:nil]; + } + else + { + NSError *underlyingError = [NSError errorWithDomain:AltServerInstallationErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: @(description)}]; + + error = [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorInstallationFailed userInfo:@{NSUnderlyingErrorKey: underlyingError}]; + } + + completionHandler(error); + } + else + { + NSLog(@"Finished installing app!"); + completionHandler(nil); + } + + ALTDeviceManager.sharedManager.installationCompletionHandlers[UUID] = nil; + ALTDeviceManager.sharedManager.installationProgress[UUID] = nil; + } + } + else if (progress.completedUnitCount < percent) { progress.completedUnitCount = percent;