merge of 'dba1ad61c390f95055923ae1fb35e60552f617c6'

and 'f84ff8b356783cf12619b83a8104e55fe76a7411'
This commit is contained in:
zzz
2018-09-22 12:11:43 +00:00
23 changed files with 505 additions and 725 deletions

View File

@@ -73,3 +73,15 @@ sloccount.sc
# IDEA
\.iml$
# Meeh stuff
target/scala-2.12
target/streams
project/target
launchers/macosx/project/project/target
launchers/macosx/I2PLauncher.xcodeproj/project.xcworkspace/xcuserdata
launchers/macosx/I2PLauncher.xcodeproj/xcuserdata
launchers/macosx/I2PLauncher.xcworkspace/xcuserdata
launchers/macosx/I2PLauncher.app
launchers/macosx/target

View File

@@ -5,11 +5,18 @@
#include <string.h>
#include <memory.h>
#ifdef __cplusplus
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <assert.h>
#endif
#include <Cocoa/Cocoa.h>
#include "SBridge.h"
#include "RouterTask.h"
#include "JavaHelper.h"
#define DEF_I2P_VERSION "0.9.36"
@@ -27,18 +34,34 @@
@class ExtractMetaInfo;
@interface ExtractMetaInfo : NSObject
@property (copy) NSString* i2pBase;
@property (copy) NSString* javaBinary;
@property (copy) NSString* zipFile;
@property (copy) NSString* jarFile;
@end
#ifdef __cplusplus
#include "JavaHelper.h"
inline void sendUserNotification(NSString* title, NSString* informativeText, NSImage* contentImage = NULL, bool makeSound = false) {
#ifdef __cplusplus
inline const char* RealHomeDirectory() {
struct passwd *pw = getpwuid(getuid());
assert(pw);
return pw->pw_dir;
}
inline std::string getDefaultBaseDir()
{
// Figure out base directory
auto homeDir = RealHomeDirectory();
const char* pathFromHome = "%s/Library/I2P";
char buffer[strlen(homeDir)+strlen(pathFromHome)];
sprintf(buffer, pathFromHome, homeDir);
std::string i2pBaseDir(buffer);
return i2pBaseDir;
}
inline void sendUserNotification(NSString* title, NSString* informativeText, bool makeSound = false) {
NSUserNotification *userNotification = [[NSUserNotification alloc] init];
userNotification.title = title;
@@ -55,32 +78,9 @@ inline void sendUserNotification(NSString* title, NSString* informativeText, NSI
[[NSUserNotificationCenter defaultUserNotificationCenter] scheduleNotification:userNotification];
};
using maybeAnRouterRunner = I2PRouterTask*;
std::vector<std::string> buildClassPath(std::string basePath);
extern JvmListSharedPtr gRawJvmList;
// DO NOT ACCESS THIS GLOBAL VARIABLE DIRECTLY.
static std::mutex globalRouterStatusMutex;
static maybeAnRouterRunner globalRouterStatus = maybeAnRouterRunner{};
static bool isRuterRunning = false;
maybeAnRouterRunner getGlobalRouterObject();
void setGlobalRouterObject(I2PRouterTask* newRouter);
bool getGlobalRouterIsRunning();
void setGlobalRouterIsRunning(bool running);
#include "SBridge.h"
#endif
@class MenuBarCtrl;
@interface AppDelegate : NSObject <NSUserNotificationCenterDelegate, NSApplicationDelegate> {
@public
//NSImageView *imageCell;
}
@interface AppDelegate : NSObject <NSUserNotificationCenterDelegate, NSApplicationDelegate>
@property BOOL enableLogging;
@property BOOL enableVerboseLogging;
@property (assign) SwiftMainDelegate *swiftRuntime;
@@ -93,12 +93,7 @@ void setGlobalRouterIsRunning(bool running);
- (void) applicationDidFinishLaunching:(NSNotification *)aNotification;
- (void) applicationWillTerminate:(NSNotification *)aNotification;
- (void) setApplicationDefaultPreferences;
- (void) userChooseJavaHome;
- (AppDelegate *) initWithArgc:(int)argc argv:(const char **)argv;
#ifdef __cplusplus
- (void) startupI2PRouter;
- (NSString *) userSelectJavaHome:(JvmListPtr)rawJvmList;
#endif
- (BOOL) userNotificationCenter:(NSUserNotificationCenter *)center
shouldPresentNotification:(NSUserNotification *)notification;
@end

View File

@@ -0,0 +1,15 @@
//
// Deployer.h
// I2PLauncher
//
// Created by Mikal Villa on 19/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSObject ()
@end

View File

@@ -0,0 +1,13 @@
//
// Deployer.m
// I2PLauncher
//
// Created by Mikal Villa on 19/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Deployer.h"

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 47;
objects = {
/* Begin PBXBuildFile section */
@@ -14,7 +14,6 @@
BF1EFA41215141110014EB07 /* RouterTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = BF1EFA3E215141100014EB07 /* RouterTask.mm */; };
BF1EFA47215141640014EB07 /* base.zip in Resources */ = {isa = PBXBuildFile; fileRef = BF1EFA44215141630014EB07 /* base.zip */; };
BF1EFA48215141640014EB07 /* ItoopieTransparent.png in Resources */ = {isa = PBXBuildFile; fileRef = BF1EFA45215141640014EB07 /* ItoopieTransparent.png */; };
BF1EFA4A215141CD0014EB07 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF5061932113C6ED0014EB07 /* NetworkExtension.framework */; };
BF5061702113C48E0014EB07 /* I2PLauncher.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = BF50616E2113C48E0014EB07 /* I2PLauncher.xcdatamodeld */; };
BF5061722113C4900014EB07 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF5061712113C4900014EB07 /* Assets.xcassets */; };
BF5061752113C4900014EB07 /* UserInterfaces.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF5061732113C4900014EB07 /* UserInterfaces.xib */; };
@@ -25,7 +24,12 @@
BF53150D2150CE310014EB07 /* DateTimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF53150C2150CE310014EB07 /* DateTimeUtils.swift */; };
BF5315132150EB510014EB07 /* RouterProcessStatus+ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5315122150EB510014EB07 /* RouterProcessStatus+ObjectiveC.swift */; };
BF531515215105B40014EB07 /* LogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF531514215105B40014EB07 /* LogViewController.swift */; };
BF650CA92152AC7D0014EB07 /* bumpInfoPlist.sh in Resources */ = {isa = PBXBuildFile; fileRef = BF650CA52152AC7D0014EB07 /* bumpInfoPlist.sh */; };
BF650CAA2152AC7D0014EB07 /* dmgconfig.py in Resources */ = {isa = PBXBuildFile; fileRef = BF650CA62152AC7D0014EB07 /* dmgconfig.py */; };
BF650CAB2152AC7D0014EB07 /* Deployer.m in Sources */ = {isa = PBXBuildFile; fileRef = BF650CA72152AC7D0014EB07 /* Deployer.m */; };
BF7506CB21509CFD0014EB07 /* RouterProcessStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF7506CA21509CFD0014EB07 /* RouterProcessStatus.swift */; };
BF86541321515CA00014EB07 /* launcher.jar in Resources */ = {isa = PBXBuildFile; fileRef = BF1EFA46215141640014EB07 /* launcher.jar */; };
BF865417215182820014EB07 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF865416215182820014EB07 /* Foundation.framework */; };
BFBDCAE9215040670014EB07 /* Subprocess.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBDCAE8215040670014EB07 /* Subprocess.swift */; };
BFBDCAEB215041630014EB07 /* TaskPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBDCAEA215041630014EB07 /* TaskPipeline.swift */; };
BFBDCAED215041C10014EB07 /* Subprocess+CompactAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBDCAEC215041C10014EB07 /* Subprocess+CompactAPI.swift */; };
@@ -39,6 +43,7 @@
BFBDCB0021505BEE0014EB07 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFBDCAFF21505BED0014EB07 /* AppKit.framework */; };
BFBDCB02215060190014EB07 /* DetectJava.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBDCB01215060190014EB07 /* DetectJava.swift */; };
BFBDCB04215060970014EB07 /* StatusBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBDCB03215060970014EB07 /* StatusBarController.swift */; };
BFE1CBAD2151908F0014EB07 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFE1CBAC2151908F0014EB07 /* CoreFoundation.framework */; };
BFF4581C213C48EA0014EB07 /* EventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF4581B213C48EA0014EB07 /* EventMonitor.swift */; };
/* End PBXBuildFile section */
@@ -48,7 +53,6 @@
BF1EFA38215140E60014EB07 /* SBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBridge.h; sourceTree = SOURCE_ROOT; };
BF1EFA39215140E60014EB07 /* SBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SBridge.mm; sourceTree = SOURCE_ROOT; };
BF1EFA3B215141100014EB07 /* RouterTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RouterTask.h; sourceTree = SOURCE_ROOT; };
BF1EFA3C215141100014EB07 /* JavaHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaHelper.h; sourceTree = SOURCE_ROOT; };
BF1EFA3D215141100014EB07 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = SOURCE_ROOT; };
BF1EFA3E215141100014EB07 /* RouterTask.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RouterTask.mm; sourceTree = SOURCE_ROOT; };
BF1EFA3F215141110014EB07 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = SOURCE_ROOT; };
@@ -62,7 +66,6 @@
BF5061742113C4900014EB07 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UserInterfaces.xib; sourceTree = "<group>"; };
BF5061762113C4900014EB07 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BF5061792113C4900014EB07 /* I2PLauncher.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = I2PLauncher.entitlements; sourceTree = "<group>"; };
BF5061932113C6ED0014EB07 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
BF5061952113C84E0014EB07 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
BF5315062150C55B0014EB07 /* RouterRunner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterRunner.swift; sourceTree = "<group>"; };
BF5315082150C6760014EB07 /* RouterDeployer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterDeployer.swift; sourceTree = "<group>"; };
@@ -70,7 +73,13 @@
BF53150C2150CE310014EB07 /* DateTimeUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeUtils.swift; sourceTree = "<group>"; };
BF5315122150EB510014EB07 /* RouterProcessStatus+ObjectiveC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RouterProcessStatus+ObjectiveC.swift"; sourceTree = "<group>"; };
BF531514215105B40014EB07 /* LogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewController.swift; sourceTree = "<group>"; };
BF650CA52152AC7D0014EB07 /* bumpInfoPlist.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = bumpInfoPlist.sh; sourceTree = SOURCE_ROOT; };
BF650CA62152AC7D0014EB07 /* dmgconfig.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = dmgconfig.py; sourceTree = SOURCE_ROOT; };
BF650CA72152AC7D0014EB07 /* Deployer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Deployer.m; sourceTree = SOURCE_ROOT; };
BF650CA82152AC7D0014EB07 /* Deployer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Deployer.h; sourceTree = SOURCE_ROOT; };
BF7506CA21509CFD0014EB07 /* RouterProcessStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterProcessStatus.swift; sourceTree = "<group>"; };
BF865414215180F60014EB07 /* libswiftDarwin.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftDarwin.tbd; path = System/Library/PrivateFrameworks/Swift/libswiftDarwin.tbd; sourceTree = SDKROOT; };
BF865416215182820014EB07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
BFBDCAE8215040670014EB07 /* Subprocess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subprocess.swift; sourceTree = "<group>"; };
BFBDCAEA215041630014EB07 /* TaskPipeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskPipeline.swift; sourceTree = "<group>"; };
BFBDCAEC215041C10014EB07 /* Subprocess+CompactAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Subprocess+CompactAPI.swift"; sourceTree = "<group>"; };
@@ -85,6 +94,7 @@
BFBDCAFF21505BED0014EB07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
BFBDCB01215060190014EB07 /* DetectJava.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectJava.swift; sourceTree = "<group>"; };
BFBDCB03215060970014EB07 /* StatusBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBarController.swift; sourceTree = "<group>"; };
BFE1CBAC2151908F0014EB07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
BFF45818213C428E0014EB07 /* I2PLauncher-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "I2PLauncher-Bridging-Header.h"; sourceTree = "<group>"; };
BFF4581B213C48EA0014EB07 /* EventMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventMonitor.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -94,7 +104,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
BF1EFA4A215141CD0014EB07 /* NetworkExtension.framework in Frameworks */,
BFE1CBAD2151908F0014EB07 /* CoreFoundation.framework in Frameworks */,
BF865417215182820014EB07 /* Foundation.framework in Frameworks */,
BFBDCB0021505BEE0014EB07 /* AppKit.framework in Frameworks */,
BF5061962113C84E0014EB07 /* Cocoa.framework in Frameworks */,
);
@@ -150,9 +161,12 @@
BF50616A2113C48E0014EB07 /* I2PLauncher */ = {
isa = PBXGroup;
children = (
BF650CA52152AC7D0014EB07 /* bumpInfoPlist.sh */,
BF650CA82152AC7D0014EB07 /* Deployer.h */,
BF650CA72152AC7D0014EB07 /* Deployer.m */,
BF650CA62152AC7D0014EB07 /* dmgconfig.py */,
BF1EFA42215141220014EB07 /* include */,
BF1EFA3F215141110014EB07 /* AppDelegate.h */,
BF1EFA3C215141100014EB07 /* JavaHelper.h */,
BF1EFA3D215141100014EB07 /* main.mm */,
BF1EFA3B215141100014EB07 /* RouterTask.h */,
BF1EFA3E215141100014EB07 /* RouterTask.mm */,
@@ -177,9 +191,11 @@
BF5061922113C6ED0014EB07 /* Frameworks */ = {
isa = PBXGroup;
children = (
BFE1CBAC2151908F0014EB07 /* CoreFoundation.framework */,
BF865416215182820014EB07 /* Foundation.framework */,
BF865414215180F60014EB07 /* libswiftDarwin.tbd */,
BFBDCAFF21505BED0014EB07 /* AppKit.framework */,
BF5061952113C84E0014EB07 /* Cocoa.framework */,
BF5061932113C6ED0014EB07 /* NetworkExtension.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -236,15 +252,20 @@
BF5061602113C48E0014EB07 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0940;
LastUpgradeCheck = 1000;
ORGANIZATIONNAME = "The I2P Project";
TargetAttributes = {
BF5061672113C48E0014EB07 = {
CreatedOnToolsVersion = 9.4.1;
DevelopmentTeam = W3C42P2LA8;
LastSwiftMigration = 0940;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.ApplicationGroups.Mac = {
enabled = 0;
};
com.apple.NetworkExtensions = {
enabled = 1;
enabled = 0;
};
com.apple.Sandbox = {
enabled = 0;
@@ -254,7 +275,7 @@
};
};
buildConfigurationList = BF5061632113C48E0014EB07 /* Build configuration list for PBXProject "I2PLauncher" */;
compatibilityVersion = "Xcode 9.3";
compatibilityVersion = "Xcode 6.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -276,6 +297,9 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BF86541321515CA00014EB07 /* launcher.jar in Resources */,
BF650CAA2152AC7D0014EB07 /* dmgconfig.py in Resources */,
BF650CA92152AC7D0014EB07 /* bumpInfoPlist.sh in Resources */,
BF07789721506C810014EB07 /* Storyboard.storyboard in Resources */,
BF5061722113C4900014EB07 /* Assets.xcassets in Resources */,
BF5061752113C4900014EB07 /* UserInterfaces.xib in Resources */,
@@ -298,7 +322,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Run from launchers/macosx\nexport BUILDDIR=$(pwd)\ncd ../..\nant preppkg-osx\ncd pkg-temp\nrm -f ../base.zip\nzip -r7 ../base.zip *\ncp ../base.zip $BUILDDIR\ncd $BUILDDIR\n\n\n\n";
shellScript = "# Run from launchers/macosx\nexport BUILDDIR=$(pwd)\ncd ..\nsbt macosx:assembly\ncd ..\nant preppkg-osx\ncd pkg-temp\nrm -f ../base.zip\nzip -r -v -9 ../base.zip *\ncp ../base.zip $BUILDDIR/base.zip\ncd $BUILDDIR\ncp $BUILDDIR/target/scala-2.11/routerLauncher-assembly-0.1.0-SNAPSHOT.jar $BUILDDIR/launcher.jar\n\n\n\n";
};
/* End PBXShellScriptBuildPhase section */
@@ -320,6 +344,7 @@
BFBDCAED215041C10014EB07 /* Subprocess+CompactAPI.swift in Sources */,
BFBDCB02215060190014EB07 /* DetectJava.swift in Sources */,
BF07789E21506D2B0014EB07 /* PopoverViewController.swift in Sources */,
BF650CAB2152AC7D0014EB07 /* Deployer.m in Sources */,
BF1EFA40215141110014EB07 /* main.mm in Sources */,
BFBDCAF4215042670014EB07 /* AppleStuffExceptionHandler.m in Sources */,
BF531515215105B40014EB07 /* LogViewController.swift in Sources */,
@@ -358,7 +383,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
@@ -400,10 +425,10 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SDKROOT = macosx10.13;
};
name = Debug;
};
@@ -416,7 +441,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
@@ -452,80 +477,80 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SDKROOT = macosx10.13;
SWIFT_COMPILATION_MODE = wholemodule;
};
name = Release;
};
BF50617D2113C4900014EB07 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CODE_SIGN_ENTITLEMENTS = I2PLauncher/I2PLauncher.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = W3C42P2LA8;
GCC_C_LANGUAGE_STANDARD = gnu11;
FRAMEWORK_SEARCH_PATHS = (
/Library/Frameworks,
/System/Library/Frameworks,
);
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/include",
"$(SRCROOT)/include/neither",
);
INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = include;
INFOPLIST_FILE = I2PLauncher/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = net.i2p.launcher.I2PLauncher;
LD_NO_PIE = YES;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = net.i2p.bootstrap.macosx.I2PLauncher;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SWIFT_OBJC_BRIDGING_HEADER = "I2PLauncher/I2PLauncher-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
SYSTEM_HEADER_SEARCH_PATHS = "$(SRCROOT)/include/**";
USER_HEADER_SEARCH_PATHS = "";
};
name = Debug;
};
BF50617E2113C4900014EB07 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CODE_SIGN_ENTITLEMENTS = I2PLauncher/I2PLauncher.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = W3C42P2LA8;
GCC_C_LANGUAGE_STANDARD = gnu11;
FRAMEWORK_SEARCH_PATHS = (
/Library/Frameworks,
/System/Library/Frameworks,
);
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/include",
"$(SRCROOT)/include/neither",
);
INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES = include;
INFOPLIST_FILE = I2PLauncher/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.10;
PRODUCT_BUNDLE_IDENTIFIER = net.i2p.launcher.I2PLauncher;
LD_NO_PIE = YES;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_BUNDLE_IDENTIFIER = net.i2p.bootstrap.macosx.I2PLauncher;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SWIFT_OBJC_BRIDGING_HEADER = "I2PLauncher/I2PLauncher-Bridging-Header.h";
SWIFT_VERSION = 3.0;
SYSTEM_HEADER_SEARCH_PATHS = "$(SRCROOT)/include/**";
USER_HEADER_SEARCH_PATHS = "";
};
name = Release;
};

