123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827 |
- //
- // AppDelegate.m
- // nitoTV4Installer
- //
- // Created by Kevin Bradley on 1/24/18.
- // Copyright © 2018 Kevin Bradley. All rights reserved.
- //
- #import "AppDelegate.h"
- #import "ATVDeviceController.h"
- @interface AppDelegate ()
- @property (weak) IBOutlet NSWindow *window;
- //@property (readwrite, assign) BOOL atvAvailable;
- //@property (nonatomic, strong) NSString *bundleID;
- @property (nonatomic, strong) IBOutlet ATVDeviceController *deviceController;
- @end
- @implementation AppDelegate
- @synthesize window,workingPath, sshSession, isSending, downloading, downloadFile;
- @synthesize deviceController;
- static NSString *appleTVAddress = nil;
- - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
- // Insert code here to initialize your application
-
- //deviceController = [[ATVDeviceController alloc] init];
- //variables that was a carry over from code i migrated this from, can probably be pruned, dont think i use it.
- appleTVAddress = APPLE_TV_ADDRESS;
- NSLog(@"SELECTED_VALUE: %@", SELECTED_VALUE);
- if (SELECTED_VALUE != nil)
- {
- [deviceController.theComboBox selectItemWithTitle:SELECTED_VALUE];
-
- [deviceController menuItemSelected:deviceController.theComboBox];
- }
-
- NSLog(@"appleTVAddress: %@", appleTVAddress);
-
- if ([[appleTVAddress componentsSeparatedByString:@":"] count] < 2)
- {
- [self resetServerSettings];
-
- }
-
- }
- - (NSString *)appSupportFolder
- {
- NSString *supportFolder = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/nitoDownload"];
- NSLog(@"dir: %@", supportFolder);
- if (![FM fileExistsAtPath:supportFolder])
- {
- [FM createDirectoryAtPath:supportFolder withIntermediateDirectories:YES attributes:nil error:nil];
- }
- return supportFolder;
- }
- + (NSArray *)returnForProcess:(NSString *)call
- {
- if (call==nil)
- return 0;
- char line[200];
-
- FILE* fp = popen([call UTF8String], "r");
- NSMutableArray *lines = [[NSMutableArray alloc]init];
- if (fp)
- {
- while (fgets(line, sizeof line, fp))
- {
- NSString *s = [NSString stringWithCString:line encoding:NSUTF8StringEncoding];
- s = [s stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
- [lines addObject:s];
- }
- }
- pclose(fp);
- return lines;
- }
- //59293ffbdee698488aba799a96fcfe95e1165fa10f760362a2ce910576134e39
- - (BOOL)verifyChecksum:(NSString *)checksum onFile:(NSString *)file
- {
- NSString *processReturn = [[AppDelegate returnForProcess:[NSString stringWithFormat:@"/usr/bin/shasum -a 256 \"%@\" | cut -c 1-64", file]] componentsJoinedByString:@"\n"];
- NSLog(@"return: -%@-", processReturn);
- return [processReturn isEqualToString:checksum];
-
- }
- - (void)downloadFile:(NSString *)thePayload
- {
- //we're already downloading, cancel
- //TODO: make downloading NSOperation/NSOperationQueue based
- if (self.downloading == true)
- {
- [downloadFile cancel];
- self.downloading = false;
- statusLabel.stringValue = @"";
- [self.progressInd setDoubleValue:0];
- [self.progressInd setHidden:TRUE];
- self.mainButton.enabled = TRUE;
- return;
- }
- //create instance of downloader class
- downloadFile = [KBDownloadFile new];;
- //self.downloadButton.title = @"Cancel";
- self.downloading = true;
-
- NSString *downloadLocation = [[self appSupportFolder] stringByAppendingPathComponent:[thePayload lastPathComponent]];
-
- if ([FM fileExistsAtPath:downloadLocation])
- {
- NSString *hash = @"59293ffbdee698488aba799a96fcfe95e1165fa10f760362a2ce910576134e39";
- switch (self.versionState) {
- case KBInstallVersionStateEleven:
- case KBInstallVersionStateTenTwo:
-
- hash = @"59293ffbdee698488aba799a96fcfe95e1165fa10f760362a2ce910576134e39";
- break;
-
- case KBInstallVersionStateNine:
- case KBInstallVersionStateTenOne:
-
- hash = @"327c7cea49282109e23c9415d318121f91b79ca7bb813c8724a1c0752e8311af";
- break;
-
- default:
- break;
- }
- if( [self verifyChecksum:hash onFile:downloadLocation])
- {
- NSLog(@"file validated!");
-
- [self handleDownloadFile:downloadLocation];
- return;
- //completion(true);
-
- }
- }
-
- statusLabel.stringValue = [NSString stringWithFormat:@"Downloading: %@...", thePayload.lastPathComponent];
-
- //get the stream we want to download
-
- [downloadFile downloadFileWithURL:[NSURL URLWithString:thePayload] toLocation:downloadLocation progress:^(double percentComplete) {
-
- [self setDownloadProgress:percentComplete];
-
- } completed:^(NSString *downloadedFile) {
- //[self hideProgress];
- self.downloading = false;
-
- [self setDownloadProgress:0];
- statusLabel.stringValue = [NSString stringWithFormat:@"Uploading file %@....", downloadedFile.lastPathComponent];
-
-
- [self handleDownloadFile:downloadedFile];
-
-
-
- //[self uploadFile:downloadedFile];
-
- }];
-
- }
- - (void)handleDownloadFile:(NSString *)downloadedFile
- {
- [self setDownloadProgress:0];
- statusLabel.stringValue = [NSString stringWithFormat:@"Uploading file %@....", downloadedFile.lastPathComponent];
-
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
-
-
- [self uploadFile:downloadedFile withCompletion:^(BOOL success) {
-
- dispatch_async(dispatch_get_main_queue(), ^{
-
- if (success)
- {
- NSLog(@"file uploaded successfully!");
- statusLabel.stringValue = @"File uploaded successfully!";
- statusLabel.stringValue = @"Installing payload...";
- NSString *tarString = [self tarPathForCurrentMode];
- NSString *bootstrap = [NSString stringWithFormat:@"/var/mobile/Documents/%@", downloadedFile.lastPathComponent];
-
- NSString *installCommand = [NSString stringWithFormat:@"%@ fxpv %@ -C / ; /usr/libexec/substrate ; /usr/bin/uicache ; /bin/bash /usr/libexec/nito/firmware.sh ; rm /var/mobile/Library/Preferences/Featured.plist", tarString, bootstrap];
-
-
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
-
- NSString *returnString = [self sendCommandString:installCommand];
- NSLog(@"return string: %@", returnString);
- NSString *logFile = [[self appSupportFolder] stringByAppendingPathComponent:@"install.log"];
-
- [returnString writeToFile:logFile atomically:YES encoding:NSUTF8StringEncoding error:nil];
-
- if (self.versionState == KBInstallVersionStateNine)
- {
- [self sendCommandString:@"/usr/bin/killall -9 PineBoard HeadBoard lsd nitoTV"];
- }
-
- dispatch_async(dispatch_get_main_queue(), ^{
- [[NSWorkspace sharedWorkspace] openFile:logFile];
-
- statusLabel.stringValue = @"Payload installed?!?!";
-
-
- [self.progressInd stopAnimation:nil];
- self.mainButton.enabled = TRUE;
- });
- });
-
- } else {
- statusLabel.stringValue = @"File failed to upload!";
- [self.progressInd stopAnimation:nil];
- self.mainButton.enabled = TRUE;
- }
-
- });
-
- }];
-
- });
-
-
-
- }
- - (void)hideProgress
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- statusLabel.stringValue = @"";
- [[self progressInd] stopAnimation:nil];
- [[self progressInd] setDoubleValue:0];
- [[self progressInd] setHidden:true];
- });
-
- }
- - (void)setDownloadProgress:(double)theProgress
- {
- dispatch_async(dispatch_get_main_queue(), ^{
-
- if (theProgress == 0)
- {
- [self.progressInd setIndeterminate:TRUE];
- [self.progressInd setHidden:FALSE];
- [self.progressInd setNeedsDisplay:YES];
- [self.progressInd setUsesThreadedAnimation:YES];
- [self.progressInd startAnimation:self];
- return;
- }
- [self.progressInd setIndeterminate:FALSE];
- [self.progressInd startAnimation:self];
- [self.progressInd setHidden:FALSE];
- [self.progressInd setNeedsDisplay:YES];
- [self.progressInd setDoubleValue:theProgress];
- });
-
- }
- - (void)setStatusText:(NSString *)statusText
- {
- dispatch_async(dispatch_get_main_queue(), ^{
-
- statusLabel.stringValue = statusText;
- });
- }
- - (BOOL)atvAvailable
- {
- return _atvAvailable;
- }
- - (void)setAtvAvailable:(BOOL)atvAvailable
- {
- _atvAvailable = atvAvailable;
- }
- - (void)applicationWillTerminate:(NSNotification *)aNotification {
- // Insert code here to tear down your application
- }
- - (NSString *)tarPathForCurrentMode
- {
- NSString *path = nil;
- switch (self.versionState) {
- case KBInstallVersionStateNine:
-
- path= @"/usr/bin/tar";
- break;
-
- case KBInstallVersionStateTenOne:
-
- path= @"/tmp/usr/bin/tar"; //need to verify
- break;
-
- case KBInstallVersionStateTenTwo:
-
- path= @"/usr/bin/tar";
- break;
-
- case KBInstallVersionStateEleven:
-
- path= @"/jb/usr/bin/tar";
- break;
- default:
- break;
- }
- return path;
- }
- - (NSString *)lsPathForCurrentMode
- {
- NSString *path = nil;
- switch (self.versionState) {
- case KBInstallVersionStateNine:
-
- path= @"/bin/ls";
- break;
-
- case KBInstallVersionStateTenOne:
-
- path= @"/tmp/bin/ls";
- break;
-
- case KBInstallVersionStateTenTwo:
-
- path= @"/usr/bin/ls";
- break;
-
- case KBInstallVersionStateEleven:
-
- path= @"/jb/bin/ls";
- break;
- default:
- break;
- }
- return path;
- }
- - (BOOL)checkForFile:(NSString *)file
- {
- //@"ls /usr/bin/ | grep appinst"
- NSString *lsCommand = [self lsPathForCurrentMode];
- NSString *path = [file stringByDeletingLastPathComponent];
- NSString *bareFile = [file lastPathComponent];
- NSString *theReturn = [self sendCommandString:[NSString stringWithFormat:@"%@ -a %@ | grep %@", lsCommand, path, bareFile]];
- if (theReturn != nil)
- { return (TRUE);
- } else { return (FALSE);}
-
- return (FALSE);
- }
- - (void)checkJailbreakWithCompletion:(void(^)(BOOL jailbroken))completion
- {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
-
- BOOL jb = [self isJailbroken];
- if (jb)
- {
- NSLog(@"we outchea");
- } else {
- NSLog(@"nope!");
- }
- completion(jb);
- });
- }
- - (BOOL)isJailbroken
- {
- NSError *error = nil;
- if (APPLE_TV_ADDRESS != nil)
- {
- ObjSSH *ssh = [ObjSSH connectToHost:APPLE_TV_ADDRESS withUsername:@"root" password:@"alpine" error:&error];
- if (error)
- {
- NSLog(@"error: %@", [error localizedDescription]);
- if ([[error localizedDescription] isEqualToString:@"Failed to connect"])
- {
- [ssh disconnect];
-
- return (FALSE);
- }
-
- [ssh disconnect];
-
- }
- } else {
- return (FALSE);
- }
-
-
- return (TRUE);
- }
- //if they changed password from alpine this is used to get the proper password to connect
- - (void)resetServerSettings
- {
- [DEFAULTS removeObjectForKey:@"appleTVHost"];
- [DEFAULTS removeObjectForKey:ATV_OS];
- [DEFAULTS removeObjectForKey:ATV_API];
- [DEFAULTS setObject:@"Choose Apple TV" forKey:@"selectedValue"];
- appleTVAddress = nil;
- [[self progressInd] stopAnimation:nil];
- }
- - (NSString *)secureInput: (NSString *)prompt defaultValue: (NSString *)defaultValue {
- NSAlert *alert = [NSAlert alertWithMessageText: prompt
- defaultButton:@"OK"
- alternateButton:@"Cancel"
- otherButton:nil
- informativeTextWithFormat:@""];
-
- NSSecureTextField *input = [[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];
- [input setStringValue:defaultValue];
-
- [alert setAccessoryView:input];
- NSInteger button = [alert runModal];
- if (button == NSAlertDefaultReturn) {
- [input validateEditing];
- NSString *inputString = [input stringValue];
-
- return inputString;
- } else if (button == NSAlertAlternateReturn) {
-
- return nil;
- } else {
-
- return nil;
- }
- }
- //add a password to the keychain for SSH
- - (void)addkeychainPassword:(NSString *)password
- {
- //kSecProtocolTypeSSH
- [EMInternetKeychainItem addInternetKeychainItemForServer:APPLE_TV_ADDRESS withUsername:@"root" password:password path:@"/usr/bin/ssh" port:22 protocol:kSecProtocolTypeSSH];
- }
- - (void)removeKeychainForHost:(NSString *)ipAddress
- {
- //kSecProtocolTypeSSH
- EMInternetKeychainItem *keychainItem = [EMInternetKeychainItem internetKeychainItemForServer:ipAddress withUsername:@"root" path:@"/usr/bin/ssh" port:22 protocol:kSecProtocolTypeSSH];
- [keychainItem removeFromKeychain];
- }
- //fetch the password from the keychain for the specified ip address
- - (NSString *)passwordForHost:(NSString *)ipAddress
- {
- EMInternetKeychainItem *keychainItem = [EMInternetKeychainItem internetKeychainItemForServer:ipAddress withUsername:@"root" path:@"/usr/bin/ssh" port:22 protocol:kSecProtocolTypeSSH];
- //Grab the password.
- if (keychainItem != nil)
- {
- //Grab the password.
- NSString *password = keychainItem.password;
-
- return password;
- }
-
- NSLog(@"nothing!");
- return nil;
-
- }
- - (BOOL)uploadFile:(NSString *)theFile toPath:(NSString *)newPath
- {
- NSLog(@"uploading file: %@", theFile);
- NSError *error = nil;
- BOOL getSession = [self connectToSSH];
- if (getSession == FALSE)
- {
- NSLog(@"failed to get session!");
- return (FALSE);
- }
-
- NSString *finalPath = [newPath stringByAppendingPathComponent:[theFile lastPathComponent]];
-
- BOOL uploadFile = [sshSession uploadFile:theFile to:finalPath error:&error];
- if (error)
- {
- NSLog(@"ERROR!: %@", error);
- }
- return (uploadFile);
-
- }
- - (void)uploadFile:(NSString *)theFile withCompletion:(void(^)(BOOL success))completion
- {
- NSLog(@"uploading file: %@", theFile);
- NSError *error = nil;
- BOOL getSession = [self connectToSSH];
- if (getSession == FALSE)
- {
- NSLog(@"failed to get session!");
- completion(false);
- }
- BOOL uploadFile = [self uploadFile:theFile toPath:@"/var/mobile/Documents"];
- completion(uploadFile);
-
- }
- //upload a file over SSH to the selected AppleTV
- - (BOOL)uploadFile:(NSString *)theFile
- {
- NSLog(@"uploading file: %@", theFile);
- NSError *error = nil;
- BOOL getSession = [self connectToSSH];
- if (getSession == FALSE)
- {
- NSLog(@"failed to get session!");
- return (FALSE);
- }
- statusLabel.stringValue = [NSString stringWithFormat:@"Uploading file %@....", theFile.lastPathComponent];
- BOOL uploadFile = [sshSession uploadFile:theFile to:[theFile lastPathComponent] error:&error];
- if (error)
- {
- NSLog(@"ERROR!: %@", error);
- }
- return (uploadFile);
-
- }
- //used to send basic commands to the jailbroken AppleTV over SSH
- - (NSString *)sendCommandString:(NSString *)theCommand
- {
- NSLog(@"%@", theCommand);
- NSError *error = nil;
- BOOL getSession = [self connectToSSH];
- if (getSession == FALSE)
- {
- NSLog(@"failed to get session!");
- return nil;
- }
-
-
- NSString *response = [sshSession execute:theCommand error:&error];
-
- return response;
-
- }
- //open the SSH session
- - (BOOL)connectToSSH
- {
- NSError *error = nil;
-
- if (sshSession == nil)
- {
- //NSLog(@"APPLE_TV_ADDRESS: %@", APPLE_TV_ADDRESS);
- sshSession = [ObjSSH connectToHost:APPLE_TV_ADDRESS withUsername:@"root" password:@"alpine" error:&error];
- if (sshSession == nil)
- {
- NSLog(@"error: %@ get password!", error);
- NSString *passwordForHost = [self passwordForHost:APPLE_TV_ADDRESS];
- NSString *output = nil;
- if (passwordForHost != nil)
- {
- output = passwordForHost;
-
- } else {
- output = [self secureInput:@"Enter Password" defaultValue:@""];
- }
-
- if ([output length] == 0)
- {
- NSLog(@"no password to send!! return!");
-
- return (FALSE);
-
- } else {
-
-
-
- error = nil;
- sshSession = [ObjSSH connectToHost:APPLE_TV_ADDRESS withUsername:@"root" password:output error:&error];
-
- if (error != nil)
- {
- NSLog(@"error: %@ password failed!", error);
-
- [self removeKeychainForHost:APPLE_TV_ADDRESS];
- return (FALSE);
- } else {
- [self addkeychainPassword:output];
- }
-
- }
-
-
- }
- }
- if (sshSession != nil)
- return (TRUE);
-
-
- return (FALSE);
- }
- - (void)showNotJailbrokenWarning
- {
- NSAlert *alert = [NSAlert alertWithMessageText:@"This Apple TV isn't jailbroken, please jailbreak it first! Would you like to visit our web site for further assistance?"
- defaultButton:@"Yes"
- alternateButton:@"Cancel"
- otherButton:nil
- informativeTextWithFormat:@""];
-
- NSInteger button = [alert runModal];
- if (button == NSAlertDefaultReturn) {
-
- [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://wiki.awkwardtv.org"]];
- }
- }
- - (void)showATVWarning
- {
- NSAlert *alert = [NSAlert alertWithMessageText:@"Only the AppleTV 4 is supported"
- defaultButton:@"OK"
- alternateButton:nil
- otherButton:nil
- informativeTextWithFormat:@""];
-
- [alert runModal];
- }
- - (NSString *)logLocation
- {
- NSString *location = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Logs/iReSign"];
- if (![FM fileExistsAtPath:location])
- {
- [FM createDirectoryAtPath:location withIntermediateDirectories:true attributes:nil error:nil];
- }
- return location;
- }
- //versions
- //265.5 = 9.0
- //301.44.3 = 10.0
- //310.17 = 10.1 (either .0 or .1)
- //320.20.1 = 10.2.2
- //353.50 = 11.1
- - (IBAction)doIt:(id)sender
- {
- [self.mainButton setEnabled:NO];
- NSString *bootstrapPath = @"http://nitosoft.com/ATV4/bootstraps/";
- NSString *swVers = self.deviceDict[@"osvers"];
- if (swVers.length > 0)
- {
- NSLog(@"our sw vers: %@", swVers);
- if ([swVers floatValue] >= 11)
- {
- self.versionState = KBInstallVersionStateEleven;
- NSLog(@"11 payload!");
- bootstrapPath = [bootstrapPath stringByAppendingString:@"bootstrap11.tar"];
- }
-
- } else {
-
- swVers = self.deviceDict[@"srcvers"];
- {
- NSLog(@"our src vers: %@", swVers);
- if([swVers compare:@"320.20.1" options:NSNumericSearch] != NSOrderedAscending)
- {
- self.versionState = KBInstallVersionStateTenTwo;
- NSLog(@"10.2.2 or greater!");
- bootstrapPath = [bootstrapPath stringByAppendingString:@"bootstrap11.tar"];
- } else if([swVers compare:@"301.44.3" options:NSNumericSearch] != NSOrderedAscending)
- {
- NSLog(@"10.0 or greater");
- self.versionState = KBInstallVersionStateTenOne;
- bootstrapPath = [bootstrapPath stringByAppendingString:@"bootstrap9.tar"];
- } else {
- NSLog(@"9.0 or greater?");
- self.versionState = KBInstallVersionStateNine;
- bootstrapPath = [bootstrapPath stringByAppendingString:@"bootstrap9.tar"];
-
-
- }
-
- }
- }
- if ([self connectToSSH])
- {
- // if ([self checkForFile:@"/var/root/.bootstrapped"]){
-
- // NSLog(@"were already bootstrapped!");
- //} else {
- [self downloadFile:bootstrapPath];
- // }
- //
- //[self downloadSyslogAndShow:YES];
- } else {
- self.mainButton.enabled = TRUE;
- }
- }
- - (BOOL)downloadSyslogAndShow:(BOOL)show
- {
- BOOL getSession = [self connectToSSH];
- if (getSession == FALSE)
- {
- NSLog(@"failed to get session!");
- return false;
- }
- NSError *error = nil;
- NSString *newSyslog = [[self logLocation] stringByAppendingPathComponent:@"syslog.log"];
- if ([[NSFileManager defaultManager] fileExistsAtPath:newSyslog])
- {
- [[NSFileManager defaultManager] removeItemAtPath:newSyslog error:nil];
- }
- //echo latest syslog output to a new file for downloadin..
- [self sendCommandString:@"/jb/usr/bin/syslog > syslog.log"];
- BOOL downloadFile = [sshSession downloadFile:@"/var/root/syslog.log" to:newSyslog error:&error];
- if (downloadFile)
- {
- NSLog(@"File downloaded Successfully!");
- if (show == true)
- {
- [[NSWorkspace sharedWorkspace] openFile:newSyslog];
- }
- return true;
- }
- return false;
- }
- - (void)installFile:(NSString *)theFile withCompletionBlock:(void(^)(BOOL success))completionBlock
- {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
-
- @autoreleasepool {
-
- BOOL success = FALSE;
-
- if ([self uploadFile:finalDestination toPath:@"/var/mobile/Documents"] == true)
- {
- dispatch_async(dispatch_get_main_queue(), ^{
-
- [statusLabel setStringValue:[NSString stringWithFormat:@"Installing file %@...", fileName]];
-
- });
-
- /*
-
- Massively kludgy but it works, for some reason when appinst runs it doesnt go to stdout (or something) so i /need/ to redirect it to a text file, then cat that text file to check for whether or not "installed <bundle_id>" exists
-
- */
-
- NSString *checkResponse = [NSString stringWithFormat:@"installed %@", self.bundleID];
-
- NSString *runLine = [NSString stringWithFormat:@"/usr/bin/appinst /var/mobile/Documents/%@ 2> install.txt ; cat install.txt", fileName];
- //NSString *runLine = [NSString stringWithFormat:@"/usr/bin/appinst /var/mobile/Documents/%@", fileName];
-
- NSString *response = [self sendCommandString:runLine];
-
- //using rangeOfString because containsString is too new for backwards compat.
-
- if ([response rangeOfString:checkResponse].location == NSNotFound)
- {
-
- NSString *errorLog = [[self logLocation] stringByAppendingFormat:@"/%@.log", self.bundleID];
-
- //remove old copies
- if ([FM fileExistsAtPath:errorLog])
- {
- [FM removeItemAtPath:errorLog error:nil];
- }
-
- //the response above has a bunch of garbled text in it, download the install file "proper" to get the cleaner version
-
- BOOL downloadFile = [sshSession downloadFile:@"/var/root/install.txt" to:errorLog error:nil];
- if (downloadFile == false)
- {
-
- //if that fails for some reason write the version with the garbage at the end
-
- [response writeToFile:errorLog atomically:true encoding:NSUTF8StringEncoding error:nil];
-
- }
-
- response = [NSString stringWithContentsOfFile:errorLog encoding:NSUTF8StringEncoding error:nil];
- NSLog(@"INSTALLATION FAILED WITH LOG: %@", response);
-
- //grab latest relevant syslog chunk
- [self downloadSyslogAndShow:false];
-
- } else {
- runLine = [NSString stringWithFormat:@"/bin/rm /var/mobile/Documents/%@", fileName];
- [self sendCommandString:runLine];
- success = true;
- }
-
-
- }
-
-
- dispatch_async(dispatch_get_main_queue(), ^{
-
-
- completionBlock(success);
-
-
-
- });
-
- }
-
- });
- }
- @end
|