//
//  electra_objc.m
//  electra1131
//
//  Created by CoolStar on 6/6/18.
//  Copyright © 2018 CoolStar. All rights reserved.
//

#include <dlfcn.h>
#include <copyfile.h>
#include <stdio.h>
#include <spawn.h>
#include <unistd.h>
#include <mach/mach.h>
#include <mach-o/dyld.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/utsname.h>
#import <Foundation/Foundation.h>
#import "NSData+GZip.h"
#import "utils.h"
#import "file_utils.h"
#import "ViewController.h"
#include "electra_objc.h"
#include "MobileGestalt.h"
#include <CommonCrypto/CommonCrypto.h>
#include "NSString+SHA256.h"

const char* realPath() {
    char path[4096];
    uint32_t size = sizeof(path);
    _NSGetExecutablePath(path, &size);
    char *pt = realpath(path, NULL);
    return pt;
}

const char* progname(const char* prog) {
    NSString *execpath = [[NSString stringWithUTF8String:realPath()] stringByDeletingLastPathComponent];

    NSString *bootstrap = [execpath stringByAppendingPathComponent:[NSString stringWithUTF8String:prog]];
    return [bootstrap UTF8String];
}

const char *userGenerator(void) {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    if ([userDefaults objectForKey:@K_GENERATOR] == nil)
        return NULL;
    
    const char *generator = [[userDefaults objectForKey:@K_GENERATOR] UTF8String];
    char compareString[22];
    uint64_t rawGeneratorValue;
    sscanf(generator, "0x%16llx", &rawGeneratorValue);
    sprintf(compareString, "0x%016llx", rawGeneratorValue);
    if(strcmp(compareString, generator) != 0)
        return NULL;
    return generator;
}

const char *genToSet(void) {
    const char *generator = userGenerator();
    if (generator == NULL)
        generator = strdup(K_ELECTRA_GENERATOR);
    
    return generator;
}

void getAndSendStats(void) {
    NSString *electraVer = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    NSString *deviceVer = [[UIDevice currentDevice] systemVersion];
    struct utsname u = { 0 };
    uname(&u);
    NSString *deviceModel = [NSString stringWithUTF8String:u.machine];
    CFStringRef value = MGCopyAnswer(kMGUniqueDeviceID);
    
    if (!value) {
        return;
    }
    
    NSString *SHA256OfUDID = [[NSString stringWithFormat:@"%@", value] SHA256String];
    
    CFRelease(value);
    
    if (!electraVer || !deviceVer || !deviceModel || !SHA256OfUDID) {
        return;
    }
    
    NSDictionary *dict = @{ @"ios_version": deviceVer, @"electra_version": electraVer, @"device_model": deviceModel, @"udid": SHA256OfUDID };
#if ELECTRADEBUG
    NSLog(@"%@", dict);
#else /* !ELECTRADEBUG */
    NSError *error = nil;
    NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
    
    if (error) {
        return;
    }
    
    NSMutableURLRequest *URLRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://collectra.herokuapp.com/devices"]];
    [URLRequest setHTTPMethod:@"POST"];
    [URLRequest setHTTPBody:data];
    [URLRequest addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    
    NSURLSession *URLSession = [NSURLSession sharedSession];
    
    NSURLSessionDataTask *URLSessionDataTask = [URLSession dataTaskWithRequest:URLRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
#if ELECTRADEBUG
        NSLog(@"response: %li", httpResponse.statusCode);
#endif /* ELECTRADEBUG */
    }];
    [URLSessionDataTask resume];
#endif /* !ELECTRADEBUG */
}

void extractGz(const char *from, const char *to) {
    NSData *gz = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@(from) ofType:@"gz"]];
    NSData *extracted = [gz gunzippedData];
    int fd = open(to, O_CREAT | O_WRONLY, 0755);
    write(fd, [extracted bytes], [extracted length]);
    close(fd);
}

void update_springboard_plist(){
    NSDictionary *springBoardPlist = [NSMutableDictionary dictionaryWithContentsOfFile:@"/var/mobile/Library/Preferences/com.apple.springboard.plist"];
    [springBoardPlist setValue:@YES forKey:@"SBShowNonDefaultSystemApps"];
    [springBoardPlist writeToFile:@"/var/mobile/Library/Preferences/com.apple.springboard.plist" atomically:YES];
    
    NSDictionary* attr = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithShort:0755], NSFilePosixPermissions,@"mobile",NSFileOwnerAccountName,NULL];
    
    NSError *error = nil;
    [[NSFileManager defaultManager] setAttributes:attr ofItemAtPath:@"/var/mobile/Library/Preferences/com.apple.springboard.plist" error:&error];
}

void startDaemons(){    
    pid_t pd;
    
    NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/etc/rc.d" error:nil];
    
    files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/Library/LaunchDaemons/" error:nil];
    for (NSString *fileName in files){
        if ([fileName isEqualToString:@"jailbreakd.plist"])
            continue;
        if ([fileName isEqualToString:@"com.openssh.sshd.plist"])
            continue;
        
        NSString *fullPath = [@"/Library/LaunchDaemons" stringByAppendingPathComponent:fileName];
        
        posix_spawn(&pd, "/bin/launchctl", NULL, NULL, (char **)&(const char*[]){ "launchctl", "load", [fullPath UTF8String], NULL }, NULL);
        waitpid(pd, NULL, 0);
    }
}

void dumpContentsOfDir(char *path){
    NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[NSString stringWithUTF8String:path] error:nil];
    NSLog(@"Files at %s: %@", path, files);
}

void dumpContentsOfFile(char *path){
    NSString *fileContents = [NSString stringWithContentsOfFile:[NSString stringWithUTF8String:path] encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"File %s contains: %@", path, fileContents);
}

void displaySnapshotNotice(){
    [[ViewController currentViewController] displaySnapshotNotice];
}

void displaySnapshotWarning(){
    [[ViewController currentViewController] displaySnapshotWarning];
}

void removingLiberiOS(){
    [[ViewController currentViewController] removingLiberiOS];
}

void installingCydia(){
    [[ViewController currentViewController] installingCydia];
}

void cydiaDone(){
    [[ViewController currentViewController] cydiaDone];
}

void restarting() {
    [[ViewController currentViewController] restarting];
}
