get process name (from app bundle)
delete sample's output file made find camera/mic instance methods fixed icons for main app code cleanup/TODOs
This commit is contained in:
parent
c356077600
commit
78ea2d11c4
|
@ -34,7 +34,11 @@
|
|||
if(YES == [self isInstalled])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"already installed, so uninstalling...");
|
||||
logMsg(LOG_DEBUG, @"already installed, so stopping/uninstalling...");
|
||||
|
||||
//stop
|
||||
// ->kill login item/XPC service
|
||||
[self stop];
|
||||
|
||||
//uninstall
|
||||
if(YES != [self uninstall])
|
||||
|
@ -43,10 +47,6 @@
|
|||
goto bail;
|
||||
}
|
||||
|
||||
//and stop
|
||||
//TODO: erorr checking
|
||||
[self stop];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"uninstalled");
|
||||
}
|
||||
|
@ -81,16 +81,9 @@
|
|||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"stopping login item");
|
||||
|
||||
//stop login item/XPC service
|
||||
if(YES != [self stop])
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"stopping failed");
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//stop
|
||||
// ->kill login item/XPC service
|
||||
[self stop];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"uninstalling...");
|
||||
|
@ -228,22 +221,13 @@ bail:
|
|||
}
|
||||
|
||||
//stop
|
||||
-(BOOL)stop
|
||||
-(void)stop
|
||||
{
|
||||
//flag
|
||||
BOOL bStopped = NO;
|
||||
|
||||
//kill it
|
||||
// pkill doesn't provide error info, so...
|
||||
execTask(PKILL, @[APP_HELPER_NAME]);
|
||||
|
||||
//happy
|
||||
bStopped = YES;
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return bStopped;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//uninstall
|
||||
|
|
|
@ -14,67 +14,6 @@
|
|||
|
||||
#import "../Shared/XPCProtocol.h"
|
||||
|
||||
//TODO: make instance methods?!
|
||||
|
||||
//grab first apple camera
|
||||
AVCaptureDevice* findAppleCamera()
|
||||
{
|
||||
//apple camera
|
||||
// ->likely FaceTime camera
|
||||
AVCaptureDevice* appleCamera = nil;
|
||||
|
||||
//list of cameras
|
||||
NSArray *cameras = nil;
|
||||
|
||||
//get cameras
|
||||
cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
||||
for(AVCaptureDevice* camera in cameras)
|
||||
{
|
||||
//check if apple
|
||||
if(YES == [camera.manufacturer isEqualToString:@"Apple Inc."])
|
||||
{
|
||||
//save
|
||||
appleCamera = camera;
|
||||
|
||||
//exit loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return appleCamera;
|
||||
}
|
||||
|
||||
//grab built-in mic
|
||||
AVCaptureDevice* findAppleMic()
|
||||
{
|
||||
//built-in mic
|
||||
AVCaptureDevice* appleMic = nil;
|
||||
|
||||
//list of mics
|
||||
NSArray *mics = nil;
|
||||
|
||||
//get mics
|
||||
mics = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
|
||||
for(AVCaptureDevice* mic in mics)
|
||||
{
|
||||
//check if apple
|
||||
// ->also check input source
|
||||
if( (YES == [mic.manufacturer isEqualToString:@"Apple Inc."]) &&
|
||||
(YES == [[[mic activeInputSource] inputSourceID] isEqualToString:@"imic"]) )
|
||||
{
|
||||
//save
|
||||
appleMic = mic;
|
||||
|
||||
//exit loop
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return appleMic;
|
||||
}
|
||||
|
||||
|
||||
@implementation AVMonitor
|
||||
|
||||
@synthesize mic;
|
||||
|
@ -96,6 +35,54 @@ AVCaptureDevice* findAppleMic()
|
|||
return self;
|
||||
}
|
||||
|
||||
//grab first apple camera
|
||||
// ->saves into iVar 'camera'
|
||||
// note: could maybe use defaultDeviceWithDeviceType method() to default device...
|
||||
-(void)findAppleCamera
|
||||
{
|
||||
//get cameras
|
||||
// ->look for one that belongs to apple
|
||||
for(AVCaptureDevice* currentCamera in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo])
|
||||
{
|
||||
//check if apple
|
||||
if(YES == [currentCamera.manufacturer isEqualToString:@"Apple Inc."])
|
||||
{
|
||||
//save
|
||||
self.camera = currentCamera;
|
||||
|
||||
//exit loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//grab first apple mic
|
||||
// ->saves into iVar 'mic'
|
||||
-(void)findAppleMic
|
||||
{
|
||||
//get mics
|
||||
// ->loof for one that belongs to app
|
||||
for(AVCaptureDevice* currentMic in [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio])
|
||||
{
|
||||
//check if apple
|
||||
// ->also check input source
|
||||
if( (YES == [currentMic.manufacturer isEqualToString:@"Apple Inc."]) &&
|
||||
(YES == [[[currentMic activeInputSource] inputSourceID] isEqualToString:@"imic"]) )
|
||||
{
|
||||
//save
|
||||
self.mic = currentMic;
|
||||
|
||||
//exit loop
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//initialiaze AV notifcations/callbacks
|
||||
-(BOOL)monitor
|
||||
{
|
||||
|
@ -155,13 +142,12 @@ AVCaptureDevice* findAppleMic()
|
|||
methodSelector = NSSelectorFromString(@"connectionID");
|
||||
|
||||
//find (first) apple camera
|
||||
self.camera = findAppleCamera();
|
||||
// ->saves camera into iVar, 'camera'
|
||||
[self findAppleCamera];
|
||||
|
||||
//find built in mic
|
||||
self.mic = findAppleMic();
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"found mic: %@", self.mic]);
|
||||
//find (first) apple mic
|
||||
// ->saves mic into iVar, 'mic'
|
||||
[self findAppleMic];
|
||||
|
||||
//got camera
|
||||
// ->grab connection ID and invoke helper functions
|
||||
|
@ -522,7 +508,7 @@ bail:
|
|||
if(noErr != status)
|
||||
{
|
||||
//err msg
|
||||
//TODO: add
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"CMIOObjectAddPropertyListenerBlock() failed with %d", status]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
|
@ -737,23 +723,22 @@ bail:
|
|||
// ->for activatated video; allow/block
|
||||
else
|
||||
{
|
||||
//get process name
|
||||
processName = getProcessName([event[EVENT_PROCESS_ID] intValue]);
|
||||
|
||||
//set other button title
|
||||
notification.otherButtonTitle = @"allow";
|
||||
|
||||
//set action title
|
||||
notification.actionButtonTitle = @"block";
|
||||
|
||||
//get process name
|
||||
// TODO: see 'determineName' in BB (to get name from bundle, etc)
|
||||
processName = [getProcessPath([event[EVENT_PROCESS_ID] intValue]) lastPathComponent];
|
||||
|
||||
//set pid in user info
|
||||
// ->allows code to try kill proc (later) if user clicks 'block'
|
||||
notification.userInfo = @{EVENT_PROCESS_ID:event[EVENT_PROCESS_ID]};
|
||||
|
||||
//set details
|
||||
// ->name of process using it / icon too?
|
||||
[notification setInformativeText:[NSString stringWithFormat:@"%@ (%@)", processName, event[EVENT_PROCESS_ID]]];
|
||||
[notification setInformativeText:[NSString stringWithFormat:@"process: %@ (%@)", processName, event[EVENT_PROCESS_ID]]];
|
||||
}
|
||||
|
||||
//log event?
|
||||
|
@ -772,11 +757,11 @@ bail:
|
|||
}
|
||||
|
||||
//process
|
||||
// ->add title / details / process
|
||||
// ->add title / details / process path
|
||||
else
|
||||
{
|
||||
//add
|
||||
[logMsg appendFormat:@"%@ (%@, %@)", title, details, processName];
|
||||
[logMsg appendFormat:@"%@ (process: %@, %@)", title, details, getProcessPath([event[EVENT_PROCESS_ID] intValue])];
|
||||
}
|
||||
|
||||
//write it out to syslog
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
|
@ -24,12 +22,12 @@
|
|||
<string>1.0.0</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright (c) 2016 Objective-See. All rights reserved.</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
7D9A7DE81D893E4F0091C1AF /* InfoWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D62458C1D87D38400870565 /* InfoWindow.xib */; };
|
||||
7D9A7DEC1D8BE1E00091C1AF /* Exception.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D17C5311D659E580066232A /* Exception.m */; };
|
||||
7D9A7DEE1D8CACE30091C1AF /* libbsm.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D9A7DED1D8CACE30091C1AF /* libbsm.tbd */; };
|
||||
7D9A7DF21D8F2C900091C1AF /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7D6245841D87C43900870565 /* Images.xcassets */; };
|
||||
7DAF4B7F1D657192000DA31A /* StatusBarMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DAF4B7D1D656FD3000DA31A /* StatusBarMenu.m */; };
|
||||
7DC9C8171D641A350017D143 /* OverSightXPC.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DC9C8161D641A350017D143 /* OverSightXPC.m */; };
|
||||
7DC9C8191D641A350017D143 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DC9C8181D641A350017D143 /* main.m */; };
|
||||
|
@ -166,7 +167,7 @@
|
|||
7D17C5131D658FE20066232A /* Images */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7D17CFE21D81121E0017B475 /* AVMonitor.h */,
|
||||
8B5755C819DA3F9300799E6B /* AppDelegate.h */,
|
||||
7D17C5141D658FEB0066232A /* statusIcon.png */,
|
||||
7D17C5151D658FEB0066232A /* statusIcon@2x.png */,
|
||||
);
|
||||
|
@ -276,11 +277,11 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
7D17C5131D658FE20066232A /* Images */,
|
||||
8B5755C919DA3F9300799E6B /* AppDelegate.m */,
|
||||
7D17CFE21D81121E0017B475 /* AVMonitor.h */,
|
||||
7D17CFE11D81121E0017B475 /* AVMonitor.m */,
|
||||
7DAF4B7C1D656FD3000DA31A /* StatusBarMenu.h */,
|
||||
7DAF4B7D1D656FD3000DA31A /* StatusBarMenu.m */,
|
||||
8B5755C819DA3F9300799E6B /* AppDelegate.h */,
|
||||
8B5755C919DA3F9300799E6B /* AppDelegate.m */,
|
||||
7D17CFE11D81121E0017B475 /* AVMonitor.m */,
|
||||
8B5755CD19DA3F9300799E6B /* MainMenu.xib */,
|
||||
8B5755C419DA3F9300799E6B /* Supporting Files */,
|
||||
);
|
||||
|
@ -419,6 +420,7 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7D9A7DF21D8F2C900091C1AF /* Images.xcassets in Resources */,
|
||||
7D6245921D87D46800870565 /* InfoWindow.xib in Resources */,
|
||||
7D17C53C1D659E580066232A /* icon.png in Resources */,
|
||||
8B5755A919DA3E9500799E6B /* MainMenu.xib in Resources */,
|
||||
|
@ -629,6 +631,7 @@
|
|||
8B5755B919DA3E9500799E6B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
|
@ -644,6 +647,7 @@
|
|||
8B5755BA19DA3E9500799E6B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application: Objective-See, LLC (VBG97UB4TA)";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
|
|
|
@ -309,7 +309,6 @@ bail:
|
|||
}
|
||||
|
||||
//parse on '()'
|
||||
// TODO: improve this!
|
||||
subStrings = [line componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"()"]];
|
||||
if(subStrings.count < 3)
|
||||
{
|
||||
|
@ -371,10 +370,10 @@ bail:
|
|||
videoProcs = [NSMutableArray array];
|
||||
|
||||
//invoke 'sample' on each
|
||||
// TODO: delete tmp file? 'Sample analysis of process 37370 written to file /tmp/FaceTime_2016-09-10_081703_TAwB.sample.txt' (written 2 std err?)
|
||||
for(NSNumber* processID in currentSenders)
|
||||
{
|
||||
//exec 'sample' to get threads/dylibs
|
||||
// ->uses 1.0 seconds for sampling time
|
||||
results = [[NSString alloc] initWithData:execTask(SAMPLE, @[processID.stringValue, @"1"]) encoding:NSUTF8StringEncoding];
|
||||
if( (nil == results) ||
|
||||
(0 == results.length) )
|
||||
|
@ -382,7 +381,11 @@ bail:
|
|||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
//sampling a process creates a temp file
|
||||
//->delete it!
|
||||
[self deleteSampleFile:getProcessPath(processID.intValue)];
|
||||
|
||||
//for now, just check for 'CMIOGraph::DoWork'
|
||||
// ->TODO: could look for dylibs, other calls, etc
|
||||
if(YES != [results containsString:@"CMIOGraph::DoWork"])
|
||||
|
@ -398,6 +401,66 @@ bail:
|
|||
return videoProcs;
|
||||
}
|
||||
|
||||
//'sample' binary creates a file
|
||||
// ->this looks for that file and deletes it
|
||||
-(void)deleteSampleFile:(NSString*)processPath
|
||||
{
|
||||
//error
|
||||
NSError* error = nil;
|
||||
|
||||
//files
|
||||
NSArray* files = nil;
|
||||
|
||||
//grab all files in /tmp
|
||||
files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/tmp/" error:&error];
|
||||
if(nil != error)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to enumerate files in /tmp, %@", error]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//find/delete file
|
||||
for(NSString* file in files)
|
||||
{
|
||||
//skip non-sample files
|
||||
if(YES != [file hasSuffix:@".sample.txt"])
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//ignore files that don't contain process name
|
||||
if(YES != [file containsString:[processPath lastPathComponent]])
|
||||
{
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"deleting sample file: %@", file]);
|
||||
|
||||
//delete
|
||||
if(YES != [[NSFileManager defaultManager] removeItemAtPath:[@"/tmp" stringByAppendingPathComponent:file] error:&error])
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to delete %@ (%@)", file, error]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
}//all files
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//set status of video
|
||||
-(void)updateVideoStatus:(BOOL)isEnabled
|
||||
{
|
||||
|
|
|
@ -11,12 +11,10 @@
|
|||
#import "Exception.h"
|
||||
#import "Utilities.h"
|
||||
|
||||
//TODO: renenable
|
||||
/*
|
||||
#ifdef IS_INSTALLER_APP
|
||||
#import "AppDelegate.h"
|
||||
#endif
|
||||
*/
|
||||
|
||||
|
||||
//global
|
||||
// ->only report an fatal exception once
|
||||
|
@ -98,9 +96,8 @@ void exceptionHandler(NSException *exception)
|
|||
// ->agent should exit
|
||||
errorInfo[KEY_ERROR_SHOULD_EXIT] = [NSNumber numberWithBool:YES];
|
||||
|
||||
//TODO: renable
|
||||
//display error msg
|
||||
//[((AppDelegate*)[[NSApplication sharedApplication] delegate]) displayErrorWindow:errorInfo];
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) displayErrorWindow:errorInfo];
|
||||
|
||||
//need to sleep, otherwise returning from this function will cause OS to kill agent
|
||||
// ->instead, we want error popup to be displayed (which will exit agent when closed)
|
||||
|
@ -178,9 +175,8 @@ void signalHandler(int signal, siginfo_t *info, void *context)
|
|||
// ->agent should exit
|
||||
errorInfo[KEY_ERROR_SHOULD_EXIT] = [NSNumber numberWithBool:YES];
|
||||
|
||||
//TODO: renable
|
||||
//display error msg
|
||||
//[((AppDelegate*)[[NSApplication sharedApplication] delegate]) displayErrorWindow:errorInfo];
|
||||
[((AppDelegate*)[[NSApplication sharedApplication] delegate]) displayErrorWindow:errorInfo];
|
||||
|
||||
//end app-specific code
|
||||
#endif
|
||||
|
|
|
@ -42,8 +42,5 @@ void logMsg(int level, NSString* msg)
|
|||
//log to syslog
|
||||
syslog(level, "%s: %s\n", [logPrefix UTF8String], [msg UTF8String]);
|
||||
|
||||
//TODO: remove
|
||||
NSLog(@"%s: %s", [logPrefix UTF8String], [msg UTF8String]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
/* FUNCTIONS */
|
||||
|
||||
//TODO: cleanup/remove un-needed
|
||||
|
||||
//get app's version
|
||||
// ->extracted from Info.plist
|
||||
NSString* getAppVersion();
|
||||
|
@ -36,13 +34,6 @@ SInt32 getVersion(OSType selector);
|
|||
// parse it back up to find app's bundle
|
||||
NSBundle* findAppBundle(NSString* binaryPath);
|
||||
|
||||
//given a directory and a filter predicate
|
||||
// ->return all matches
|
||||
NSArray* directoryContents(NSString* directory, NSString* predicate);
|
||||
|
||||
//hash (sha1/md5) a file
|
||||
NSDictionary* hashFile(NSString* filePath);
|
||||
|
||||
//get app's version
|
||||
// ->extracted from Info.plist
|
||||
NSString* getAppVersion();
|
||||
|
@ -54,15 +45,15 @@ NSString* getLatestVersion();
|
|||
// -1, YES or NO
|
||||
NSInteger isNewVersion(NSMutableString* versionString);
|
||||
|
||||
//exec a process and grab it's output
|
||||
NSData* execTask(NSString* binaryPath, NSArray* arguments);
|
||||
|
||||
//get process's path
|
||||
NSString* getProcessPath(pid_t pid);
|
||||
|
||||
//given a pid
|
||||
// ->get the name of the process
|
||||
NSString* getProcessName(pid_t pid);
|
||||
|
||||
//wait until a window is non nil
|
||||
// ->then make it modal
|
||||
void makeModal(NSWindowController* windowController);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -254,7 +254,7 @@ NSData* execTask(NSString* binaryPath, NSArray* arguments)
|
|||
//launch
|
||||
[task launch];
|
||||
}
|
||||
@catch(NSException *exception)
|
||||
@catch(NSException* exception)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
|
@ -412,6 +412,53 @@ bail:
|
|||
return taskPath;
|
||||
}
|
||||
|
||||
//given a pid
|
||||
// ->get the name of the process
|
||||
NSString* getProcessName(pid_t pid)
|
||||
{
|
||||
//task path
|
||||
NSString* processName = nil;
|
||||
|
||||
//process path
|
||||
NSString* processPath = nil;
|
||||
|
||||
//app's bundle
|
||||
NSBundle* appBundle = nil;
|
||||
|
||||
//get process path
|
||||
processPath = getProcessPath(pid);
|
||||
if( (nil == processPath) ||
|
||||
(0 == processPath.length) )
|
||||
{
|
||||
//default to 'unknown'
|
||||
processName = @"<unknown>";
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//try find an app bundle
|
||||
appBundle = findAppBundle(processPath);
|
||||
if(nil != appBundle)
|
||||
{
|
||||
//grab name from app's bundle
|
||||
processName = [appBundle infoDictionary][@"CFBundleName"];
|
||||
}
|
||||
|
||||
//still nil?
|
||||
// ->just grab from path
|
||||
if(nil == processName)
|
||||
{
|
||||
//from path
|
||||
processName = [processPath lastPathComponent];
|
||||
}
|
||||
|
||||
//bail
|
||||
bail:
|
||||
|
||||
return processName;
|
||||
}
|
||||
|
||||
//determine if there is a new version
|
||||
// -1, YES or NO
|
||||
NSInteger isNewVersion(NSMutableString* versionString)
|
||||
|
|
Loading…
Reference in New Issue