2018-06-30 13:10:06 +00:00
|
|
|
#include <functional>
|
|
|
|
#include <memory>
|
|
|
|
#include <iostream>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <string>
|
|
|
|
#include <list>
|
2018-07-13 06:30:16 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <future>
|
|
|
|
#include <vector>
|
2018-06-30 13:10:06 +00:00
|
|
|
|
|
|
|
#import <Foundation/Foundation.h>
|
2018-09-19 00:37:16 +00:00
|
|
|
#import <Foundation/NSFileManager.h>
|
2018-06-30 13:10:06 +00:00
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
|
2018-06-30 13:10:06 +00:00
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
#include <CoreFoundation/CFStream.h>
|
|
|
|
#include <CoreFoundation/CFPropertyList.h>
|
|
|
|
#include <CoreFoundation/CFDictionary.h>
|
|
|
|
#include <CoreFoundation/CFArray.h>
|
|
|
|
#include <CoreFoundation/CFString.h>
|
|
|
|
#include <CoreFoundation/CFPreferences.h>
|
|
|
|
|
|
|
|
#import <objc/Object.h>
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
|
|
#import <AppKit/AppKit.h>
|
|
|
|
#import <AppKit/NSApplication.h>
|
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
#import "I2PLauncher-Swift.h"
|
|
|
|
|
2018-06-30 13:10:06 +00:00
|
|
|
#include "AppDelegate.h"
|
2018-07-13 06:30:16 +00:00
|
|
|
#include "RouterTask.h"
|
2018-06-30 13:10:06 +00:00
|
|
|
#include "JavaHelper.h"
|
2018-09-18 15:39:32 +00:00
|
|
|
#include "include/fn.h"
|
|
|
|
#include "include/portcheck.h"
|
2018-09-20 02:38:44 +00:00
|
|
|
#import "SBridge.h"
|
2018-06-30 13:10:06 +00:00
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
#ifdef __cplusplus
|
2018-09-20 02:38:44 +00:00
|
|
|
#include <string>
|
2018-06-30 13:10:06 +00:00
|
|
|
|
2018-09-19 17:00:17 +00:00
|
|
|
#include "include/subprocess.hpp"
|
|
|
|
#include "include/strutil.hpp"
|
|
|
|
|
|
|
|
using namespace subprocess;
|
2018-06-30 13:10:06 +00:00
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
#endif
|
2018-07-13 06:30:16 +00:00
|
|
|
|
2018-09-19 17:00:17 +00:00
|
|
|
#define debug(format, ...) CFShow([NSString stringWithFormat:format, ## __VA_ARGS__]);
|
|
|
|
|
|
|
|
@interface AppDelegate () <NSUserNotificationCenterDelegate, NSApplicationDelegate>
|
|
|
|
@end
|
|
|
|
|
2018-07-24 16:26:40 +00:00
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
@implementation ExtractMetaInfo : NSObject
|
2018-07-24 16:26:40 +00:00
|
|
|
@end
|
2018-07-13 06:30:16 +00:00
|
|
|
|
2018-09-19 00:37:16 +00:00
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
@implementation AppDelegate
|
2018-06-30 13:10:06 +00:00
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
- (void) awakeFromNib {
|
2018-06-30 13:10:06 +00:00
|
|
|
}
|
|
|
|
|
2018-09-20 02:38:44 +00:00
|
|
|
|
|
|
|
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
|
|
|
|
shouldPresentNotification:(NSUserNotification *)notification {
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
#ifdef __cplusplus
|
2018-06-30 13:10:06 +00:00
|
|
|
|
2018-07-24 16:26:40 +00:00
|
|
|
- (void)extractI2PBaseDir:(void(^)(BOOL success, NSError *error))completion
|
2018-07-13 09:11:46 +00:00
|
|
|
{
|
2018-09-19 00:37:16 +00:00
|
|
|
|
|
|
|
NSBundle *launcherBundle = [NSBundle mainBundle];
|
|
|
|
auto homeDir = RealHomeDirectory();
|
|
|
|
NSLog(@"Home directory is %s", homeDir);
|
|
|
|
|
|
|
|
std::string basePath(homeDir);
|
|
|
|
basePath.append("/Library/I2P");
|
|
|
|
auto jarResPath = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
|
|
|
|
NSLog(@"Trying to load launcher.jar from url = %@", jarResPath);
|
|
|
|
self.metaInfo.jarFile = jarResPath;
|
|
|
|
self.metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
|
|
|
|
|
|
|
|
NSParameterAssert(basePath.c_str());
|
2018-07-13 09:11:46 +00:00
|
|
|
NSError *error = NULL;
|
2018-09-18 15:39:32 +00:00
|
|
|
BOOL success = NO;
|
2018-07-13 09:11:46 +00:00
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
2018-09-19 00:37:16 +00:00
|
|
|
std::string basearg("-Di2p.dir.base=");
|
|
|
|
basearg += basePath;
|
|
|
|
|
|
|
|
std::string zippath("-Di2p.base.zip=");
|
|
|
|
zippath += [self.metaInfo.zipFile UTF8String];
|
|
|
|
|
|
|
|
std::string jarfile("-cp ");
|
|
|
|
jarfile += [self.metaInfo.jarFile UTF8String];
|
|
|
|
|
|
|
|
// Create directory
|
|
|
|
mkdir(basePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
|
|
|
|
|
2018-09-20 02:38:44 +00:00
|
|
|
auto cli = defaultFlagsForExtractorJob;
|
2018-09-19 00:37:16 +00:00
|
|
|
setenv("I2PBASE", basePath.c_str(), true);
|
|
|
|
setenv("ZIPPATH", zippath.c_str(), true);
|
|
|
|
//setenv("DYLD_LIBRARY_PATH",".:/usr/lib:/lib:/usr/local/lib", true);
|
|
|
|
|
|
|
|
cli.push_back(basearg);
|
|
|
|
cli.push_back(zippath);
|
|
|
|
cli.push_back(jarfile);
|
|
|
|
cli.push_back("net.i2p.launchers.BaseExtractor");
|
|
|
|
auto rs = [[RouterProcessStatus alloc] init];
|
|
|
|
NSString* jh = [rs getJavaHome];
|
|
|
|
if (jh != nil) {
|
|
|
|
NSLog(@"jh er %@", jh);
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString* newString = [NSString stringWithFormat:@"file://%@", rs.getJavaHome];
|
|
|
|
NSURL *baseURL = [NSURL fileURLWithPath:newString];
|
|
|
|
|
|
|
|
std::string execStr = std::string([rs.getJavaHome UTF8String]);
|
|
|
|
for_each(cli, [&execStr](std::string str){ execStr += std::string(" ") + str; });
|
|
|
|
|
|
|
|
NSLog(@"Trying cmd: %@", [NSString stringWithUTF8String:execStr.c_str()]);
|
|
|
|
try {
|
|
|
|
sendUserNotification(APP_IDSTR, @"Please hold on while we extract I2P. You'll get a new message once done!");
|
2018-07-13 09:11:46 +00:00
|
|
|
int extractStatus = Popen(execStr.c_str(), environment{{
|
2018-09-19 00:37:16 +00:00
|
|
|
{"ZIPPATH", zippath.c_str()},
|
|
|
|
{"I2PBASE", basePath.c_str()}
|
2018-07-13 09:11:46 +00:00
|
|
|
}}).wait();
|
|
|
|
NSLog(@"Extraction exit code %@",[NSString stringWithUTF8String:(std::to_string(extractStatus)).c_str()]);
|
|
|
|
if (extractStatus == 0)
|
|
|
|
{
|
2018-09-19 00:37:16 +00:00
|
|
|
//success = YES;
|
|
|
|
NSLog(@"Time to detect I2P version in install directory");
|
|
|
|
[self.swiftRuntime findInstalledI2PVersion];
|
2018-07-13 09:11:46 +00:00
|
|
|
}
|
2018-09-19 00:37:16 +00:00
|
|
|
|
|
|
|
} catch (subprocess::OSError &err) {
|
|
|
|
auto errMsg = [NSString stringWithUTF8String:err.what()];
|
|
|
|
//success = NO;
|
|
|
|
NSLog(@"Exception: %@", errMsg);
|
|
|
|
sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg]);
|
2018-07-13 09:11:46 +00:00
|
|
|
}
|
2018-09-19 00:37:16 +00:00
|
|
|
|
|
|
|
// All done. Assume success and error are already set.
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
//sendUserNotification(APP_IDSTR, @"Extraction complete!", self.contentImage);
|
|
|
|
if (completion) {
|
|
|
|
completion(success, error);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
} catch (OSError &err) {
|
|
|
|
auto errMsg = [NSString stringWithUTF8String:err.what()];
|
|
|
|
NSLog(@"Exception: %@", errMsg);
|
|
|
|
}
|
2018-07-13 09:11:46 +00:00
|
|
|
});
|
2018-09-19 00:37:16 +00:00
|
|
|
|
|
|
|
|
2018-07-13 09:11:46 +00:00
|
|
|
}
|
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
|
2018-06-30 13:10:06 +00:00
|
|
|
- (NSString *)userSelectJavaHome:(JvmListPtr)rawJvmList
|
|
|
|
{
|
|
|
|
NSString *appleScriptString = @"set jvmlist to {\"Newest\"";
|
|
|
|
for (auto item : *rawJvmList) {
|
|
|
|
auto str = strprintf(",\"%s\"", item->JVMName.c_str()).c_str();
|
|
|
|
NSString* tmp = [NSString stringWithUTF8String:str];
|
|
|
|
appleScriptString = [appleScriptString stringByAppendingString:tmp];
|
|
|
|
}
|
|
|
|
appleScriptString = [appleScriptString stringByAppendingString:@"}\nchoose from list jvmlist\n"];
|
|
|
|
NSAppleScript *theScript = [[NSAppleScript alloc] initWithSource:appleScriptString];
|
|
|
|
NSDictionary *theError = nil;
|
|
|
|
NSString* userResult = [[theScript executeAndReturnError: &theError] stringValue];
|
|
|
|
NSLog(@"User choosed %@.\n", userResult);
|
|
|
|
if (theError != nil)
|
|
|
|
{
|
|
|
|
NSLog(@"Error: %@.\n", theError);
|
|
|
|
}
|
|
|
|
return userResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setApplicationDefaultPreferences {
|
|
|
|
auto defaultJVMHome = check_output({"/usr/libexec/java_home","-v",DEF_MIN_JVM_VER});
|
|
|
|
auto tmpStdStr = std::string(defaultJVMHome.buf.data());
|
|
|
|
trim(tmpStdStr);
|
|
|
|
auto cfDefaultHome = CFStringCreateWithCString(NULL, const_cast<const char *>(tmpStdStr.c_str()), kCFStringEncodingUTF8);
|
2018-09-20 02:38:44 +00:00
|
|
|
[self.userPreferences registerDefaults:@{
|
2018-06-30 13:10:06 +00:00
|
|
|
@"javaHome" : (NSString *)cfDefaultHome,
|
|
|
|
@"lastI2PVersion" : (NSString *)CFSTR(DEF_I2P_VERSION),
|
2018-09-18 15:39:32 +00:00
|
|
|
@"enableLogging": @YES,
|
|
|
|
@"enableVerboseLogging": @YES,
|
|
|
|
@"autoStartRouter": @YES,
|
2018-07-24 16:26:40 +00:00
|
|
|
@"i2pBaseDirectory": (NSString *)CFStringCreateWithCString(NULL, const_cast<const char *>(getDefaultBaseDir().c_str()), kCFStringEncodingUTF8)
|
2018-09-20 02:38:44 +00:00
|
|
|
}];
|
2018-09-19 00:37:16 +00:00
|
|
|
if (self.enableVerboseLogging) NSLog(@"Default JVM home preference set to: %@", cfDefaultHome);
|
2018-06-30 13:10:06 +00:00
|
|
|
|
|
|
|
auto dict = [self.userPreferences dictionaryRepresentation];
|
|
|
|
[self.userPreferences setPersistentDomain:dict forName:NSAPPDOMAIN];
|
|
|
|
|
|
|
|
CFPreferencesSetMultiple((CFDictionaryRef)dict, NULL, CFAPPDOMAIN, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
|
|
|
|
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
|
2018-07-13 06:30:16 +00:00
|
|
|
|
2018-06-30 13:10:06 +00:00
|
|
|
if (self.enableVerboseLogging) NSLog(@"Default preferences stored!");
|
2018-09-20 02:38:44 +00:00
|
|
|
#endif
|
2018-06-30 13:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-20 02:38:44 +00:00
|
|
|
|
|
|
|
|
2018-06-30 13:10:06 +00:00
|
|
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
|
|
|
// Init application here
|
2018-09-18 15:39:32 +00:00
|
|
|
|
2018-09-19 00:37:16 +00:00
|
|
|
self.swiftRuntime = [[SwiftMainDelegate alloc] init];
|
2018-09-18 15:39:32 +00:00
|
|
|
|
2018-09-20 02:38:44 +00:00
|
|
|
// This setup allows the application to send notifications
|
2018-07-13 06:30:16 +00:00
|
|
|
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
|
2018-09-20 02:38:44 +00:00
|
|
|
|
|
|
|
|
2018-06-30 13:10:06 +00:00
|
|
|
// Start with user preferences
|
|
|
|
self.userPreferences = [NSUserDefaults standardUserDefaults];
|
|
|
|
[self setApplicationDefaultPreferences];
|
|
|
|
self.enableLogging = [self.userPreferences boolForKey:@"enableLogging"];
|
|
|
|
self.enableVerboseLogging = [self.userPreferences boolForKey:@"enableVerboseLogging"];
|
|
|
|
// In case we are unbundled, make us a proper UI application
|
|
|
|
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
|
|
|
|
[NSApp activateIgnoringOtherApps:YES];
|
|
|
|
|
|
|
|
|
2018-09-20 02:38:44 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
//gRawJvmList = std::make_shared<std::list<JvmVersionPtr> >(std::list<JvmVersionPtr>());
|
2018-06-30 13:10:06 +00:00
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
RouterProcessStatus* routerStatus = [[RouterProcessStatus alloc] init];
|
2018-07-24 16:26:40 +00:00
|
|
|
std::string i2pBaseDir(getDefaultBaseDir());
|
2018-09-20 02:38:44 +00:00
|
|
|
NSLog(@"i2pBaseDir = %s", i2pBaseDir.c_str());
|
2018-09-18 15:39:32 +00:00
|
|
|
bool shouldAutoStartRouter = false;
|
2018-09-20 02:38:44 +00:00
|
|
|
|
|
|
|
// TODO: Make the port a setting which defaults to 7657
|
2018-09-18 15:39:32 +00:00
|
|
|
if (port_check(7657) != 0)
|
2018-07-24 16:26:40 +00:00
|
|
|
{
|
|
|
|
NSLog(@"Seems i2p is already running - I will not start the router (port 7657 is in use..)");
|
2018-09-18 15:39:32 +00:00
|
|
|
sendUserNotification(@"Found already running router", @"TCP port 7657 seem to be used by another i2p instance.");
|
|
|
|
|
|
|
|
[routerStatus setRouterStatus: true];
|
|
|
|
[routerStatus setRouterRanByUs: false];
|
2018-07-24 16:26:40 +00:00
|
|
|
return;
|
2018-09-18 15:39:32 +00:00
|
|
|
} else {
|
|
|
|
shouldAutoStartRouter = true;
|
2018-07-24 16:26:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (self.enableVerboseLogging) NSLog(@"processinfo %@", [[NSProcessInfo processInfo] arguments]);
|
|
|
|
|
2018-06-30 13:10:06 +00:00
|
|
|
|
2018-09-19 00:37:16 +00:00
|
|
|
NSBundle *launcherBundle = [NSBundle mainBundle];
|
|
|
|
|
2018-09-20 02:38:44 +00:00
|
|
|
// Helper object to hold statefull path information
|
2018-07-24 16:26:40 +00:00
|
|
|
self.metaInfo = [[ExtractMetaInfo alloc] init];
|
2018-09-20 02:38:44 +00:00
|
|
|
self.metaInfo.i2pBase = [NSString stringWithUTF8String:i2pBaseDir.c_str()];
|
|
|
|
self.metaInfo.javaBinary = [routerStatus getJavaHome];
|
2018-07-24 16:26:40 +00:00
|
|
|
self.metaInfo.jarFile = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
|
|
|
|
self.metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
|
2018-06-30 13:10:06 +00:00
|
|
|
|
2018-07-13 06:30:16 +00:00
|
|
|
std::string basearg("-Di2p.dir.base=");
|
2018-09-20 02:38:44 +00:00
|
|
|
basearg += i2pBaseDir;
|
2018-07-13 06:30:16 +00:00
|
|
|
|
|
|
|
std::string jarfile("-cp ");
|
2018-07-24 16:26:40 +00:00
|
|
|
jarfile += [self.metaInfo.zipFile UTF8String];
|
2018-09-19 00:37:16 +00:00
|
|
|
|
2018-09-20 02:38:44 +00:00
|
|
|
auto sBridge = [[SBridge alloc] init];
|
|
|
|
|
|
|
|
// Initialize the Swift environment (the UI components)
|
|
|
|
[self.swiftRuntime applicationDidFinishLaunching];
|
2018-07-13 06:30:16 +00:00
|
|
|
|
|
|
|
struct stat sb;
|
2018-07-24 16:26:40 +00:00
|
|
|
if ( !(stat(i2pBaseDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) )
|
2018-07-13 06:30:16 +00:00
|
|
|
{
|
|
|
|
// I2P is not extracted.
|
2018-07-13 09:11:46 +00:00
|
|
|
if (self.enableVerboseLogging) NSLog(@"I2P Directory don't exists!");
|
2018-07-13 06:30:16 +00:00
|
|
|
|
2018-09-20 02:38:44 +00:00
|
|
|
// Might be hard to read if you're not used to Objective-C
|
|
|
|
// But this is a "function call" that contains a "callback function"
|
2018-07-24 16:26:40 +00:00
|
|
|
[self extractI2PBaseDir:^(BOOL success, NSError *error) {
|
2018-09-18 15:39:32 +00:00
|
|
|
sendUserNotification(@"I2P is done extracting", @"I2P is now installed and ready to run!");
|
|
|
|
NSLog(@"Done extracting I2P");
|
2018-09-20 02:38:44 +00:00
|
|
|
|
|
|
|
if (shouldAutoStartRouter) {
|
|
|
|
[sBridge startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
|
|
|
|
[routerStatus setRouterRanByUs: true];
|
|
|
|
}
|
2018-07-13 09:11:46 +00:00
|
|
|
}];
|
2018-07-13 06:30:16 +00:00
|
|
|
|
|
|
|
} else {
|
2018-09-20 02:38:44 +00:00
|
|
|
// I2P was already found extracted
|
|
|
|
|
|
|
|
if (shouldAutoStartRouter) {
|
|
|
|
[sBridge startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
|
|
|
|
[routerStatus setRouterRanByUs: true];
|
|
|
|
}
|
2018-07-13 06:30:16 +00:00
|
|
|
}
|
2018-09-19 00:37:16 +00:00
|
|
|
|
2018-09-18 15:39:32 +00:00
|
|
|
#endif
|
2018-06-30 13:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* Exit sequence
|
|
|
|
*
|
|
|
|
**/
|
|
|
|
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
|
|
|
// Tear down here
|
|
|
|
NSString *string = @"applicationWillTerminate executed";
|
|
|
|
NSLog(@"%@", string);
|
|
|
|
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* wrapper for main */
|
|
|
|
- (AppDelegate *)initWithArgc:(int)argc argv:(const char **)argv {
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, const char **argv)
|
|
|
|
{
|
|
|
|
NSApplication *app = [NSApplication sharedApplication];
|
|
|
|
|
2018-09-19 00:37:16 +00:00
|
|
|
AppDelegate *appDelegate = [[AppDelegate alloc] initWithArgc:argc argv:argv];
|
|
|
|
app.delegate = appDelegate;
|
2018-09-20 02:38:44 +00:00
|
|
|
auto mainBundle = [NSBundle mainBundle];
|
|
|
|
NSString* stringNameBundle = [mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey];
|
|
|
|
if ([[NSRunningApplication runningApplicationsWithBundleIdentifier:[mainBundle bundleIdentifier]] count] > 1) {
|
|
|
|
[[NSAlert alertWithMessageText:[NSString stringWithFormat:@"Another copy of %@ is already running.",stringNameBundle]
|
|
|
|
defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"This copy will now quit."] runModal];
|
|
|
|
|
|
|
|
[NSApp terminate:nil];
|
|
|
|
}
|
2018-06-30 13:10:06 +00:00
|
|
|
[NSBundle loadNibNamed:@"I2Launcher" owner:NSApp];
|
|
|
|
|
|
|
|
[NSApp run];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|