View File

@@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:RouterService/RouterService.xcodeproj">
</FileRef>
<FileRef
location = "group:I2PLauncher.xcodeproj">
</FileRef>

View File

@@ -34,7 +34,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>3</string>
<string>4</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
@@ -53,5 +53,7 @@
<array>
<dict/>
</array>
<key>SUFeedURL</key>
<string>http://i2browser.i2p/updates/v1/appcast.xml</string>
</dict>
</plist>

View File

@@ -13,18 +13,19 @@ import Cocoa
//let statusItem = NSStatusBar.system().statusItem(withLength: NSSquareStatusItemLength )
let statusBarController = StatusBarController()
let javaDetector = DetectJava()
static let javaDetector = DetectJava()
static let objCBridge = SBridge()
override init() {
super.init()
self.javaDetector.findIt()
if (!javaDetector.isJavaFound()) {
print("Could not find java....")
terminate("No java..")
if (!SwiftMainDelegate.javaDetector.isJavaFound()) {
SwiftMainDelegate.javaDetector.findIt()
if (!SwiftMainDelegate.javaDetector.isJavaFound()) {
print("Could not find java....")
terminate("No java..")
}
}
let javaBinPath = self.javaDetector.javaHome
let javaBinPath = SwiftMainDelegate.javaDetector.javaHome
RouterProcessStatus.knownJavaBinPath = javaBinPath
print("Found java home = ", javaBinPath)
@@ -77,8 +78,6 @@ import Cocoa
var i2pPath = NSHomeDirectory()
i2pPath += "/Library/I2P"
//let javaBinPath = self.javaDetector.javaHome.replace(target: " ", withString: "\\ ")
let fileManager = FileManager()
var ok = ObjCBool(true)
let doesI2PDirExists = fileManager.fileExists(atPath: i2pPath, isDirectory: &ok)

View File

@@ -10,9 +10,9 @@ import Foundation
@objc class DetectJava : NSObject {
var hasJRE : Bool = false
var userWantJRE : Bool = false
var userAcceptOracleEULA : Bool = false
static var hasJRE : Bool = false
static var userWantJRE : Bool = false
static var userAcceptOracleEULA : Bool = false
override init() {
@@ -29,8 +29,9 @@ import Foundation
//Called after the change
didSet{
hasJRE = true
print("DetectJava.javaHome did change from "+oldValue+" to "+self.javaHome)
DetectJava.hasJRE = true
self.javaHome = self.javaHome.replace(target: "\n", withString: "").replace(target: "Internet Plug-Ins", withString: "Internet\\ Plug-Ins")
print("DetectJava.javaHome did change to "+self.javaHome)
}
};
private var testedEnv : Bool = false
@@ -50,25 +51,28 @@ import Foundation
*
**/
@objc func findIt() {
if (DetectJava.hasJRE) {
return
}
print("Start with checking environment variable")
self.checkJavaEnvironmentVariable()
if !(self.javaHome.isEmpty) {
RouterProcessStatus.knownJavaBinPath = Optional.some(self.javaHome)
hasJRE = true
DetectJava.hasJRE = true
return
}
print("Checking with the java_home util")
self.runJavaHomeCmd()
if !(self.javaHome.isEmpty) {
RouterProcessStatus.knownJavaBinPath = Optional.some(self.javaHome)
hasJRE = true
DetectJava.hasJRE = true
return
}
print("Checking default JRE install path")
self.checkDefaultJREPath()
if !(self.javaHome.isEmpty) {
RouterProcessStatus.knownJavaBinPath = Optional.some(self.javaHome)
hasJRE = true
DetectJava.hasJRE = true
return
}
}

View File

@@ -26,29 +26,29 @@ import AppKit
}
@objc func getRouterIsRunning() -> Bool {
if (RouterProcessStatus.isRouterRunning == Optional.none) {
return false;
} else {
let running: Bool = RouterProcessStatus.isRouterRunning
return running
}
return RouterProcessStatus.isRouterRunning
}
@objc func getJavaHome() -> String {
return RouterProcessStatus.knownJavaBinPath!
}
@objc func setJavaHome(_ home: String) {
NSLog("Setting known java to %s", home)
RouterProcessStatus.knownJavaBinPath = home
}
}
extension RouterProcessStatus {
static var isRouterRunning : Bool = false
static var isRouterChildProcess : Bool = false
static var routerVersion : String? = Optional.none
static var routerUptime : String? = Optional.none
static var routerUptime : String? = Optional.none{
//Called before the change
willSet(newValue){
print("RouterProcessStatus.routerUptime will change from ", (self.routerUptime ?? "nil"), " to "+(newValue ?? "nil"))
}
//Called after the change
didSet{
print("RouterProcessStatus.routerUptime did change to "+self.routerUptime!)
}
}
static var routerStartedAt : Date? = Optional.none
static var knownJavaBinPath : String? = Optional.none
static var i2pDirectoryPath : String = NSHomeDirectory() + "/Library/I2P"

View File

@@ -60,7 +60,7 @@ class PopoverViewController: NSViewController {
override func viewWillDraw() {
super.viewWillDraw()
if (RouterStatusView.instance == Optional.none) {
if (RouterStatusView.instance != nil) {
RouterStatusView.instance = self
}
self.setRouterStatusLabelText()
@@ -78,16 +78,13 @@ class PopoverViewController: NSViewController {
routerStartStopButton?.target = self
quickControlView?.needsDisplay = true
if (RouterProcessStatus.routerVersion == Optional.none) {
routerVersionLabel?.cell?.stringValue = "Router version: Still unknown"
// trigger a read to ensure values
let tmp = SwiftMainDelegate()
tmp.findInstalledI2PVersion()
if let version = RouterProcessStatus.routerVersion {
routerVersionLabel?.cell?.stringValue = "Router version: " + version
} else {
routerVersionLabel?.cell?.stringValue = "Router version: " + RouterProcessStatus.routerVersion!
routerVersionLabel?.cell?.stringValue = "Router version: Still unknown"
}
if (RouterProcessStatus.routerStartedAt != Optional.none) {
routerUptimeLabel?.cell?.stringValue = "Router has runned for " + DateTimeUtils.timeAgoSinceDate(date: NSDate(date: RouterProcessStatus.routerStartedAt!), numericDates: false)
if let routerStartTime = RouterProcessStatus.routerStartedAt {
routerUptimeLabel?.cell?.stringValue = "Router has runned for " + DateTimeUtils.timeAgoSinceDate(date: NSDate(date: routerStartTime), numericDates: false)
}
}

View File

@@ -9,7 +9,7 @@
<key>NSHumanReadableCopyright</key>
<string>Public Domain</string>
<key>CFBundleGetInfoString</key>
<string>0.9.35-experimental</string>
<string>0.9.36-experimental</string>
<key>CFBundleIconFile</key>
<string>images/AppIcon.icns</string>
<key>CFBundleIdentifier</key>

View File

@@ -1,167 +0,0 @@
#pragma once
#ifdef __cplusplus
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <Foundation/Foundation.h>
#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 "RouterTask.h"
#define DEF_MIN_JVM_VER "1.7+"
#include "include/strutil.hpp"
#include <functional>
#include <memory>
#include <list>
class JvmVersion
{
public:
std::string JVMName;
std::string JVMHomePath;
std::string JVMPlatformVersion;
inline const char * ToCString()
{
std::stringstream ss;
ss << "JvmVersion(name=" << JVMName.c_str() << ",version=";
ss << JVMPlatformVersion.c_str() << ",home=" << JVMHomePath.c_str() << ")";
std::string s = ss.str();
return s.c_str();
}
inline bool HasContent()
{
return (
std::strlen(JVMName.c_str()) > 0 &&
std::strlen(JVMHomePath.c_str()) > 0 &&
std::strlen(JVMPlatformVersion.c_str()) > 0
);
}
};
typedef std::shared_ptr<JvmVersion> JvmVersionPtr;
typedef std::shared_ptr<std::list<JvmVersionPtr> > JvmListPtr;
typedef std::shared_ptr<std::list<std::shared_ptr<JvmVersion> > > JvmListSharedPtr;
typedef void(^MenuBarControllerActionBlock)(BOOL active);
extern JvmListSharedPtr gRawJvmList;
class JvmHomeContext : public std::enable_shared_from_this<JvmHomeContext>
{
public:
inline void setJvm(JvmVersionPtr* current)
{
mCurrent = *current;
}
inline JvmListPtr getJvmList()
{
return gRawJvmList;
}
inline std::shared_ptr<JvmHomeContext> getContext()
{
return shared_from_this();
}
inline std::string getJavaHome()
{
if (mCurrent)
{
return mCurrent->JVMHomePath;
}
return gRawJvmList->back()->JVMHomePath;
}
private:
JvmVersionPtr mCurrent;
};
static void processJvmEntry (const void* key, const void* value, void* context) {
//CFShow(key);
//CFShow(value);
// The reason for using strprintf is to "force" a copy of the values,
// since local variables gets deleted once this function returns.
auto currentJvm = reinterpret_cast<JvmVersion*>(context);
if (CFEqual((CFStringRef)key,CFSTR("JVMName"))) {
auto strVal = extractString((CFStringRef)value);
currentJvm->JVMName = strprintf("%s",strVal.c_str());
}
if (CFEqual((CFStringRef)key,CFSTR("JVMHomePath"))) {
auto strVal = extractString((CFStringRef)value);
currentJvm->JVMHomePath = strprintf("%s",strVal.c_str());
}
if (CFEqual((CFStringRef)key,CFSTR("JVMPlatformVersion"))) {
auto strVal = extractString((CFStringRef)value);
currentJvm->JVMPlatformVersion = strprintf("%s",strVal.c_str());
}
}
static void processJvmPlistEntries (const void* item, void* context) {
CFDictionaryRef dict = CFDictionaryCreateCopy(kCFAllocatorDefault, (CFDictionaryRef)item);
JvmVersionPtr currentJvmPtr = std::shared_ptr<JvmVersion>(new JvmVersion());
struct CFunctional
{
static void applier(const void* key, const void* value, void* context){
// The reason for using strprintf is to "force" a copy of the values,
// since local variables gets deleted once this function returns.
auto currentJvm = static_cast<JvmVersion*>(context);
if (CFEqual((CFStringRef)key,CFSTR("JVMName"))) {
auto d = extractString((CFStringRef)value);
currentJvm->JVMName = trim_copy(d);
}
if (CFEqual((CFStringRef)key,CFSTR("JVMHomePath"))) {
auto d = extractString((CFStringRef)value);
currentJvm->JVMHomePath = trim_copy(d);
}
if (CFEqual((CFStringRef)key,CFSTR("JVMPlatformVersion"))) {
auto d = extractString((CFStringRef)value);
currentJvm->JVMPlatformVersion = trim_copy(d);
}
}
};
CFDictionaryApplyFunction(dict, CFunctional::applier, (void*)currentJvmPtr.get());
if (currentJvmPtr->HasContent())
{
printf("Found JVM: %s\n\n", currentJvmPtr->ToCString());
gRawJvmList->push_back(currentJvmPtr);
}
}
static void listAllJavaInstallsAvailable()
{
auto javaHomeRes = check_output({"/usr/libexec/java_home","-v",DEF_MIN_JVM_VER,"-X"});
CFDataRef javaHomes = CFDataCreate(NULL, (const UInt8 *)javaHomeRes.buf.data(), strlen(javaHomeRes.buf.data()));
CFPropertyListRef propertyList = CFPropertyListCreateWithData(kCFAllocatorDefault, javaHomes, kCFPropertyListImmutable, NULL, NULL);
auto jCount = CFArrayGetCount((CFArrayRef)propertyList);
CFArrayApplyFunction((CFArrayRef)propertyList, CFRangeMake(0, jCount), processJvmPlistEntries, NULL);
//CFShow(propertyList);
}
#endif

View File

@@ -1,9 +1,18 @@
# The Mac OS X Launcher
## Misc
**Note** this project is WIP, cause Meeh has yet to merge in Obj-C/Swift code for GUI stuff in OSX.
However, this is a thin wrapper launching both Mac OS X trayicon and the I2P router - and make them talk together.
More code will be merged in, it's just a f* mess which Meeh needs to clean up and move into repo.
`./fullBuild.sh` triggers Ant jobs and prepare the base.zip, as well as starting the ninja build.
## Howto build
You can both build the project from the Xcode UI or you can build it from command line.
An example build command:
`xcodebuild -target I2PLauncher -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk`

View File

@@ -2,48 +2,28 @@
#include <dispatch/dispatch.h>
#include <memory.h>
#include <string.h>
#include <Cocoa/Cocoa.h>
#import <AppKit/AppKit.h>
#ifdef __cplusplus
#include "include/subprocess.hpp"
#include <vector>
#include <string>
using namespace subprocess;
class JavaRunner;
const std::vector<NSString*> defaultStartupFlags {
@"-Xmx512M",
@"-Xms128m",
@"-Djava.awt.headless=true",
@"-Dwrapper.logfile=/tmp/router.log",
@"-Dwrapper.logfile.loglevel=DEBUG",
@"-Dwrapper.java.pidfile=/tmp/routerjvm.pid",
@"-Dwrapper.console.loglevel=DEBUG"
};
typedef std::function<void(void)> fp_t;
typedef std::function<void(JavaRunner *ptr)> fp_proc_t;
/**
*
* class JavaRunner
*
**/
class JavaRunner
{
public:
// copy fn
JavaRunner(std::string& javaBin, std::string& arguments, std::string& i2pBaseDir, const fp_proc_t& executingFn, const fp_t& cb);
~JavaRunner() = default;
static const std::vector<NSString*> defaultStartupFlags;
static const std::vector<std::string> defaultFlagsForExtractorJob;
void requestRouterShutdown();
std::future<int> execute();
std::shared_ptr<subprocess::Popen> javaProcess;
std::string javaBinaryPath;
std::string javaRouterArgs;
std::string execLine;
std::string _i2pBaseDir;
private:
const fp_proc_t& executingFn;
const fp_t& exitCallbackFn;
const std::vector<std::string> defaultFlagsForExtractorJob {
"-Xmx512M",
"-Xms128m",
"-Djava.awt.headless=true"
};
#endif

View File

@@ -9,6 +9,7 @@
#import "I2PLauncher-Swift.h"
#include "AppDelegate.h"
#endif
#include "include/PidWatcher.h"
#import <AppKit/AppKit.h>
@@ -49,28 +50,16 @@
name:NSFileHandleDataAvailableNotification
object:stdoutFileHandle];
[stdoutFileHandle waitForDataInBackgroundAndNotify];
[stdoutFileHandle waitForDataInBackgroundAndNotify];
[self.routerTask setTerminationHandler:^(NSTask* task) {
NSLog(@"termHandler triggered!");
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
[swiftRouterStatus setRouterStatus: true];
NSBundle *launcherBundle = [NSBundle mainBundle];
auto iconImage = [launcherBundle pathForResource:@"AppIcon" ofType:@"png"];
sendUserNotification(APP_IDSTR, @"I2P Router has stopped");
// Cleanup
self.isRouterRunning = NO;
}];
/*
self.readLogHandle = [self.processPipe fileHandleForReading];
NSData *inData = nil;
self.totalLogData = [[[NSMutableData alloc] init] autorelease];
while ((inData = [self.readLogHandle availableData]) &&
[inData length]) {
[self.totalLogData appendData:inData];
}
*/
[self.routerTask setTerminationHandler:^(NSTask* task) {
// Cleanup
NSLog(@"termHandler triggered!");
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
[swiftRouterStatus setRouterStatus: false];
[swiftRouterStatus setRouterRanByUs: false];
sendUserNotification(APP_IDSTR, @"I2P Router has stopped");
}];
return self;
}
@@ -93,80 +82,25 @@
- (int) execute
{
@try {
[self.routerTask launch];
watchPid([self.routerTask processIdentifier]);
self.isRouterRunning = YES;
return 1;
[self.routerTask launch];
watchPid([self.routerTask processIdentifier]);
self.isRouterRunning = YES;
return 1;
}
@catch (NSException *e)
{
NSLog(@"Expection occurred %@", [e reason]);
return 0;
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
[swiftRouterStatus setRouterStatus: false];
[swiftRouterStatus setRouterRanByUs: false];
sendUserNotification(@"An error occured, can't start the I2P Router", [e reason]);
return 0;
}
}
- (int) getPID
{
return [self.routerTask processIdentifier];
return [self.routerTask processIdentifier];
}
@end
#ifdef __cplusplus
const std::vector<NSString*> JavaRunner::defaultStartupFlags {
@"-Xmx512M",
@"-Xms128m",
@"-Djava.awt.headless=true",
@"-Dwrapper.logfile=/tmp/router.log",
@"-Dwrapper.logfile.loglevel=DEBUG",
@"-Dwrapper.java.pidfile=/tmp/routerjvm.pid",
@"-Dwrapper.console.loglevel=DEBUG"
};
const std::vector<std::string> JavaRunner::defaultFlagsForExtractorJob {
"-Xmx512M",
"-Xms128m",
"-Djava.awt.headless=true"
};
JavaRunner::JavaRunner(std::string& javaBin, std::string& arguments, std::string& i2pBaseDir, const fp_proc_t& execFn, const fp_t& cb)
: javaBinaryPath(javaBin), javaRouterArgs(arguments), _i2pBaseDir(i2pBaseDir), executingFn(execFn), exitCallbackFn(cb)
{
execLine = javaBinaryPath;
execLine += " " + std::string(javaRouterArgs.c_str());
printf("CLI: %s\n",execLine.c_str());
javaProcess = std::shared_ptr<Popen>(new Popen(execLine, environment{{
{"I2PBASE", _i2pBaseDir},
{"JAVA_OPTS", getenv("JAVA_OPTS")}
}}, defer_spawn{true}));
}
void JavaRunner::requestRouterShutdown()
{
// SIGHUP
javaProcess->kill(1);
}
std::future<int> JavaRunner::execute()
{
try {
auto executingFn = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
this->executingFn(this);
});
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), executingFn);
dispatch_block_wait(executingFn, DISPATCH_TIME_FOREVER);
// Here, the process is done executing.
printf("Finished executingFn - Runs callbackFn\n");
this->exitCallbackFn();
return std::async(std::launch::async, []{ return 0; });
} catch (std::exception* ex) {
printf("ERROR: %s\n", ex->what());
return std::async(std::launch::async, []{ return 1; });
}
}
#endif

View File

@@ -0,0 +1,60 @@
//
// SBridge.h
// I2PLauncher
//
// Created by Mikal Villa on 18/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#ifdef __cplusplus
#include <memory>
#include <future>
#include <glob.h>
#include <string>
#include <vector>
#include "include/fn.h"
std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir);
namespace osx {
inline void openUrl(NSString* url)
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString: url]];
}
}
inline std::vector<std::string> globVector(const std::string& pattern){
glob_t glob_result;
glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
std::vector<std::string> files;
for(unsigned int i=0;i<glob_result.gl_pathc;++i){
files.push_back(std::string(glob_result.gl_pathv[i]));
}
globfree(&glob_result);
return files;
}
inline std::string buildClassPathForObjC(std::string basePath)
{
NSBundle *launcherBundle = [NSBundle mainBundle];
auto jarList = globVector(basePath+std::string("/lib/*.jar"));
std::string classpathStrHead = "-classpath";
std::string classpathStr = "";
classpathStr += [[launcherBundle pathForResource:@"launcher" ofType:@"jar"] UTF8String];
std::string prefix(basePath);
prefix += "/lib/";
for_each(jarList, [&classpathStr](std::string str){ classpathStr += std::string(":") + str; });
return classpathStr;
}
#endif
@interface SBridge : NSObject
- (NSString*) buildClassPath:(NSString*)i2pPath;
- (void) startupI2PRouter:(NSString*)i2pRootPath javaBinPath:(NSString*)javaBinPath;
- (void) openUrl:(NSString*)url;
@end

