2014-07-09 14:45:53 +04:00
# import < Cocoa / Cocoa . h >
# import "LNStandardVersionComparator.h"
# define EXPORT __attribute __ ( ( visibility ( "default" ) ) )
# define WAIT_FOR _APPLE _EVENT _TO _ENTER _HANDLER _IN _SECONDS 1.0
# define FINDER_MIN _TESTED _VERSION @ "10.7"
# define FINDER_MAX _TESTED _VERSION @ "10.8.5"
2015-02-25 14:10:36 +03:00
# define LIFERAYNATIVITY_INJECTED _NOTIFICATION @ "SyncStateInjectedNotification"
2014-07-09 14:45:53 +04:00
EXPORT OSErr HandleLoadEvent ( const AppleEvent * ev , AppleEvent * reply , long refcon ) ;
static NSString * globalLock = @ "I'm the global lock to prevent concruent handler executions" ;
// SIMBL - compatible interface
2014-08-18 14:09:24 +04:00
@ interface OwnCloudShell : NSObject { }
2014-07-09 14:45:53 +04:00
- ( void ) install ;
- ( void ) uninstall ;
@ end
// just a dummy class for locating our bundle
2014-08-18 14:09:24 +04:00
@ interface OwnCloudInjector : NSObject { }
2014-07-09 14:45:53 +04:00
@ end
2014-08-18 14:09:24 +04:00
@ implementation OwnCloudInjector { }
2014-07-09 14:45:53 +04:00
@ end
static bool liferayNativityLoaded = false ;
2014-10-23 14:19:19 +04:00
static NSString * liferayNativityBundleName = @ "SyncStateFinder" ;
2014-07-09 14:45:53 +04:00
typedef struct {
NSString * location ;
} configuration ;
static OSErr AEPutParamString ( AppleEvent * event , AEKeyword keyword , NSString * string ) {
UInt8 * textBuf ;
CFIndex length , maxBytes , actualBytes ;
length = CFStringGetLength ( ( CFStringRef ) string ) ;
maxBytes = CFStringGetMaximumSizeForEncoding ( length , kCFStringEncodingUTF8 ) ;
textBuf = malloc ( maxBytes ) ;
if ( textBuf ) {
CFStringGetBytes ( ( CFStringRef ) string , CFRangeMake ( 0 , length ) , kCFStringEncodingUTF8 , 0 , true , ( UInt8 * ) textBuf , maxBytes , & actualBytes ) ;
OSErr err = AEPutParamPtr ( event , keyword , typeUTF8Text , textBuf , actualBytes ) ;
free ( textBuf ) ;
return err ;
} else {
return memFullErr ;
}
}
static void reportError ( AppleEvent * reply , NSString * msg ) {
NSLog ( @ "LiferayNativityInjector: %@" , msg ) ;
AEPutParamString ( reply , keyErrorString , msg ) ;
}
typedef enum {
InvalidBundleType ,
LiferayNativityBundleType ,
} LNBundleType ;
static OSErr loadBundle ( LNBundleType type , AppleEvent * reply , long refcon ) {
bool isLoaded = false ;
NSString * bundleName = nil ;
NSString * targetAppName = nil ;
NSString * versionCheckKey = nil ;
NSString * maxVersion = nil ;
NSString * minVersion = nil ;
switch ( type ) {
case LiferayNativityBundleType :
isLoaded = liferayNativityLoaded ;
bundleName = liferayNativityBundleName ;
targetAppName = @ "Finder" ;
versionCheckKey = @ "LiferayNativityFinderVersionCheck" ;
maxVersion = FINDER_MAX _TESTED _VERSION ;
minVersion = FINDER_MIN _TESTED _VERSION ;
break ;
default :
2015-02-25 14:10:36 +03:00
NSLog ( @ "SyncStateInjector: Failed to load bundle for type %d" , type ) ;
2014-07-09 14:45:53 +04:00
return 8 ;
break ;
}
if ( isLoaded ) {
2015-02-25 14:10:36 +03:00
// NSLog ( @ "SyncStateInjector: %@ already loaded." , bundleName ) ;
2014-07-09 14:45:53 +04:00
return noErr ;
}
@ try {
NSBundle * mainBundle = [ NSBundle mainBundle ] ;
if ( ! mainBundle ) {
reportError ( reply , [ NSString stringWithFormat : @ "Unable to locate main %@ bundle!" , targetAppName ] ) ;
return 4 ;
}
NSString * mainVersion = [ mainBundle objectForInfoDictionaryKey : @ "CFBundleVersion" ] ;
if ( ! mainVersion || ! [ mainVersion isKindOfClass : [ NSString class ] ] ) {
reportError ( reply , [ NSString stringWithFormat : @ "Unable to determine %@ version!" , targetAppName ] ) ;
return 5 ;
}
// future compatibility check
if ( type = = LiferayNativityBundleType ) {
// in Dock we cannot use NSAlert and similar UI stuff - this would hang the Dock process and cause 100 % CPU load
NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
if ( [ defaults boolForKey : versionCheckKey ] ) {
LNStandardVersionComparator * comparator = [ LNStandardVersionComparator defaultComparator ] ;
if ( ( [ comparator compareVersion : mainVersion toVersion : maxVersion ] = = NSOrderedDescending ) ||
( [ comparator compareVersion : mainVersion toVersion : minVersion ] = = NSOrderedAscending ) ) {
NSAlert * alert = [ NSAlert new ] ;
[ alert setMessageText : [ NSString stringWithFormat : @ "You have %@ version %@" , targetAppName , mainVersion ] ] ;
[ alert setInformativeText : [ NSString stringWithFormat : @ "But %@ was properly tested only with %@ versions in range %@ - %@\n\nYou have probably updated your system and %@ version got bumped by Apple developers.\n\nYou may expect a new LiferayNativity release soon." , bundleName , targetAppName , targetAppName , minVersion , maxVersion ] ] ;
[ alert setShowsSuppressionButton : YES ] ;
[ alert addButtonWithTitle : @ "Launch LiferayNativity anyway" ] ;
[ alert addButtonWithTitle : @ "Cancel" ] ;
NSInteger res = [ alert runModal ] ;
if ( [ [ alert suppressionButton ] state ] = = NSOnState ) {
[ defaults setBool : NO forKey : versionCheckKey ] ;
}
if ( res ! = NSAlertFirstButtonReturn ) {
// cancel
return noErr ;
}
}
}
}
2014-08-18 14:09:24 +04:00
NSBundle * liferayNativityInjectorBundle = [ NSBundle bundleForClass : [ OwnCloudInjector class ] ] ;
2014-07-09 14:45:53 +04:00
NSString * liferayNativityLocation = [ liferayNativityInjectorBundle pathForResource : bundleName ofType : @ "bundle" ] ;
NSBundle * pluginBundle = [ NSBundle bundleWithPath : liferayNativityLocation ] ;
if ( ! pluginBundle ) {
reportError ( reply , [ NSString stringWithFormat : @ "Unable to create bundle from path: %@ [%@]" , liferayNativityLocation , liferayNativityInjectorBundle ] ) ;
return 2 ;
}
NSError * error ;
if ( ! [ pluginBundle loadAndReturnError : & error ] ) {
reportError ( reply , [ NSString stringWithFormat : @ "Unable to load bundle from path: %@ error: %@" , liferayNativityLocation , [ error localizedDescription ] ] ) ;
return 6 ;
}
Class principalClass = [ pluginBundle principalClass ] ;
if ( ! principalClass ) {
reportError ( reply , [ NSString stringWithFormat : @ "Unable to retrieve principalClass for bundle: %@" , pluginBundle ] ) ;
return 3 ;
}
id principalClassObject = NSClassFromString ( NSStringFromClass ( principalClass ) ) ;
if ( [ principalClassObject respondsToSelector : @ selector ( install ) ] ) {
2015-02-25 14:10:36 +03:00
// NSLog ( @ "SyncStateInjector: Installing %@ ..." , bundleName ) ;
2014-07-09 14:45:53 +04:00
[ principalClassObject install ] ;
}
return noErr ;
} @ catch ( NSException * exception ) {
reportError ( reply , [ NSString stringWithFormat : @ "Failed to load %@ with exception: %@" , bundleName , exception ] ) ;
}
return 1 ;
}
static LNBundleType mainBundleType ( AppleEvent * reply ) {
@ try {
NSBundle * mainBundle = [ NSBundle mainBundle ] ;
if ( ! mainBundle ) {
reportError ( reply , [ NSString stringWithFormat : @ "Unable to locate main bundle!" ] ) ;
return InvalidBundleType ;
}
if ( [ [ mainBundle bundleIdentifier ] isEqualToString : @ "com.apple.finder" ] ) {
return LiferayNativityBundleType ;
}
} @ catch ( NSException * exception ) {
reportError ( reply , [ NSString stringWithFormat : @ "Failed to load main bundle with exception: %@" , exception ] ) ;
}
return InvalidBundleType ;
}
EXPORT OSErr HandleLoadEvent ( const AppleEvent * ev , AppleEvent * reply , long refcon ) {
@ synchronized ( globalLock ) {
@ autoreleasepool {
2014-08-18 14:09:24 +04:00
NSBundle * injectorBundle = [ NSBundle bundleForClass : [ OwnCloudInjector class ] ] ;
2014-07-09 14:45:53 +04:00
NSString * injectorVersion = [ injectorBundle objectForInfoDictionaryKey : @ "CFBundleVersion" ] ;
if ( ! injectorVersion || ! [ injectorVersion isKindOfClass : [ NSString class ] ] ) {
2015-02-25 14:10:36 +03:00
reportError ( reply , [ NSString stringWithFormat : @ "Unable to determine SyncStateInjector version!" ] ) ;
2014-07-09 14:45:53 +04:00
return 7 ;
}
@ try {
OSErr err = loadBundle ( mainBundleType ( reply ) , reply , refcon ) ;
if ( err ! = noErr )
{
return err ;
}
pid_t pid = [ [ NSProcessInfo processInfo ] processIdentifier ] ;
[ [ NSDistributedNotificationCenter defaultCenter ] postNotificationName : LIFERAYNATIVITY_INJECTED _NOTIFICATION object : [ [ NSBundle mainBundle ] bundleIdentifier ] userInfo : @ { @ "pid" : @ ( pid ) } ] ;
liferayNativityLoaded = true ;
return noErr ;
} @ catch ( NSException * exception ) {
2014-08-18 14:09:24 +04:00
reportError ( reply , [ NSString stringWithFormat : @ "Failed to load OwnCloudFinder with exception: %@" , exception ] ) ;
2014-07-09 14:45:53 +04:00
}
return 1 ;
}
}
}
EXPORT OSErr HandleLoadedEvent ( const AppleEvent * ev , AppleEvent * reply , long refcon ) {
@ synchronized ( globalLock ) {
@ autoreleasepool {
LNBundleType type = mainBundleType ( reply ) ;
if ( ( type = = LiferayNativityBundleType ) && liferayNativityLoaded ) {
return noErr ;
}
reportError ( reply , @ "LiferayNativity not loaded" ) ;
return 1 ;
}
}
}
EXPORT OSErr HandleUnloadEvent ( const AppleEvent * ev , AppleEvent * reply , long refcon ) {
@ synchronized ( globalLock ) {
@ autoreleasepool {
@ try {
if ( ! liferayNativityLoaded ) {
2015-02-25 14:10:36 +03:00
// NSLog ( @ "SyncStateInjector: not loaded." ) ;
2014-07-09 14:45:53 +04:00
return noErr ;
}
NSString * bundleName = liferayNativityBundleName ;
2014-08-18 14:09:24 +04:00
NSBundle * liferayNativityInjectorBundle = [ NSBundle bundleForClass : [ OwnCloudInjector class ] ] ;
2014-07-09 14:45:53 +04:00
NSString * liferayNativityLocation = [ liferayNativityInjectorBundle pathForResource : bundleName ofType : @ "bundle" ] ;
NSBundle * pluginBundle = [ NSBundle bundleWithPath : liferayNativityLocation ] ;
if ( ! pluginBundle ) {
reportError ( reply , [ NSString stringWithFormat : @ "Unable to create bundle from path: %@ [%@]" , liferayNativityLocation , liferayNativityInjectorBundle ] ) ;
return 2 ;
}
Class principalClass = [ pluginBundle principalClass ] ;
if ( ! principalClass ) {
reportError ( reply , [ NSString stringWithFormat : @ "Unable to retrieve principalClass for bundle: %@" , pluginBundle ] ) ;
return 3 ;
}
id principalClassObject = NSClassFromString ( NSStringFromClass ( principalClass ) ) ;
if ( [ principalClassObject respondsToSelector : @ selector ( uninstall ) ] ) {
2015-02-25 14:10:36 +03:00
// NSLog ( @ "SyncStateInjector: Uninstalling %@ ..." , bundleName ) ;
2014-07-09 14:45:53 +04:00
[ principalClassObject uninstall ] ;
}
liferayNativityLoaded = false ;
return noErr ;
} @ catch ( NSException * exception ) {
2014-08-18 14:09:24 +04:00
reportError ( reply , [ NSString stringWithFormat : @ "Failed to unload OwnCloudFinder with exception: %@" , exception ] ) ;
2014-07-09 14:45:53 +04:00
}
return 1 ;
}
}
}