// Copyright (c) 2004, Nisus Software, Inc.
// All rights reserved.
-// Redistribution and use in source and binary forms, with or without
+// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
-// Redistributions of source code must retain the above copyright notice,
+// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
-// Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
+// Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
-// Neither the name of the Nisus Software, Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from this
+// Neither the name of the Nisus Software, Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
static BOOL inited = NO ;
if (inited) return ;
- [super initialize] ;
+ [super initialize] ;
inited = YES ;
-
+
if (!LinkBackServers) LinkBackServers = [[NSMutableDictionary alloc] init];
}
-+ (LinkBackServer*)LinkBackServerWithName:(NSString*)aName
++ (LinkBackServer*)LinkBackServerWithName:(NSString*)aName
{
return [LinkBackServers objectForKey: aName] ;
}
-+ (BOOL)publishServerWithName:(NSString*)aName delegate:(id<LinkBackServerDelegate>)del
++ (BOOL)publishServerWithName:(NSString*)aName delegate:(id<LinkBackServerDelegate>)del
{
LinkBackServer* serv = [[LinkBackServer alloc] initWithName: aName delegate: del] ;
BOOL ret = [serv publish] ; // retains if successful
BOOL LinkBackServerIsSupported(NSString* name, id supportedServers)
{
BOOL ret = NO ;
+#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
+ NSUInteger idx ;
+#else
int idx ;
+#endif
NSString* curServer = supportedServers ;
-
+
// NOTE: supportedServers may be nil, an NSArray, or NSString.
if (supportedServers) {
if ([supportedServers isKindOfClass: [NSArray class]]) {
idx = [supportedServers count] ;
- while((NO==ret) && (--idx >= 0)) {
- curServer = [supportedServers objectAtIndex: idx] ;
+ while((NO==ret) && (idx > 0)) {
+ curServer = [supportedServers objectAtIndex: --idx] ;
ret = [curServer isEqualToString: name] ;
}
- } else ret = [curServer isEqualToString: name] ;
+ } else ret = [curServer isEqualToString: name] ;
}
-
+
return ret ;
}
NSString* ret = nil ;
NSFileManager* fm = [NSFileManager defaultManager] ;
-#if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
+#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1050)
NSArray* contents = [fm contentsOfDirectoryAtPath: dir error: nil] ;
+ NSUInteger idx ;
#else
NSArray* contents = [fm directoryContentsAtPath: dir] ;
-#endif
int idx ;
+#endif
- NSLog(@"searching for %@ in folder: %@", serverName, dir) ;
-
// working info
NSString* cpath ;
NSBundle* cbundle ;
NSString* cbundleIdentifier ;
id supportedServers ;
+ NSLog(@"searching for %@ in folder: %@", serverName, dir) ;
+
// resolve any symlinks, expand tildes.
dir = [dir stringByStandardizingPath] ;
-
+
// find all .app bundles in the directory and test them.
idx = (contents) ? [contents count] : 0 ;
- while((nil==ret) && (--idx >= 0)) {
- cpath = [contents objectAtIndex: idx] ;
-
+ while((nil==ret) && (idx > 0)) {
+ cpath = [contents objectAtIndex: --idx] ;
+
if ([[cpath pathExtension] isEqualToString: @"app"]) {
cpath = [dir stringByAppendingPathComponent: cpath] ;
cbundle = [NSBundle bundleWithPath: cpath] ;
cbundleIdentifier = [cbundle bundleIdentifier] ;
-
+
if ([cbundleIdentifier isEqualToString: bundleIdentifier]) {
supportedServers = [[cbundle infoDictionary] objectForKey: @"LinkBackServer"] ;
ret= (LinkBackServerIsSupported(serverName, supportedServers)) ? cpath : nil ;
}
}
}
-
+
// if the app was not found, descend into non-app dirs. only descend 4 levels to avoid taking forever.
if ((nil==ret) && (level<4)) {
idx = (contents) ? [contents count] : 0 ;
- while((nil==ret) && (--idx >= 0)) {
+ while((nil==ret) && (idx > 0)) {
BOOL isdir ;
-
- cpath = [contents objectAtIndex: idx] ;
+
+ cpath = [contents objectAtIndex: --idx] ;
[fm fileExistsAtPath: cpath isDirectory: &isdir] ;
if (isdir && (![[cpath pathExtension] isEqualToString: @"app"])) {
cpath = [dir stringByAppendingPathComponent: cpath] ;
}
}
}
-
+
return ret ;
}
void LinkBackRunAppNotFoundPanel(NSString* appName, NSURL* url)
{
- int result ;
-
+
// strings for panel
NSBundle* b = [NSBundle bundleForClass: [LinkBack class]] ;
NSString* title ;
NSString* msg ;
NSString* ok ;
NSString* urlstr ;
-
+
title = NSLocalizedStringFromTableInBundle(@"_AppNotFoundTitle", @"Localized", b, @"app not found title") ;
ok = NSLocalizedStringFromTableInBundle(@"_OK", @"Localized", b, @"ok") ;
msg = (url) ? NSLocalizedStringFromTableInBundle(@"_AppNotFoundMessageWithURL", @"Localized", b, @"app not found msg") : NSLocalizedStringFromTableInBundle(@"_AppNotFoundMessageNoURL", @"Localized", b, @"app not found msg") ;
-
+
urlstr = (url) ? NSLocalizedStringFromTableInBundle(@"_GetApplication", @"Localized", b, @"Get application") : nil ;
title = [NSString stringWithFormat: title, appName] ;
-
- result = NSRunCriticalAlertPanel(title, msg, ok, urlstr, nil) ;
- if (NSAlertAlternateReturn == result) {
- [[NSWorkspace sharedWorkspace] openURL: url] ;
- }
+
+ NSAlert* alert = [[NSAlert alloc] init];
+ [alert setAlertStyle:NSAlertStyleCritical];
+ [alert setMessageText:title];
+ [alert setInformativeText:[NSString stringWithFormat:@"%@", msg]];
+ [alert addButtonWithTitle:ok];
+ [alert addButtonWithTitle:urlstr];
+ [alert beginSheetModalForWindow:[NSApp mainWindow] completionHandler:^(NSModalResponse returnCode) {
+ if (returnCode == NSAlertSecondButtonReturn)
+ [[NSWorkspace sharedWorkspace] openURL: url] ;
+ }];
}
-+ (LinkBackServer*)LinkBackServerWithName:(NSString*)aName inApplication:(NSString*)bundleIdentifier launchIfNeeded:(BOOL)flag fallbackURL:(NSURL*)url appName:(NSString*)appName ;
++ (LinkBackServer*)LinkBackServerWithName:(NSString*)aName inApplication:(NSString*)bundleIdentifier launchIfNeeded:(BOOL)flag fallbackURL:(NSURL*)url appName:(NSString*)appName
{
BOOL connect = YES ;
NSString* serverName = MakeLinkBackServerName(bundleIdentifier, aName) ;
id ret = nil ;
NSTimeInterval tryMark ;
-
+
// Try to connect
ret = [NSConnection rootProxyForConnectionWithRegisteredName: serverName host: nil] ;
-
+
// if launchIfNeeded, and the connection was not available, try to launch.
if((!ret) && (flag)) {
NSString* appPath ;
id linkBackServers ;
-
+
// first, try to find the app with the bundle identifier
appPath = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier: bundleIdentifier] ;
- linkBackServers = [[[NSBundle bundleWithPath: appPath] infoDictionary] objectForKey: @"LinkBackServer"] ;
+ linkBackServers = [[[NSBundle bundleWithPath: appPath] infoDictionary] objectForKey: @"LinkBackServer"] ;
appPath = (LinkBackServerIsSupported(aName, linkBackServers)) ? appPath : nil ;
-
+
// if the found app is not supported, we will need to search for the app ourselves.
if (nil==appPath) appPath = FindLinkBackServer(bundleIdentifier, aName, @"/Applications",0);
-
+
if (nil==appPath) appPath = FindLinkBackServer(bundleIdentifier, aName, @"~/Applications",0);
-
+
if (nil==appPath) appPath = FindLinkBackServer(bundleIdentifier, aName, @"/Network/Applications",0);
-
+
// if app path has been found, launch the app.
if (appPath) {
[[NSWorkspace sharedWorkspace] launchApplication: appName] ;
connect = NO ;
}
}
-
- // if needed, try to connect.
+
+ // if needed, try to connect.
// retry connection for a while if we did not succeed at first. This gives the app time to launch.
if (connect && (nil==ret)) {
tryMark = [NSDate timeIntervalSinceReferenceDate] ;
do {
ret = [NSConnection rootProxyForConnectionWithRegisteredName: serverName host: nil] ;
} while ((!ret) && (([NSDate timeIntervalSinceReferenceDate]-tryMark)<10)) ;
-
+
}
// setup protocol and return
delegate = aDel ;
listener = nil ;
}
-
+
return self ;
}
{
NSString* serverName = MakeLinkBackServerName([[NSBundle mainBundle] bundleIdentifier], name) ;
BOOL ret = YES ;
-
+
// create listener and connect
NSPort* port = [NSPort port] ;
listener = [NSConnection connectionWithReceivePort: port sendPort:port] ;
[listener setRootObject: self] ;
ret = [listener registerName: serverName] ;
-
+
// if successful, retain connection and add self to list of servers.
if (ret) {
[listener retain] ;
[LinkBackServers setObject: self forKey: name] ;
- } else listener = nil ; // listener will dealloc on its own.
-
+ } else listener = nil ; // listener will dealloc on its own.
+
return ret ;
}
-- (void)retract
+- (void)retract
{
if (listener) {
[listener invalidate] ;
[listener release] ;
listener = nil ;
}
-
+
[LinkBackServers removeObjectForKey: name] ;
}
-- (LinkBack*)initiateLinkBackFromClient:(LinkBack*)clientLinkBack
+- (LinkBack*)initiateLinkBackFromClient:(LinkBack*)clientLinkBack
{
LinkBack* ret = [[LinkBack alloc] initServerWithClient: clientLinkBack delegate: delegate] ;
-
+
// NOTE: we do not release because LinkBack will release itself when it the link closes. (caj)
-
- return ret ;
+
+ return ret ;
}
@end