133
launchers/macosx/SBridge.mm Normal file
View File

@@ -0,0 +1,133 @@
//
// SBridge.m
// I2PLauncher
//
// Created by Mikal Villa on 18/09/2018.
// Copyright © 2018 The I2P Project. All rights reserved.
//
#import "SBridge.h"
#ifdef __cplusplus
#include <functional>
#include <memory>
#include <glob.h>
#include <string>
#include <list>
#include <stdlib.h>
#include <future>
#include <vector>
#import <AppKit/AppKit.h>
#import "I2PLauncher-Swift.h"
#include "AppDelegate.h"
#include "include/fn.h"
std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir) {
@try {
RTaskOptions* options = [RTaskOptions alloc];
options.binPath = javaBin;
options.arguments = arguments;
options.i2pBaseDir = i2pBaseDir;
auto instance = [[I2PRouterTask alloc] initWithOptions: options];
[instance execute];
sendUserNotification(APP_IDSTR, @"The I2P router is starting up.");
auto pid = [instance getPID];
return std::async(std::launch::async, [&pid]{
return pid;
});
}
@catch (NSException *e)
{
auto errStr = [NSString stringWithFormat:@"Expection occurred %@",[e reason]];
NSLog(@"%@", errStr);
sendUserNotification(APP_IDSTR, errStr);
return std::async(std::launch::async, [&]{
return 0;
});
}
}
@implementation SBridge
- (void) openUrl:(NSString*)url
{
osx::openUrl(url);
}
- (NSString*) buildClassPath:(NSString*)i2pPath
{
const char * basePath = [i2pPath UTF8String];
auto jarList = buildClassPathForObjC(basePath);
const char * classpath = jarList.c_str();
NSLog(@"Classpath from ObjC = %s", classpath);
return [[NSString alloc] initWithUTF8String:classpath];
}
- (void)startupI2PRouter:(NSString*)i2pRootPath javaBinPath:(NSString*)javaBinPath
{
std::string basePath([i2pRootPath UTF8String]);
// Get paths
//NSBundle *launcherBundle = [NSBundle mainBundle];
auto classPathStr = buildClassPathForObjC(basePath);
RouterProcessStatus* routerStatus = [[RouterProcessStatus alloc] init];
try {
std::vector<NSString*> argList = {
@"-Xmx512M",
@"-Xms128m",
@"-Djava.awt.headless=true",
@"-Dwrapper.logfile=/tmp/router.log",
@"-Dwrapper.logfile.loglevel=DEBUG",
@"-Dwrapper.java.pidfile=/tmp/routerjvm.pid",
@"-Dwrapper.console.loglevel=DEBUG"
};
std::string baseDirArg("-Di2p.dir.base=");
baseDirArg += basePath;
std::string javaLibArg("-Djava.library.path=");
javaLibArg += basePath;
// TODO: pass this to JVM
//auto java_opts = getenv("JAVA_OPTS");
std::string cpString = std::string("-cp");
argList.push_back([NSString stringWithUTF8String:baseDirArg.c_str()]);
argList.push_back([NSString stringWithUTF8String:javaLibArg.c_str()]);
argList.push_back([NSString stringWithUTF8String:cpString.c_str()]);
argList.push_back([NSString stringWithUTF8String:classPathStr.c_str()]);
argList.push_back(@"net.i2p.router.Router");
auto javaBin = std::string([javaBinPath UTF8String]);
sendUserNotification(APP_IDSTR, @"I2P Router is starting up!");
auto nsJavaBin = javaBinPath;
auto nsBasePath = i2pRootPath;
NSArray* arrArguments = [NSArray arrayWithObjects:&argList[0] count:argList.size()];
// We don't really know yet, but per now a workaround
[routerStatus setRouterStatus: true];
NSLog(@"Trying to run command: %@", javaBinPath);
NSLog(@"With I2P Base dir: %@", i2pRootPath);
NSLog(@"And Arguments: %@", arrArguments);
startupRouter(nsJavaBin, arrArguments, nsBasePath);
} catch (std::exception &err) {
auto errMsg = [NSString stringWithUTF8String:err.what()];
NSLog(@"Exception: %@", errMsg);
sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg]);
[routerStatus setRouterStatus: false];
[routerStatus setRouterRanByUs: false];
}
}
@end
#endif

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd ../../..
ant preppkg-osx-only
cd pkg-temp
zip -r7 $DIR/base.zip *
echo "[+] Done building base.zip from ant's pkg-temp."
ninja appbundle

View File

@@ -53,16 +53,12 @@ inline std::string extractString(CFStringRef value)
}
}
using std::experimental::optional;
// Use CFStringRef instead of NSString*, otherwise disable ARC
inline optional<CFStringRef> optionalString(bool val) {
optional<CFStringRef> myOptString;
if(val) {
// Cast to corresponding CoreFoundation object
myOptString = (CFStringRef)@"String";
}
return myOptString;
inline bool replace(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = str.find(from);
if(start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
@@ -102,4 +98,22 @@ static inline std::string trim_copy(std::string s) {
return s;
}
#if __cplusplus > 201402L
using std::optional;
// Use CFStringRef instead of NSString*, otherwise disable ARC
inline optional<CFStringRef> optionalString(bool val) {
optional<CFStringRef> myOptString;
if(val) {
// Cast to corresponding CoreFoundation object
myOptString = (CFStringRef)@"String";
}
return myOptString;
}
#endif
#endif

View File

@@ -1,57 +0,0 @@
#ifndef NEITHER_TRAITS_HPP
#define NEITHER_TRAITS_HPP
namespace neither {
template<class L, class R>
struct Either;
template<class T>
struct Maybe;
template<class L,class...Xs>
auto isCopyable (L l, Xs...) -> L {
return l;
}
template<class L, class R>
auto ensureEither ( Either<L,R> const& e) -> Either<L,R> {
return e;
}
template<class L, class R>
auto ensureEither ( Either<L,R> && e) -> Either<L,R> {
return e;
}
template<class L, class R>
auto ensureEitherRight ( Either<L,R> const& e, R) -> Either<L, R> {
return e;
}
template<class L, class R>
auto ensureEitherRight ( Either<L,R>&& e, R&&) -> Either<L, R> {
return e;
}
template<class L, class R>
auto ensureEitherLeft ( Either<L,R> const& e, L) -> Either<L, R> {
return e;
}
template<class L, class R>
auto ensureEitherLeft ( Either<L,R>&& e, L&& ) -> Either<L, R> {
return e;
}
template<class T>
auto ensureMaybe ( Maybe<T> const& e) -> Maybe<T> {
return e;
}
}
#endif

View File

@@ -11,14 +11,6 @@
#import <Foundation/Foundation.h>
#import <Foundation/NSFileManager.h>
#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>
@@ -30,94 +22,43 @@
#include "AppDelegate.h"
#include "RouterTask.h"
#include "JavaHelper.h"
#include "include/fn.h"
#include "include/portcheck.h"
#import "SBridge.h"
#ifdef __cplusplus
#include <string>
#include "include/subprocess.hpp"
#include "include/strutil.hpp"
using namespace subprocess;
#endif
#define debug(format, ...) CFShow([NSString stringWithFormat:format, ## __VA_ARGS__]);
@interface AppDelegate () <NSUserNotificationCenterDelegate, NSApplicationDelegate>
@end
#ifdef __cplusplus
#import "SBridge.h"
JvmListSharedPtr gRawJvmList = nullptr;
#endif
@interface AppDelegate () <NSUserNotificationCenterDelegate, NSApplicationDelegate>
@end
#ifdef __cplusplus
maybeAnRouterRunner getGlobalRouterObject()
{
std::lock_guard<std::mutex> lock(globalRouterStatusMutex);
return globalRouterStatus; // Remember this might be nullptr now.
}
void setGlobalRouterObject(I2PRouterTask* newRouter)
{
std::lock_guard<std::mutex> lock(globalRouterStatusMutex);
globalRouterStatus = newRouter;
}
pthread_mutex_t mutex;
bool getGlobalRouterIsRunning()
{
pthread_mutex_lock(&mutex);
bool current = isRuterRunning;
pthread_mutex_unlock(&mutex);
return current;
}
void setGlobalRouterIsRunning(bool running)
{
pthread_mutex_lock(&mutex);
isRuterRunning = running;
pthread_mutex_unlock(&mutex);
}
#endif
@implementation ExtractMetaInfo : NSObject
@end
#ifdef __cplusplus
bool replace(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = str.find(from);
if(start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
#endif
@implementation AppDelegate
- (void) awakeFromNib {
}
#ifdef __cplusplus
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <assert.h>
#include "include/subprocess.hpp"
using namespace subprocess;
const char* RealHomeDirectory() {
struct passwd *pw = getpwuid(getuid());
assert(pw);
return pw->pw_dir;
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
shouldPresentNotification:(NSUserNotification *)notification {
return YES;
}
#ifdef __cplusplus
- (void)extractI2PBaseDir:(void(^)(BOOL success, NSError *error))completion
{
@@ -151,7 +92,7 @@ const char* RealHomeDirectory() {
// Create directory
mkdir(basePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
auto cli = JavaRunner::defaultFlagsForExtractorJob;
auto cli = defaultFlagsForExtractorJob;
setenv("I2PBASE", basePath.c_str(), true);
setenv("ZIPPATH", zippath.c_str(), true);
//setenv("DYLD_LIBRARY_PATH",".:/usr/lib:/lib:/usr/local/lib", true);
@@ -161,27 +102,9 @@ const char* RealHomeDirectory() {
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];
NSLog(@"MEEH URL PATH: %s", [baseURL fileSystemRepresentation]);
auto charCli = map(cli, [](std::string str){ return str.c_str(); });
std::string execStr = std::string([rs.getJavaHome UTF8String]);
// TODO: Cheap hack, make it better.
replace(execStr, "Internet Plug-Ins", "Internet\\ Plug-Ins");
replace(execStr, "\n", "");
NSLog(@"Java path1 = %s", execStr.c_str());
[rs setJavaHome: [NSString stringWithFormat:@"%s", execStr.c_str()]];
for_each(cli, [&execStr](std::string str){ execStr += std::string(" ") + str; });
//execStr = replace(execStr, "\\\\ ", "\\ ");
//NSLog(@"Java path2 = %s", execStr.c_str());
NSLog(@"Trying cmd: %@", [NSString stringWithUTF8String:execStr.c_str()]);
try {
@@ -193,9 +116,7 @@ const char* RealHomeDirectory() {
NSLog(@"Extraction exit code %@",[NSString stringWithUTF8String:(std::to_string(extractStatus)).c_str()]);
if (extractStatus == 0)
{
//success = YES;
NSLog(@"Time to detect I2P version in install directory");
[self.swiftRuntime findInstalledI2PVersion];
NSLog(@"Extraction complete!");
}
} catch (subprocess::OSError &err) {
@@ -207,7 +128,6 @@ const char* RealHomeDirectory() {
// 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);
}
@@ -219,79 +139,15 @@ const char* RealHomeDirectory() {
NSLog(@"Exception: %@", errMsg);
}
});
}
#endif
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
shouldPresentNotification:(NSUserNotification *)notification {
return YES;
}
#ifdef __cplusplus
inline std::string getDefaultBaseDir()
{
// Figure out base directory
const char* pathFromHome = "/Users/%s/Library/I2P";
auto username = getenv("USER");
char buffer[strlen(pathFromHome)+strlen(username)];
sprintf(buffer, pathFromHome, username);
std::string i2pBaseDir(buffer);
return i2pBaseDir;
}
- (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)userChooseJavaHome {
listAllJavaInstallsAvailable();
std::shared_ptr<JvmHomeContext> appContext = std::shared_ptr<JvmHomeContext>( new JvmHomeContext() );
for (auto item : *appContext->getJvmList()) {
printf("JVM %s (Version: %s, Directory: %s)\n", item->JVMName.c_str(), item->JVMPlatformVersion.c_str(), item->JVMHomePath.c_str());
}
JvmListPtr rawJvmList = appContext->getJvmList();
NSString * userJavaHome = [self userSelectJavaHome: rawJvmList];
// TODO: Add logic so user can set preferred JVM
}
#endif
- (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);
/*[self.userPreferences registerDefaults:@{
@"javaHome" : (NSString *)cfDefaultHome,
@"lastI2PVersion" : (NSString *)CFSTR(DEF_I2P_VERSION),
[self.userPreferences registerDefaults:@{
@"enableLogging": @YES,
@"enableVerboseLogging": @YES,
@"autoStartRouter": @YES,
@"i2pBaseDirectory": (NSString *)CFStringCreateWithCString(NULL, const_cast<const char *>(getDefaultBaseDir().c_str()), kCFStringEncodingUTF8)
}];*/
if (self.enableVerboseLogging) NSLog(@"Default JVM home preference set to: %@", cfDefaultHome);
}];
auto dict = [self.userPreferences dictionaryRepresentation];
[self.userPreferences setPersistentDomain:dict forName:NSAPPDOMAIN];
@@ -302,51 +158,36 @@ inline std::string getDefaultBaseDir()
if (self.enableVerboseLogging) NSLog(@"Default preferences stored!");
}
#endif
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Init application here
self.swiftRuntime = [[SwiftMainDelegate alloc] init];
// This setup allows the application to send notifications
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
// Start with user preferences
self.userPreferences = [NSUserDefaults standardUserDefaults];
[self setApplicationDefaultPreferences];
self.enableLogging = [self.userPreferences boolForKey:@"enableLogging"];
self.enableVerboseLogging = [self.userPreferences boolForKey:@"enableVerboseLogging"];
#ifdef __cplusplus
gRawJvmList = std::make_shared<std::list<JvmVersionPtr> >(std::list<JvmVersionPtr>());
#endif
// In case we are unbundled, make us a proper UI application
[NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
[NSApp activateIgnoringOtherApps:YES];
// TODO: Also check for new installations from time to time.
#ifdef __cplusplus
auto javaHomePref = [self.userPreferences stringForKey:@"javaHome"];
if (self.enableVerboseLogging)
{
NSLog(@"Java home from preferences: %@", javaHomePref);
}
if (self.enableVerboseLogging)
{
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
NSLog(@"Appdomain is: %@", appDomain);
}
NSLog(@"We should have started the statusbar object by now...");
RouterProcessStatus* routerStatus = [[RouterProcessStatus alloc] init];
std::string i2pBaseDir(getDefaultBaseDir());
auto pref = self.userPreferences;
NSLog(@"i2pBaseDir = %s", i2pBaseDir.c_str());
bool shouldAutoStartRouter = false;
// TODO: Make the port a setting which defaults to 7657
if (port_check(7657) != 0)
{
NSLog(@"Seems i2p is already running - I will not start the router (port 7657 is in use..)");
@@ -354,51 +195,32 @@ inline std::string getDefaultBaseDir()
[routerStatus setRouterStatus: true];
[routerStatus setRouterRanByUs: false];
return;
shouldAutoStartRouter = false;
} else {
shouldAutoStartRouter = true;
}
if (self.enableVerboseLogging) NSLog(@"processinfo %@", [[NSProcessInfo processInfo] arguments]);
auto getJavaBin = [&pref,&self]() -> std::string {
// Get Java home
/*NSString* val = @"";
val = [pref stringForKey:@"javaHome"];
if (val == NULL) val = @"";
if (self.enableVerboseLogging) NSLog(@"Javahome: %@", val);
auto javaHome = std::string([val UTF8String]);
//trim(javaHome); // Trim to remove endline
auto javaBin = std::string(javaHome);
javaBin += "/bin/java"; // Append java binary to path.
return javaBin;*/
DetectJava *dt = [[DetectJava alloc] init];
[dt findIt];
if ([dt isJavaFound]) {
return [dt.javaHome UTF8String];
} else {
throw new std::runtime_error("Java home fatal error");
}
};
NSBundle *launcherBundle = [NSBundle mainBundle];
auto sBridge = [[SBridge alloc] init];
auto jarResPath = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
NSLog(@"Trying to load launcher.jar from url = %@", jarResPath);
// Helper object to hold statefull path information
self.metaInfo = [[ExtractMetaInfo alloc] init];
//self.metaInfo.i2pBase = [NSString stringWithUTF8String:i2pBaseDir.c_str()];
self.metaInfo.javaBinary = [NSString stringWithUTF8String:getJavaBin().c_str()];
self.metaInfo.i2pBase = [NSString stringWithUTF8String:i2pBaseDir.c_str()];
self.metaInfo.javaBinary = [routerStatus getJavaHome];
self.metaInfo.jarFile = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
self.metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
std::string basearg("-Di2p.dir.base=");
//basearg += i2pBaseDir;
basearg += i2pBaseDir;
std::string jarfile("-cp ");
jarfile += [self.metaInfo.zipFile UTF8String];
// Initialize the Swift environment (the UI components)
[self.swiftRuntime applicationDidFinishLaunching];
struct stat sb;
if ( !(stat(i2pBaseDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) )
@@ -406,17 +228,29 @@ inline std::string getDefaultBaseDir()
// I2P is not extracted.
if (self.enableVerboseLogging) NSLog(@"I2P Directory don't exists!");
// Might be hard to read if you're not used to Objective-C
// But this is a "function call" that contains a "callback function"
[self extractI2PBaseDir:^(BOOL success, NSError *error) {
sendUserNotification(@"I2P is done extracting", @"I2P is now installed and ready to run!");
[self.swiftRuntime applicationDidFinishLaunching];
NSLog(@"Done extracting I2P");
if (shouldAutoStartRouter) [self startupI2PRouter];
NSLog(@"Time to detect I2P version in install directory");
[self.swiftRuntime findInstalledI2PVersion];
if (shouldAutoStartRouter) {
[sBridge startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
[routerStatus setRouterRanByUs: true];
}
}];
} else {
if (self.enableVerboseLogging) NSLog(@"I2P directory found!");
if (shouldAutoStartRouter) [self startupI2PRouter];
[self.swiftRuntime applicationDidFinishLaunching];
// I2P was already found extracted
NSLog(@"Time to detect I2P version in install directory");
[self.swiftRuntime findInstalledI2PVersion];
if (shouldAutoStartRouter) {
[sBridge startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
[routerStatus setRouterRanByUs: true];
}
}
#endif
@@ -448,15 +282,20 @@ inline std::string getDefaultBaseDir()
int main(int argc, const char **argv)
{
NSApplication *app = [NSApplication sharedApplication];
//NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
AppDelegate *appDelegate = [[AppDelegate alloc] initWithArgc:argc argv:argv];
app.delegate = appDelegate;
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];
}
[NSBundle loadNibNamed:@"I2Launcher" owner:NSApp];
[NSApp run];
// Handle any errors
//[pool drain];
return 0;
}

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 LoopPerfect
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.