Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
829f0d779d |
@@ -12,7 +12,6 @@
|
||||
#import "Configure.h"
|
||||
#import "HelperComms.h"
|
||||
#import "AboutWindowController.h"
|
||||
#import "ErrorWindowController.h"
|
||||
#import "ConfigureWindowController.h"
|
||||
|
||||
//block for install/uninstall
|
||||
@@ -41,16 +40,10 @@ typedef void (^block)(NSNumber*);
|
||||
//configure window controller
|
||||
@property(nonatomic, retain)ConfigureWindowController* configureWindowController;
|
||||
|
||||
//error window controller
|
||||
@property(nonatomic, retain)ErrorWindowController* errorWindowController;
|
||||
|
||||
|
||||
/* METHODS */
|
||||
|
||||
//display configuration window w/ 'install' || 'uninstall' button
|
||||
-(void)displayConfigureWindow:(BOOL)isInstalled;
|
||||
|
||||
//display error window
|
||||
-(void)displayErrorWindow:(NSDictionary*)errorInfo;
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
@synthesize configureObj;
|
||||
|
||||
@synthesize aboutWindowController;
|
||||
@synthesize errorWindowController;
|
||||
@synthesize configureWindowController;
|
||||
|
||||
//main app interface
|
||||
@@ -41,17 +40,6 @@
|
||||
//start crash handler
|
||||
[SentryClient.sharedClient startCrashHandlerWithError:nil];
|
||||
|
||||
//make sure system is supported (lid)
|
||||
// if not, will inform user via alert
|
||||
if(YES != [self isSupported])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_ERR, @"device doesn't appear to have a lid (i.e. is unsupported)");
|
||||
|
||||
//exit
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
|
||||
//alloc/init Config obj
|
||||
configureObj = [[Configure alloc] init];
|
||||
|
||||
@@ -61,51 +49,6 @@
|
||||
return;
|
||||
}
|
||||
|
||||
//check if there's a lid
|
||||
// if not, alert to tell user
|
||||
-(BOOL)isSupported
|
||||
{
|
||||
//flag
|
||||
BOOL supported = NO;
|
||||
|
||||
//alert
|
||||
NSAlert* alert = nil;
|
||||
|
||||
//no lid
|
||||
// can't support!
|
||||
if(stateUnavailable == getLidState())
|
||||
{
|
||||
//init alert
|
||||
alert = [[NSAlert alloc] init];
|
||||
|
||||
//set main text
|
||||
alert.messageText = @"Unsupported Device";
|
||||
|
||||
//set informative text
|
||||
alert.informativeText = [NSString stringWithFormat:@"'%@' does not appear to be a laptop", [[NSHost currentHost] localizedName]];
|
||||
|
||||
//add button
|
||||
[alert addButtonWithTitle:@"Ok"];
|
||||
|
||||
//set style
|
||||
alert.alertStyle = NSAlertStyleWarning;
|
||||
|
||||
//show it
|
||||
[alert runModal];
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//happy
|
||||
supported = YES;
|
||||
|
||||
bail:
|
||||
|
||||
return supported;
|
||||
|
||||
}
|
||||
|
||||
//exit when last window is closed
|
||||
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
|
||||
{
|
||||
@@ -143,58 +86,6 @@ bail:
|
||||
return;
|
||||
}
|
||||
|
||||
//display error window
|
||||
-(void)displayErrorWindow:(NSDictionary*)errorInfo
|
||||
{
|
||||
//alloc error window
|
||||
errorWindowController = [[ErrorWindowController alloc] initWithWindowNibName:@"ErrorWindowController"];
|
||||
|
||||
//main thread
|
||||
// just show UI alert, unless its fatal (then load URL)
|
||||
if(YES == [NSThread isMainThread])
|
||||
{
|
||||
//non-fatal errors
|
||||
// show error error popup
|
||||
if(YES != [errorInfo[KEY_ERROR_URL] isEqualToString:FATAL_ERROR_URL])
|
||||
{
|
||||
//display it
|
||||
// call this first to so that outlets are connected
|
||||
[self.errorWindowController display];
|
||||
|
||||
//configure it
|
||||
[self.errorWindowController configure:errorInfo];
|
||||
}
|
||||
//fatal error
|
||||
// launch browser to go to fatal error page, then exit
|
||||
else
|
||||
{
|
||||
//launch browser
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:errorInfo[KEY_ERROR_URL]]];
|
||||
|
||||
//then exit
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
}
|
||||
//background thread
|
||||
// have to show error window on main thread
|
||||
else
|
||||
{
|
||||
//show alert
|
||||
// in main UI thread
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
|
||||
//display it
|
||||
// call this first to so that outlets are connected
|
||||
[self.errorWindowController display];
|
||||
|
||||
//configure it
|
||||
[self.errorWindowController configure:errorInfo];
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//menu handler for 'about'
|
||||
-(IBAction)displayAboutWindow:(id)sender
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14109" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14109"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -22,7 +22,7 @@
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" texturedBackground="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="460" height="176"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||
<view key="contentView" id="se5-gp-TjO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="460" height="176"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
//
|
||||
// file: ErrorWindowController.h
|
||||
// project: DND (config)
|
||||
// description: error window (header)
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
@import Cocoa;
|
||||
|
||||
@interface ErrorWindowController : NSWindowController <NSWindowDelegate>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//main msg in window
|
||||
@property (weak, atomic) IBOutlet NSTextField *errMsg;
|
||||
|
||||
//sub msg in window
|
||||
@property (weak, atomic) IBOutlet NSTextField *errSubMsg;
|
||||
|
||||
//info/help/fix button
|
||||
@property (weak, atomic) IBOutlet NSButton *infoButton;
|
||||
|
||||
//close button
|
||||
@property (weak, atomic) IBOutlet NSButton *closeButton;
|
||||
|
||||
//(optional) url for 'Info' button
|
||||
@property(nonatomic, retain) NSURL* errorURL;
|
||||
|
||||
//flag indicating close button should exit app
|
||||
@property(atomic) BOOL shouldExit;
|
||||
|
||||
/* METHODS */
|
||||
|
||||
//configure the object/window
|
||||
-(void)configure:(NSDictionary*)errorInfo;
|
||||
|
||||
//display (show) window
|
||||
-(void)display;
|
||||
|
||||
@end
|
||||
@@ -1,156 +0,0 @@
|
||||
//
|
||||
// file: ErrorWindowController.m
|
||||
// project: DND (config)
|
||||
// description: error window
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
#import "Consts.h"
|
||||
#import "ErrorWindowController.h"
|
||||
|
||||
@interface ErrorWindowController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation ErrorWindowController
|
||||
|
||||
@synthesize errorURL;
|
||||
@synthesize shouldExit;
|
||||
@synthesize closeButton;
|
||||
|
||||
//automatically called when nib is loaded
|
||||
// center window
|
||||
-(void)awakeFromNib
|
||||
{
|
||||
//center
|
||||
[self.window center];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//configure the object/window
|
||||
-(void)configure:(NSDictionary*)errorInfo
|
||||
{
|
||||
//set error msg
|
||||
self.errMsg.stringValue = errorInfo[KEY_ERROR_MSG];
|
||||
|
||||
//set error sub msg
|
||||
self.errSubMsg.stringValue = errorInfo[KEY_ERROR_SUB_MSG];
|
||||
|
||||
//save exit
|
||||
self.shouldExit = [errorInfo[KEY_ERROR_SHOULD_EXIT] boolValue];
|
||||
|
||||
//grab optional error url
|
||||
if(nil != errorInfo[KEY_ERROR_URL])
|
||||
{
|
||||
//extract/convert
|
||||
self.errorURL = [NSURL URLWithString:errorInfo[KEY_ERROR_URL]];
|
||||
}
|
||||
|
||||
//when exiting
|
||||
// change 'close' to 'exit'
|
||||
if(YES == self.shouldExit)
|
||||
{
|
||||
//change title
|
||||
self.closeButton.title = @"Exit";
|
||||
}
|
||||
|
||||
//for fatal errors
|
||||
// change 'Info' to 'help fix'
|
||||
if(YES == [[self.errorURL absoluteString] isEqualToString:FATAL_ERROR_URL])
|
||||
{
|
||||
//change title
|
||||
self.infoButton.title = @"Help Fix";
|
||||
}
|
||||
|
||||
//set delegate
|
||||
[self.window setDelegate:self];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//display (show) window
|
||||
-(void)display
|
||||
{
|
||||
//show (now configured), alert
|
||||
[self showWindow:self];
|
||||
|
||||
//make it key window
|
||||
[self.window makeKeyAndOrderFront:self];
|
||||
|
||||
//make window front
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
//make 'close' have focus
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 100 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
|
||||
|
||||
//make close button active
|
||||
[self.window makeFirstResponder:self.closeButton];
|
||||
|
||||
});
|
||||
|
||||
//make white
|
||||
[self.window setBackgroundColor: NSColor.whiteColor];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//invoked when user clicks '?' (help button)
|
||||
// open url with more info about the error(s)
|
||||
-(IBAction)help:(id)sender
|
||||
{
|
||||
#pragma unused(sender)
|
||||
|
||||
//if a url was specified
|
||||
// use that one
|
||||
if(nil != self.errorURL)
|
||||
{
|
||||
//open URL
|
||||
// invokes user's default browser
|
||||
[[NSWorkspace sharedWorkspace] openURL:self.errorURL];
|
||||
}
|
||||
//use default URL
|
||||
else
|
||||
{
|
||||
//open URL
|
||||
// invokes user's default browser
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:FATAL_ERROR_URL]];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//invoked when user clicks 'close'
|
||||
// just close window
|
||||
-(IBAction)close:(id)sender
|
||||
{
|
||||
#pragma unused(sender)
|
||||
|
||||
//close
|
||||
[self.window close];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//automatically invoked when window is closing
|
||||
// exit the app if specified...
|
||||
-(void)windowWillClose:(NSNotification *)notification
|
||||
{
|
||||
#pragma unused(notification)
|
||||
|
||||
//check if should exit process
|
||||
// e.g. an error during install, etc
|
||||
if(YES == self.shouldExit)
|
||||
{
|
||||
//dbg msg
|
||||
//logMsg(LOG_DEBUG, @"exiting application");
|
||||
|
||||
//exit
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,85 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="13771" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13771"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="ErrorWindowController">
|
||||
<connections>
|
||||
<outlet property="closeButton" destination="zbs-ul-WTJ" id="1fu-zv-brA"/>
|
||||
<outlet property="errMsg" destination="Act-U9-8G9" id="PMa-6M-gwu"/>
|
||||
<outlet property="errSubMsg" destination="tQ0-f2-G4C" id="4hz-9M-Gub"/>
|
||||
<outlet property="infoButton" destination="sNV-Jw-9dZ" id="qdf-xQ-ubf"/>
|
||||
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<window title="Do Not Disturb Error" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" texturedBackground="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="744" y="427" width="380" height="137"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<view key="contentView" id="se5-gp-TjO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="380" height="137"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zbs-ul-WTJ">
|
||||
<rect key="frame" x="284" y="13" width="82" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Close" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Pjp-Se-SfK">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="close:" target="-2" id="sez-MW-4AE"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="tQ0-f2-G4C">
|
||||
<rect key="frame" x="114" y="49" width="248" height="36"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Label" id="sk0-EF-ZfG">
|
||||
<font key="font" size="11" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="0.0" translatesAutoresizingMaskIntoConstraints="NO" id="Act-U9-8G9">
|
||||
<rect key="frame" x="114" y="88" width="248" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="ERROR msg" id="VCu-zh-Vcs">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
<color key="textColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="sNV-Jw-9dZ">
|
||||
<rect key="frame" x="202" y="13" width="82" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Info" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="L1w-RB-EC4">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="help:" target="-2" id="gCm-No-dHq"/>
|
||||
</connections>
|
||||
</button>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="sRj-I0-15e">
|
||||
<rect key="frame" x="12" y="35" width="92" height="92"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="dndIcon" id="9iG-ot-b7i"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="-2" id="0bl-1N-AYu"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="257" y="269.5"/>
|
||||
</window>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="dndIcon" width="256" height="256"/>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -16,12 +16,10 @@
|
||||
BF04235611C0531400431286 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BF04235511C0531400431286 /* AppDelegate.m */; };
|
||||
BF65C19111B985C0007C20AB /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF65C19011B985C0007C20AB /* MainMenu.xib */; };
|
||||
CD17D53B20104DD700F798D7 /* Logging.m in Sources */ = {isa = PBXBuildFile; fileRef = CD17D53820104DD700F798D7 /* Logging.m */; };
|
||||
CD17D54D20104EE700F798D7 /* ErrorWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD17D54320104EE600F798D7 /* ErrorWindowController.xib */; };
|
||||
CD17D54E20104EE700F798D7 /* AboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD17D54420104EE700F798D7 /* AboutWindow.xib */; };
|
||||
CD17D54F20104EE700F798D7 /* Configure.m in Sources */ = {isa = PBXBuildFile; fileRef = CD17D54720104EE700F798D7 /* Configure.m */; };
|
||||
CD17D55020104EE700F798D7 /* ConfigureWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD17D54820104EE700F798D7 /* ConfigureWindowController.m */; };
|
||||
CD17D55120104EE700F798D7 /* ConfigureWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CD17D54920104EE700F798D7 /* ConfigureWindowController.xib */; };
|
||||
CD17D55220104EE700F798D7 /* ErrorWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD17D54A20104EE700F798D7 /* ErrorWindowController.m */; };
|
||||
CD17D55320104EE700F798D7 /* AboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD17D54B20104EE700F798D7 /* AboutWindowController.m */; };
|
||||
CD17D55E201148F900F798D7 /* configure.sh in Resources */ = {isa = PBXBuildFile; fileRef = CD17D55D201148F900F798D7 /* configure.sh */; };
|
||||
CD17D56320116C3800F798D7 /* com.objective-see.dnd.plist in Resources */ = {isa = PBXBuildFile; fileRef = CD17D56220116C3800F798D7 /* com.objective-see.dnd.plist */; };
|
||||
@@ -95,16 +93,13 @@
|
||||
CD17D53A20104DD700F798D7 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../shared/Logging.h; sourceTree = "<group>"; };
|
||||
CD17D53E20104E5A00F798D7 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Consts.h; path = ../../shared/Consts.h; sourceTree = "<group>"; };
|
||||
CD17D54220104EE600F798D7 /* AboutWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboutWindowController.h; sourceTree = "<group>"; };
|
||||
CD17D54320104EE600F798D7 /* ErrorWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ErrorWindowController.xib; sourceTree = "<group>"; };
|
||||
CD17D54420104EE700F798D7 /* AboutWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AboutWindow.xib; sourceTree = "<group>"; };
|
||||
CD17D54520104EE700F798D7 /* Configure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Configure.h; sourceTree = "<group>"; };
|
||||
CD17D54620104EE700F798D7 /* ConfigureWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConfigureWindowController.h; sourceTree = "<group>"; };
|
||||
CD17D54720104EE700F798D7 /* Configure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Configure.m; sourceTree = "<group>"; };
|
||||
CD17D54820104EE700F798D7 /* ConfigureWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConfigureWindowController.m; sourceTree = "<group>"; };
|
||||
CD17D54920104EE700F798D7 /* ConfigureWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ConfigureWindowController.xib; sourceTree = "<group>"; };
|
||||
CD17D54A20104EE700F798D7 /* ErrorWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ErrorWindowController.m; sourceTree = "<group>"; };
|
||||
CD17D54B20104EE700F798D7 /* AboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AboutWindowController.m; sourceTree = "<group>"; };
|
||||
CD17D54C20104EE700F798D7 /* ErrorWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ErrorWindowController.h; sourceTree = "<group>"; };
|
||||
CD17D55D201148F900F798D7 /* configure.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = configure.sh; sourceTree = "<group>"; };
|
||||
CD17D56220116C3800F798D7 /* com.objective-see.dnd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "com.objective-see.dnd.plist"; path = "../launchDaemon/launchDaemon/com.objective-see.dnd.plist"; sourceTree = "<group>"; };
|
||||
CD18D64C200DA301005609F9 /* XPCProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = XPCProtocol.h; path = Shared/XPCProtocol.h; sourceTree = SOURCE_ROOT; };
|
||||
@@ -192,9 +187,6 @@
|
||||
CD17D54620104EE700F798D7 /* ConfigureWindowController.h */,
|
||||
CD17D54820104EE700F798D7 /* ConfigureWindowController.m */,
|
||||
CD17D54920104EE700F798D7 /* ConfigureWindowController.xib */,
|
||||
CD17D54C20104EE700F798D7 /* ErrorWindowController.h */,
|
||||
CD17D54A20104EE700F798D7 /* ErrorWindowController.m */,
|
||||
CD17D54320104EE600F798D7 /* ErrorWindowController.xib */,
|
||||
CD73DA98200490B4001FFC84 /* HelperComms.h */,
|
||||
CD73DA97200490B4001FFC84 /* HelperComms.m */,
|
||||
4BE4904C10445D49006BE471 /* Info.plist */,
|
||||
@@ -344,7 +336,6 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CD2F4082204B462E0066673E /* dndText.png in Resources */,
|
||||
CD17D54D20104EE700F798D7 /* ErrorWindowController.xib in Resources */,
|
||||
CDAAC24C20226DFB0032F2E6 /* logo.png in Resources */,
|
||||
CD17D56320116C3800F798D7 /* com.objective-see.dnd.plist in Resources */,
|
||||
CDAAC24B20226DFB0032F2E6 /* objectiveSee.png in Resources */,
|
||||
@@ -392,7 +383,6 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CD17D55220104EE700F798D7 /* ErrorWindowController.m in Sources */,
|
||||
4BE4905110445D49006BE471 /* main.m in Sources */,
|
||||
CD73DA942004633A001FFC84 /* HelperListener.m in Sources */,
|
||||
CD17D55320104EE700F798D7 /* AboutWindowController.m in Sources */,
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
<string>Copyright © 2018 Objective-See. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string></string>
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
||||
@@ -55,8 +55,11 @@
|
||||
CD256E062050DE9B00768457 /* ThunderboltMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = CD256DF32050DE4C00768457 /* ThunderboltMonitor.m */; };
|
||||
CD256E072050DE9B00768457 /* USBMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = CD256DF52050DE4C00768457 /* USBMonitor.m */; };
|
||||
CD256E082050DE9B00768457 /* UserAuthMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = CD256DED2050DE4B00768457 /* UserAuthMonitor.m */; };
|
||||
CD2C85F42119D9D5007CF784 /* LidTrigger.m in Sources */ = {isa = PBXBuildFile; fileRef = CD27BC6321139AD70017AEFD /* LidTrigger.m */; };
|
||||
CD2C85F82119FC02007CF784 /* DeviceTrigger.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2C85F52119FB2A007CF784 /* DeviceTrigger.m */; };
|
||||
CD2C85FC211A0084007CF784 /* PowerTrigger.m in Sources */ = {isa = PBXBuildFile; fileRef = CD2C85FA211A006F007CF784 /* PowerTrigger.m */; };
|
||||
CDA993A62048905D00C1E9CD /* FrameworkInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CDA993A42048905D00C1E9CD /* FrameworkInterface.m */; };
|
||||
CE60F9C91FC9BBE500EFFDDA /* Lid.m in Sources */ = {isa = PBXBuildFile; fileRef = CE60F9C81FC9BBE500EFFDDA /* Lid.m */; };
|
||||
CE60F9C91FC9BBE500EFFDDA /* Triggers.m in Sources */ = {isa = PBXBuildFile; fileRef = CE60F9C81FC9BBE500EFFDDA /* Triggers.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -179,13 +182,19 @@
|
||||
CD256DF82050DE4C00768457 /* Monitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Monitor.h; path = launchDaemon/monitor/Monitor.h; sourceTree = SOURCE_ROOT; };
|
||||
CD256DFF2050DE6600768457 /* ProcListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcListener.h; path = launchDaemon/monitor/ProcListener.h; sourceTree = SOURCE_ROOT; };
|
||||
CD256E002050DE6600768457 /* ProcListener.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProcListener.m; path = launchDaemon/monitor/ProcListener.m; sourceTree = SOURCE_ROOT; };
|
||||
CD27BC6321139AD70017AEFD /* LidTrigger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LidTrigger.m; path = triggers/LidTrigger.m; sourceTree = "<group>"; };
|
||||
CD27BC6421139AD70017AEFD /* LidTrigger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LidTrigger.h; path = triggers/LidTrigger.h; sourceTree = "<group>"; };
|
||||
CD2C85F52119FB2A007CF784 /* DeviceTrigger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DeviceTrigger.m; path = triggers/DeviceTrigger.m; sourceTree = "<group>"; };
|
||||
CD2C85F62119FB2A007CF784 /* DeviceTrigger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeviceTrigger.h; path = triggers/DeviceTrigger.h; sourceTree = "<group>"; };
|
||||
CD2C85F9211A006F007CF784 /* PowerTrigger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PowerTrigger.h; path = triggers/PowerTrigger.h; sourceTree = "<group>"; };
|
||||
CD2C85FA211A006F007CF784 /* PowerTrigger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PowerTrigger.m; path = triggers/PowerTrigger.m; sourceTree = "<group>"; };
|
||||
CD3307C5203639AD00F10D71 /* procInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = procInfo.h; path = launchDaemon/libs/procInfo.h; sourceTree = "<group>"; };
|
||||
CD3307C82036518400F10D71 /* main.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = "<group>"; };
|
||||
CDA993A32048905D00C1E9CD /* FrameworkInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameworkInterface.h; sourceTree = "<group>"; };
|
||||
CDA993A42048905D00C1E9CD /* FrameworkInterface.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FrameworkInterface.m; sourceTree = "<group>"; };
|
||||
CDAAC245202259B50032F2E6 /* Consts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Consts.h; path = ../../shared/Consts.h; sourceTree = "<group>"; };
|
||||
CE60F9C71FC9BBE500EFFDDA /* Lid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Lid.h; sourceTree = "<group>"; };
|
||||
CE60F9C81FC9BBE500EFFDDA /* Lid.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Lid.m; sourceTree = "<group>"; };
|
||||
CE60F9C71FC9BBE500EFFDDA /* Triggers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Triggers.h; sourceTree = "<group>"; };
|
||||
CE60F9C81FC9BBE500EFFDDA /* Triggers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Triggers.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -277,12 +286,13 @@
|
||||
7D7755D21F02DF9500D0017D /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CD27BC6221139A800017AEFD /* triggers */,
|
||||
CD256DEC2050DE3200768457 /* monitor */,
|
||||
7D7756071F05D62E00D0017D /* shared */,
|
||||
7DD2BF721F1E9CE700B33214 /* NSMutableArray+QueueAdditions.h */,
|
||||
7DD2BF731F1E9CE700B33214 /* NSMutableArray+QueueAdditions.m */,
|
||||
CE60F9C71FC9BBE500EFFDDA /* Lid.h */,
|
||||
CE60F9C81FC9BBE500EFFDDA /* Lid.m */,
|
||||
CE60F9C71FC9BBE500EFFDDA /* Triggers.h */,
|
||||
CE60F9C81FC9BBE500EFFDDA /* Triggers.m */,
|
||||
CDA993A32048905D00C1E9CD /* FrameworkInterface.h */,
|
||||
CDA993A42048905D00C1E9CD /* FrameworkInterface.m */,
|
||||
CD227869204648E000C72C76 /* Preferences.h */,
|
||||
@@ -336,6 +346,19 @@
|
||||
path = monitor;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CD27BC6221139A800017AEFD /* triggers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CD2C85F9211A006F007CF784 /* PowerTrigger.h */,
|
||||
CD2C85FA211A006F007CF784 /* PowerTrigger.m */,
|
||||
CD2C85F62119FB2A007CF784 /* DeviceTrigger.h */,
|
||||
CD2C85F52119FB2A007CF784 /* DeviceTrigger.m */,
|
||||
CD27BC6421139AD70017AEFD /* LidTrigger.h */,
|
||||
CD27BC6321139AD70017AEFD /* LidTrigger.m */,
|
||||
);
|
||||
name = triggers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
CD3307C42036399900F10D71 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -446,6 +469,9 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CD2C85FC211A0084007CF784 /* PowerTrigger.m in Sources */,
|
||||
CD2C85F82119FC02007CF784 /* DeviceTrigger.m in Sources */,
|
||||
CD2C85F42119D9D5007CF784 /* LidTrigger.m in Sources */,
|
||||
CD20869B208E8F0200BA1D0A /* VolumeMonitor.m in Sources */,
|
||||
CD256E022050DE9B00768457 /* ProcListener.m in Sources */,
|
||||
CD256E032050DE9B00768457 /* AuthEvent.m in Sources */,
|
||||
@@ -457,7 +483,7 @@
|
||||
CD22786C20464A6E00C72C76 /* Preferences.m in Sources */,
|
||||
CDA993A62048905D00C1E9CD /* FrameworkInterface.m in Sources */,
|
||||
7D46FEFF1F5E41F000FEB0F8 /* UserCommsListener.m in Sources */,
|
||||
CE60F9C91FC9BBE500EFFDDA /* Lid.m in Sources */,
|
||||
CE60F9C91FC9BBE500EFFDDA /* Triggers.m in Sources */,
|
||||
7DD2BF761F1E9CE700B33214 /* NSMutableArray+QueueAdditions.m in Sources */,
|
||||
7DD2BF681F1DC42700B33214 /* Utilities.m in Sources */,
|
||||
7DD2BF771F1E9CE700B33214 /* Queue.m in Sources */,
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Lid.h"
|
||||
#import "consts.h"
|
||||
#import "logging.h"
|
||||
#import "Triggers.h"
|
||||
#import "Preferences.h"
|
||||
#import "FrameworkInterface.h"
|
||||
|
||||
/* GLOBALS */
|
||||
|
||||
//lid obj
|
||||
extern Lid* lid;
|
||||
//trigger obj
|
||||
extern Triggers* triggers;
|
||||
|
||||
//DND framework interface obj
|
||||
extern FrameworkInterface* framework;
|
||||
@@ -160,28 +160,27 @@ bail:
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"updating preferences (%@)", updates]);
|
||||
|
||||
//user setting state?
|
||||
// toggle the state of the daemon (lid) watcher too
|
||||
// toggle the state of the daemon triggers too
|
||||
if(nil != updates[PREF_IS_DISABLED])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"client toggling state: %@", updates[PREF_IS_DISABLED]]);
|
||||
|
||||
//disable?
|
||||
//disable triggers
|
||||
if(YES == [updates[PREF_IS_DISABLED] boolValue])
|
||||
{
|
||||
//dbg msg
|
||||
// and log to file
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, @"disabling...");
|
||||
|
||||
//unregister for lid notifications
|
||||
[lid unregister4Notifications];
|
||||
//turn off all triggers
|
||||
[triggers toggle:ALL_TRIGGERS state:NSOffState];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"unregistered for lid change notifications");
|
||||
logMsg(LOG_DEBUG, @"disabled triggers");
|
||||
|
||||
//cancel all lid notifications
|
||||
// ...will also disconnect client
|
||||
[lid cancelDispatchBlocks];
|
||||
//cancel all dispatch blocks
|
||||
[triggers cancelDispatchBlocks];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"cancelled all dispatch blocks (disconnecting any connected iOS client)");
|
||||
@@ -190,18 +189,81 @@ bail:
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:DISMISS_NOTIFICATION object:nil userInfo:nil];
|
||||
}
|
||||
|
||||
//enable?
|
||||
//enable triggers
|
||||
else
|
||||
{
|
||||
//dbg msg
|
||||
// and log to file
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, @"enabling...");
|
||||
|
||||
//register for lid notifications
|
||||
[lid register4Notifications];
|
||||
|
||||
//turn off all triggers
|
||||
[triggers toggle:ALL_TRIGGERS state:NSOnState];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"registered for lid change notifications");
|
||||
logMsg(LOG_DEBUG, @"enabled (all) triggers");
|
||||
}
|
||||
}
|
||||
|
||||
//toggle lid triggers
|
||||
if(nil != updates[PREF_LID_TRIGGER])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"toggling lid notifications");
|
||||
|
||||
//enable lid trigger
|
||||
if(YES == [updates[PREF_LID_TRIGGER] boolValue])
|
||||
{
|
||||
//enable
|
||||
[triggers toggle:LID_TRIGGER state:NSOnState];
|
||||
}
|
||||
|
||||
//disable lid trigger
|
||||
else
|
||||
{
|
||||
//disable
|
||||
[triggers toggle:LID_TRIGGER state:NSOffState];
|
||||
}
|
||||
}
|
||||
|
||||
//toggle device triggers
|
||||
if(nil != updates[PREF_DEVICE_TRIGGER])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"toggling device notifications");
|
||||
|
||||
//enable device trigger
|
||||
if(YES == [updates[PREF_DEVICE_TRIGGER] boolValue])
|
||||
{
|
||||
//enable
|
||||
[triggers toggle:DEVICE_TRIGGER state:NSOnState];
|
||||
}
|
||||
|
||||
//disable device trigger
|
||||
else
|
||||
{
|
||||
//disable
|
||||
[triggers toggle:DEVICE_TRIGGER state:NSOffState];
|
||||
}
|
||||
}
|
||||
|
||||
//toggle power triggers
|
||||
if(nil != updates[PREF_POWER_TRIGGER])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"toggling power notifications");
|
||||
|
||||
//enable power trigger
|
||||
if(YES == [updates[PREF_POWER_TRIGGER] boolValue])
|
||||
{
|
||||
//enable
|
||||
[triggers toggle:POWER_TRIGGER state:NSOnState];
|
||||
}
|
||||
|
||||
//disable power trigger
|
||||
else
|
||||
{
|
||||
//disable
|
||||
[triggers toggle:POWER_TRIGGER state:NSOffState];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
//
|
||||
// file: Lid.h
|
||||
// file: Triggers.m
|
||||
// project: DND (launch daemon)
|
||||
// description: monitor and alert logic for lid open events (header)
|
||||
// description: generic management of various triggers (header)
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Utilities.h"
|
||||
#import "LidTrigger.h"
|
||||
#import "PowerTrigger.h"
|
||||
#import "DeviceTrigger.h"
|
||||
#import <dnd/dnd-Swift.h>
|
||||
|
||||
@import Foundation;
|
||||
|
||||
#import <IOKit/IOKitLib.h>
|
||||
#import <IOKit/pwr_mgt/IOPM.h>
|
||||
|
||||
/* FUNCTIONS */
|
||||
|
||||
//check if user auth'd
|
||||
@@ -24,26 +23,25 @@ BOOL authViaTouchID(void);
|
||||
|
||||
/* CLASS INTERFACE */
|
||||
|
||||
@interface Lid : NSObject <DNDClientMacDelegate>
|
||||
@interface Triggers : NSObject <DNDClientMacDelegate>
|
||||
{
|
||||
//lid state
|
||||
LidState lidState;
|
||||
|
||||
//dispatch queue
|
||||
dispatch_queue_t dispatchQ;
|
||||
|
||||
//notification port
|
||||
IONotificationPortRef notificationPort;
|
||||
|
||||
//notification object
|
||||
io_object_t notification;
|
||||
|
||||
}
|
||||
|
||||
/* PROPERTIES */
|
||||
|
||||
//lid trigger obj
|
||||
@property(nonatomic, retain)LidTrigger* lidTrigger;
|
||||
|
||||
//device(s) trigger obj
|
||||
@property(nonatomic, retain)DeviceTrigger* deviceTrigger;
|
||||
|
||||
//power trigger obj
|
||||
@property(nonatomic, retain)PowerTrigger* powerTrigger;
|
||||
|
||||
|
||||
//client
|
||||
@property(nonatomic, retain)DNDClientMac *client;
|
||||
@property(nonatomic, retain)DNDClientMac* client;
|
||||
|
||||
//dismiss dispatch group
|
||||
@property(nonatomic, retain)dispatch_group_t dispatchGroup;
|
||||
@@ -54,11 +52,15 @@ BOOL authViaTouchID(void);
|
||||
//dispatch blocks
|
||||
@property(nonatomic, retain)NSMutableArray* dispatchBlocks;
|
||||
|
||||
//TODO: make dictionary w/ alert
|
||||
//latest undeliveried alert
|
||||
@property(nonatomic, retain)NSDate* undeliveredAlert;
|
||||
|
||||
/* METHODS */
|
||||
|
||||
//toggle trigger(s)
|
||||
-(void)toggle:(NSUInteger)type state:(NSControlStateValue)state;
|
||||
|
||||
//check if client should be init'd
|
||||
-(BOOL)shouldInitClient;
|
||||
|
||||
@@ -68,14 +70,8 @@ BOOL authViaTouchID(void);
|
||||
//cancel all dipatch blocks
|
||||
-(void)cancelDispatchBlocks;
|
||||
|
||||
//register for notifications
|
||||
-(BOOL)register4Notifications;
|
||||
|
||||
//register for notifications
|
||||
-(void)unregister4Notifications;
|
||||
|
||||
//proces lid open event
|
||||
-(void)processEvent:(NSDate*)timestamp user:(NSString*)user;
|
||||
//process trigger event
|
||||
-(void)processEvent:(NSUInteger)type info:(NSDictionary*)info;
|
||||
|
||||
//wait for dismiss
|
||||
// note: handles multiple client via dispatch group
|
||||
@@ -1,19 +1,16 @@
|
||||
// file: Lid.m
|
||||
// file: Triggers.m
|
||||
// project: DND (launch daemon)
|
||||
// description: monitor and alert logic for lid open events
|
||||
// description: generic management of various triggers
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
// code inspired by:
|
||||
// https://github.com/zarigani/ClamshellWake/blob/master/ClamshellWake.cpp
|
||||
// https://github.com/dustinrue/ControlPlane/blob/master/Source/LaptopLidEvidenceSource.m
|
||||
|
||||
// note: manually get state from terminal via:
|
||||
// ioreg -r -k AppleClamshellState -d 4 | grep AppleClamshellState
|
||||
|
||||
#import "Lid.h"
|
||||
#import "Consts.h"
|
||||
#import "Queue.h"
|
||||
#import "Logging.h"
|
||||
#import "Monitor.h"
|
||||
#import "Triggers.h"
|
||||
#import "AuthEvent.h"
|
||||
#import "Utilities.h"
|
||||
#import "Preferences.h"
|
||||
@@ -22,12 +19,8 @@
|
||||
|
||||
/* GLOBALS */
|
||||
|
||||
//last state
|
||||
// sometimes multiple notifications are delivered!?
|
||||
LidState lastLidState;
|
||||
|
||||
//lid obj
|
||||
extern Lid* lid;
|
||||
//trigger obj
|
||||
extern Triggers* triggers;
|
||||
|
||||
//queue object
|
||||
extern Queue* eventQueue;
|
||||
@@ -41,123 +34,6 @@ extern Preferences* preferences;
|
||||
//DND framework interface obj
|
||||
extern FrameworkInterface* framework;
|
||||
|
||||
//callback for power/lid events
|
||||
static void pmDomainChange(void *refcon, io_service_t service, uint32_t messageType, void *messageArgument)
|
||||
{
|
||||
//lid state
|
||||
int lidState = stateUnavailable;
|
||||
|
||||
//sleep bit
|
||||
int sleepState = -1;
|
||||
|
||||
//preferences
|
||||
NSDictionary* currentPrefs = nil;
|
||||
|
||||
//timestamp
|
||||
NSDate* timestamp = nil;
|
||||
|
||||
//init timestamp
|
||||
timestamp = [NSDate date];
|
||||
|
||||
//ignore any messages that are related to lid state
|
||||
if(kIOPMMessageClamshellStateChange != messageType)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"got 'kIOPMMessageClamshellStateChange' message");
|
||||
|
||||
//get prefs
|
||||
currentPrefs = [preferences get:nil];
|
||||
|
||||
//if user explicity set disabled
|
||||
// bail here, to ignore everything
|
||||
if(YES == [currentPrefs[PREF_IS_DISABLED] boolValue])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"client disabled DND, so ignoring lid event");
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//get state
|
||||
lidState = ((int) messageArgument & kClamshellStateBit);
|
||||
|
||||
//get sleep state
|
||||
sleepState = !!(((int)messageArgument & kClamshellSleepBit));
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"lid state: %@ (sleep bit: %d)", (lidState) ? @"closed" : @"open", sleepState]);
|
||||
|
||||
//(new) open?
|
||||
// OS sometimes delivers 2x events, so ignore same same
|
||||
if( (stateOpen == lidState) &&
|
||||
(stateOpen != lastLidState) )
|
||||
{
|
||||
//ignore if lid isn't really open
|
||||
// on reboot, OS may deliver 'open' message if external monitors are connected
|
||||
if(stateOpen != getLidState())
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//update 'prev' state
|
||||
lastLidState = stateOpen;
|
||||
|
||||
//dbg msg
|
||||
// log to file
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"[NEW EVENT] lid state: open (sleep state: %d)", sleepState]);
|
||||
|
||||
//touch id mode?
|
||||
// wait up to 10 seconds, and ignore event if user auth'd via biometrics
|
||||
if(YES == [currentPrefs[PREF_TOUCHID_MODE] boolValue])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"'touch id' mode enabled, waiting up to 10 seconds for biometric auth event");
|
||||
|
||||
//user auth'd via touchID?
|
||||
// will wait for up to 10 seconds
|
||||
if(YES == authViaTouchID())
|
||||
{
|
||||
//dbg msg
|
||||
// log to file
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, @"user authenticated via touchID, so ignoring event");
|
||||
|
||||
//bail
|
||||
// will ignore the event
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"no touch id auth event found, so will process event");
|
||||
}
|
||||
|
||||
//process event
|
||||
// report to user, execute actions, etc
|
||||
[lid processEvent:timestamp user:getConsoleUser()];
|
||||
}
|
||||
|
||||
//(new) close?
|
||||
// OS sometimes delivers 2x events, so ignore same same
|
||||
else if( (stateClosed == lidState) &&
|
||||
(stateClosed != lastLidState) )
|
||||
{
|
||||
//update 'prev' state
|
||||
lastLidState = stateClosed;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"[NEW EVENT] lid state: closed (sleep state: %d)", sleepState]);
|
||||
}
|
||||
|
||||
bail:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//check if user auth'd
|
||||
// a) within last 10 seconds
|
||||
// b) via biometrics (touchID)
|
||||
@@ -230,7 +106,7 @@ BOOL authViaTouchID()
|
||||
});
|
||||
|
||||
//wait for touch id auth
|
||||
// ...up to five seconds
|
||||
// ...up to ten seconds for event
|
||||
dispatch_semaphore_wait(semaphore, dispatch_time(0, 10*NSEC_PER_SEC));
|
||||
|
||||
//tell user auth monitor to stop
|
||||
@@ -242,15 +118,19 @@ BOOL authViaTouchID()
|
||||
return touchIDAuth;
|
||||
}
|
||||
|
||||
@implementation Lid
|
||||
@implementation Triggers
|
||||
|
||||
|
||||
@synthesize client;
|
||||
|
||||
@synthesize lidTrigger;
|
||||
@synthesize powerTrigger;
|
||||
@synthesize deviceTrigger;
|
||||
@synthesize dispatchGroup;
|
||||
@synthesize dispatchBlocks;
|
||||
@synthesize undeliveredAlert;
|
||||
@synthesize dispatchGroupEmpty;
|
||||
|
||||
|
||||
//init
|
||||
-(id)init
|
||||
{
|
||||
@@ -258,21 +138,15 @@ BOOL authViaTouchID()
|
||||
self = [super init];
|
||||
if(nil != self)
|
||||
{
|
||||
//init
|
||||
dispatchQ = NULL;
|
||||
//init lid (trigger) obj
|
||||
lidTrigger = [[LidTrigger alloc] init];
|
||||
|
||||
//init
|
||||
notificationPort = NULL;
|
||||
//init device (trigger) obj
|
||||
deviceTrigger = [[DeviceTrigger alloc] init];
|
||||
|
||||
//init
|
||||
notification = 0;
|
||||
//init power (trigger) obj
|
||||
powerTrigger = [[PowerTrigger alloc] init];
|
||||
|
||||
//init to current state
|
||||
lastLidState = getLidState();
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"initial lid state: %d", lastLidState]);
|
||||
|
||||
//init dispatch group for dismiss events
|
||||
dispatchGroup = dispatch_group_create();
|
||||
|
||||
@@ -346,144 +220,86 @@ bail:
|
||||
return initialized;
|
||||
}
|
||||
|
||||
//register for notifications
|
||||
-(BOOL)register4Notifications
|
||||
//toggle trigger(s)
|
||||
-(void)toggle:(NSUInteger)type state:(NSControlStateValue)state
|
||||
{
|
||||
//return var
|
||||
BOOL registered = NO;
|
||||
//current prefs
|
||||
NSDictionary* currentPrefs = nil;
|
||||
|
||||
//status var
|
||||
kern_return_t status = kIOReturnError;
|
||||
//dbd msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"toggling trigger (type: %lu, state: %lu)", (unsigned long)type, state]);
|
||||
|
||||
//root domain for power management
|
||||
io_service_t powerManagementRD = MACH_PORT_NULL;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"registering for lid notifications");
|
||||
|
||||
//make sure state is ok
|
||||
if(stateUnavailable == getLidState())
|
||||
//enable based on type
|
||||
switch(type)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to get lid state, so aborting lid notifications registration");
|
||||
//all
|
||||
// based on triggers
|
||||
case ALL_TRIGGERS:
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"toggling all triggers");
|
||||
|
||||
//get current prefs
|
||||
currentPrefs = [preferences get:nil];
|
||||
|
||||
//lid trigger?
|
||||
if(YES == [currentPrefs[PREF_LID_TRIGGER] boolValue])
|
||||
{
|
||||
//toggle
|
||||
[self.lidTrigger toggle:state];
|
||||
}
|
||||
|
||||
//device trigger?
|
||||
if(YES == [currentPrefs[PREF_DEVICE_TRIGGER] boolValue])
|
||||
{
|
||||
//toggle
|
||||
[self.deviceTrigger toggle:state];
|
||||
}
|
||||
|
||||
//power trigger
|
||||
if(YES == [currentPrefs[PREF_POWER_TRIGGER] boolValue])
|
||||
{
|
||||
//toggle
|
||||
[self.powerTrigger toggle:state];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
//lid trigger
|
||||
case LID_TRIGGER:
|
||||
|
||||
//toggle
|
||||
[self.lidTrigger toggle:state];
|
||||
|
||||
break;
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
//device trigger
|
||||
case DEVICE_TRIGGER:
|
||||
|
||||
//toggle
|
||||
[self.deviceTrigger toggle:state];
|
||||
|
||||
break;
|
||||
|
||||
//power trigger
|
||||
case POWER_TRIGGER:
|
||||
|
||||
//toggle
|
||||
[self.powerTrigger toggle:state];
|
||||
|
||||
break;
|
||||
|
||||
//create queue
|
||||
dispatchQ = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
|
||||
if(NULL == dispatchQ)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to create dispatch queue for lid notifications");
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set target
|
||||
dispatch_set_target_queue(dispatchQ, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
|
||||
|
||||
//create notification port
|
||||
notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
|
||||
if(NULL == notificationPort)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to create notification port for lid notifications");
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set dispatch queue
|
||||
IONotificationPortSetDispatchQueue(notificationPort, dispatchQ);
|
||||
|
||||
//get matching service for power management root domain
|
||||
powerManagementRD = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMrootDomain"));
|
||||
if(0 == powerManagementRD)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to get power management root domain for lid notifications");
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//add interest notification
|
||||
status = IOServiceAddInterestNotification(notificationPort, powerManagementRD, kIOGeneralInterest,
|
||||
pmDomainChange, &lidState, ¬ification);
|
||||
if(KERN_SUCCESS != status)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to get add interest notifcation for lid notifications (error: 0x:%x)", status]);
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//happy
|
||||
registered = YES;
|
||||
|
||||
bail:
|
||||
|
||||
//release
|
||||
if(MACH_PORT_NULL != powerManagementRD)
|
||||
{
|
||||
//release
|
||||
IOObjectRelease(powerManagementRD);
|
||||
|
||||
//unset
|
||||
powerManagementRD = MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
return registered;
|
||||
}
|
||||
|
||||
//unregister for notifications
|
||||
-(void)unregister4Notifications
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"unregistering lid notifications");
|
||||
|
||||
//release notification
|
||||
if(0 != notification)
|
||||
{
|
||||
//release
|
||||
IOObjectRelease(notification);
|
||||
|
||||
//unset
|
||||
notification = 0;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"released service interest notification");
|
||||
}
|
||||
|
||||
//destroy notification port
|
||||
if(NULL != notificationPort)
|
||||
{
|
||||
//set queue to NULL
|
||||
IONotificationPortSetDispatchQueue(notificationPort, NULL);
|
||||
|
||||
//unset dispatch queue
|
||||
dispatchQ = NULL;
|
||||
|
||||
//destroy port
|
||||
IONotificationPortDestroy(notificationPort);
|
||||
|
||||
//unset
|
||||
notificationPort = NULL;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"destroyed notification port");
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//proces lid open event
|
||||
//proces trigger event
|
||||
// report to user, execute cmd, send alert to server, etc
|
||||
-(void)processEvent:(NSDate*)timestamp user:(NSString*)user
|
||||
-(void)processEvent:(NSUInteger)type info:(NSDictionary*)info
|
||||
{
|
||||
//monitor obj
|
||||
Monitor* monitor = nil;
|
||||
@@ -494,13 +310,38 @@ bail:
|
||||
//get current prefs
|
||||
currentPrefs = [preferences get:nil];
|
||||
|
||||
//auth mode?
|
||||
// wait up to 10 seconds, and ignore event if user auth'd via biometrics or apple watch
|
||||
if(YES == [currentPrefs[PREF_AUTH_MODE] boolValue])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"'auth' mode enabled, waiting up to 10 seconds for biometric auth || apple watch event");
|
||||
|
||||
//TODO: add apple watch
|
||||
|
||||
//user auth'd via touchID?
|
||||
// will wait for up to 10 seconds
|
||||
if(YES == authViaTouchID())
|
||||
{
|
||||
//dbg msg
|
||||
// log to file
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, @"user authenticated via touchID, so ignoring event");
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"no touch id auth event found, so will continue processing event");
|
||||
}
|
||||
|
||||
//only add events to queue
|
||||
// when client is not running in passive mode
|
||||
if(YES != [currentPrefs[PREF_PASSIVE_MODE] boolValue])
|
||||
{
|
||||
//add to global queue
|
||||
// this will trigger processing of alert to user
|
||||
[eventQueue enqueue:@{ALERT_TIMESTAMP:timestamp}];
|
||||
[eventQueue enqueue:@{ALERT_TYPE:[NSNumber numberWithInteger:type], ALERT_TIMESTAMP:[NSDate date], ALERT_INFO:info}];
|
||||
}
|
||||
//passive mode
|
||||
// just log a msg about this fact
|
||||
@@ -533,7 +374,6 @@ bail:
|
||||
if( (YES == [currentPrefs[PREF_EXECUTE_ACTION] boolValue]) &&
|
||||
(0 != [currentPrefs[PREF_EXECUTE_PATH] length] ) )
|
||||
{
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"executing: %@ as %@", currentPrefs[PREF_EXECUTE_PATH], currentPrefs[PREF_EXECUTE_USER]]);
|
||||
|
||||
@@ -565,7 +405,7 @@ bail:
|
||||
}
|
||||
|
||||
//registered device?
|
||||
// send to alert to server
|
||||
// send alert to server
|
||||
if(nil != self.client)
|
||||
{
|
||||
//dbg msg
|
||||
@@ -579,14 +419,14 @@ bail:
|
||||
logMsg(LOG_DEBUG, @"no (prev) alerts undelivered");
|
||||
|
||||
//save timestamp
|
||||
self.undeliveredAlert = timestamp;
|
||||
self.undeliveredAlert = [NSDate date];
|
||||
|
||||
//send to server
|
||||
// will wait up to x minutes if there's no network connectivity
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
//wait
|
||||
[self send2Server:user];
|
||||
[self send2Server:getConsoleUser()];
|
||||
|
||||
});
|
||||
}
|
||||
@@ -599,7 +439,7 @@ bail:
|
||||
logMsg(LOG_DEBUG, @"previously alert undelivered, just updating that...");
|
||||
|
||||
//save timestamp
|
||||
self.undeliveredAlert = timestamp;
|
||||
self.undeliveredAlert = [NSDate date];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,7 +448,7 @@ bail:
|
||||
else
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"did not send to server - no client/registered device");
|
||||
logMsg(LOG_DEBUG, @"did not send to server, as there's no client/registered device");
|
||||
}
|
||||
|
||||
bail:
|
||||
@@ -7,6 +7,8 @@
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
|
||||
/* FUNCTIONS */
|
||||
|
||||
//uninstall
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Lid.h"
|
||||
#import "main.h"
|
||||
#import "Consts.h"
|
||||
#import "Queue.h"
|
||||
#import "Consts.h"
|
||||
#import "Logging.h"
|
||||
#import "Triggers.h"
|
||||
#import "Utilities.h"
|
||||
#import "Preferences.h"
|
||||
#import "UserAuthMonitor.h"
|
||||
@@ -27,7 +27,7 @@ Preferences* preferences = nil;
|
||||
|
||||
//lid object
|
||||
// registers for notifications, gets state, etc
|
||||
Lid* lid = nil;
|
||||
Triggers* triggers = nil;
|
||||
|
||||
//queue object
|
||||
// contains watch items that should be processed
|
||||
@@ -48,7 +48,7 @@ int main(int argc, const char * argv[])
|
||||
{
|
||||
//return
|
||||
int result = -1;
|
||||
|
||||
|
||||
@autoreleasepool
|
||||
{
|
||||
//user comms listener (XPC) obj
|
||||
@@ -123,6 +123,7 @@ int main(int argc, const char * argv[])
|
||||
// allows to close logging, etc.
|
||||
register4Shutdown();
|
||||
|
||||
|
||||
//1st time identity generatation is done on demand
|
||||
// subsequent times though, can just always do here
|
||||
if(nil != currentPrefs[PREF_CLIENT_ID])
|
||||
@@ -141,30 +142,27 @@ int main(int argc, const char * argv[])
|
||||
logMsg(LOG_DEBUG, @"initialized DND identity");
|
||||
}
|
||||
|
||||
//init global lid object
|
||||
lid = [[Lid alloc] init];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"lid state: %d", getLidState()]);
|
||||
//init global triggers object
|
||||
triggers = [[Triggers alloc] init];
|
||||
|
||||
//not (prev) disabled?
|
||||
// register for lid notifications
|
||||
// toggle all triggers based on their setting
|
||||
if(YES != [currentPrefs[PREF_IS_DISABLED] boolValue])
|
||||
{
|
||||
//register for lid notifications
|
||||
[lid register4Notifications];
|
||||
//toggle all triggers
|
||||
[triggers toggle:ALL_TRIGGERS state:NSOnState];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"registered for lid change notifications");
|
||||
logMsg(LOG_DEBUG, @"toggled (all) triggers");
|
||||
}
|
||||
|
||||
//(prev) disabled
|
||||
else
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"currently disabled, so did not register for lid change notifications");
|
||||
logMsg(LOG_DEBUG, @"user set 'disabled' preference, so did not register for any triggers");
|
||||
}
|
||||
|
||||
|
||||
//init global queue
|
||||
eventQueue = [[Queue alloc] init];
|
||||
|
||||
@@ -185,9 +183,6 @@ int main(int argc, const char * argv[])
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"listening for client XPC connections");
|
||||
|
||||
//run loop
|
||||
[[NSRunLoop currentRunLoop] run];
|
||||
|
||||
}//pool
|
||||
|
||||
//happy
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// file: DeviceTrigger.h
|
||||
// project: DND (launch daemon)
|
||||
// description: monitor and alert logic for device insertion events (header)
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
@import Cocoa;
|
||||
@import Foundation;
|
||||
|
||||
#import <IOKit/usb/IOUSBLib.h>
|
||||
|
||||
/* CLASS INTERFACE */
|
||||
|
||||
@interface DeviceTrigger : NSObject
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* PROPERTIES */
|
||||
|
||||
//notification port
|
||||
@property(nonatomic)IONotificationPortRef notificationPort;
|
||||
|
||||
//callback for USB devices
|
||||
void usbAppeared(void *refCon, io_iterator_t iterator);
|
||||
|
||||
//run loop source
|
||||
@property(nonatomic)CFRunLoopSourceRef runLoopSource;
|
||||
|
||||
|
||||
/* METHODS */
|
||||
|
||||
//register for notifications
|
||||
-(BOOL)toggle:(NSControlStateValue)state;
|
||||
|
||||
//process new USB insertion
|
||||
// get info about device and log
|
||||
-(void)handleNewDevice:(io_iterator_t)iterator;
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,244 @@
|
||||
// file: DeviceTrigger.m
|
||||
// project: DND (launch daemon)
|
||||
// description: monitor and alert logic for device insertion events
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Consts.h"
|
||||
#import "Logging.h"
|
||||
#import "Triggers.h"
|
||||
#import "Utilities.h"
|
||||
#import "Preferences.h"
|
||||
#import "DeviceTrigger.h"
|
||||
|
||||
/* GLOBALS */
|
||||
|
||||
//triggers object
|
||||
extern Triggers* triggers;
|
||||
|
||||
//preferences obj
|
||||
extern Preferences* preferences;
|
||||
|
||||
@implementation DeviceTrigger
|
||||
|
||||
@synthesize runLoopSource;
|
||||
@synthesize notificationPort;
|
||||
|
||||
//callback for USB devices
|
||||
void usbAppeared(void *refCon, io_iterator_t iterator)
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"usb device inserted"]);
|
||||
|
||||
//process new device
|
||||
[(__bridge DeviceTrigger *)refCon handleNewDevice:iterator];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//toggle lid notifications
|
||||
-(BOOL)toggle:(NSControlStateValue)state
|
||||
{
|
||||
//flag
|
||||
BOOL wasToggled = NO;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"toggling devices notifications: %lu", state]);
|
||||
|
||||
//on?
|
||||
// enable
|
||||
if(NSOnState == state)
|
||||
{
|
||||
//enable
|
||||
wasToggled = [self enable];
|
||||
}
|
||||
//off
|
||||
// disable
|
||||
else
|
||||
{
|
||||
//disable
|
||||
[self disable];
|
||||
|
||||
//manually set flag
|
||||
wasToggled = YES;
|
||||
}
|
||||
|
||||
return wasToggled;
|
||||
}
|
||||
|
||||
//start USB monitoring
|
||||
-(BOOL)enable
|
||||
{
|
||||
//status
|
||||
BOOL initialized = NO;
|
||||
|
||||
//status
|
||||
kern_return_t status = kIOReturnError;
|
||||
|
||||
//iterator
|
||||
io_iterator_t iterator = 0;
|
||||
|
||||
//device
|
||||
io_service_t device = 0;
|
||||
|
||||
//create notification port
|
||||
self.notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
|
||||
|
||||
//get run loop source
|
||||
self.runLoopSource = IONotificationPortGetRunLoopSource(self.notificationPort);
|
||||
|
||||
//add source
|
||||
CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopDefaultMode);
|
||||
|
||||
//add notification
|
||||
// pass in 'self' so can access obj-c methods in callbacks
|
||||
status = IOServiceAddMatchingNotification(self.notificationPort, kIOMatchedNotification, IOServiceMatching(kIOUSBDeviceClassName), usbAppeared,(__bridge void *)self, &iterator);
|
||||
if(kIOReturnSuccess != status)
|
||||
{
|
||||
//err
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"IOServiceAddMatchingNotification() failed with %d", status]);
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//process existing devices
|
||||
// also 'drains' interator...
|
||||
device = IOIteratorNext(iterator);
|
||||
while(0 != device)
|
||||
{
|
||||
//record device name/properties
|
||||
//[self logDeviceProperties:device];
|
||||
|
||||
//release
|
||||
IOObjectRelease(device);
|
||||
|
||||
//get next
|
||||
device = IOIteratorNext(iterator);
|
||||
}
|
||||
|
||||
//happy
|
||||
initialized = YES;
|
||||
|
||||
bail:
|
||||
|
||||
return initialized;
|
||||
}
|
||||
|
||||
//stop
|
||||
// invalidate runloop src and notification port
|
||||
-(void)disable
|
||||
{
|
||||
//invalidate runloop src
|
||||
if(nil != self.runLoopSource)
|
||||
{
|
||||
//invalidate
|
||||
CFRunLoopSourceInvalidate(self.runLoopSource);
|
||||
|
||||
//unset
|
||||
self.runLoopSource = nil;
|
||||
}
|
||||
|
||||
//destroy notification port
|
||||
if(nil != self.notificationPort)
|
||||
{
|
||||
//destroy
|
||||
IONotificationPortDestroy(self.notificationPort);
|
||||
|
||||
//unset
|
||||
self.notificationPort = nil;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//process new USB insertion
|
||||
// get info about device and log
|
||||
-(void)handleNewDevice:(io_iterator_t)iterator
|
||||
{
|
||||
//usb device
|
||||
io_service_t device;
|
||||
|
||||
//device name
|
||||
io_name_t deviceName = {0};
|
||||
|
||||
//timestamp
|
||||
NSDate* timestamp = nil;
|
||||
|
||||
//process
|
||||
while((device = IOIteratorNext(iterator)))
|
||||
{
|
||||
//reset
|
||||
bzero(deviceName, sizeof(io_name_t));
|
||||
|
||||
//init timestamp
|
||||
timestamp = [NSDate date];
|
||||
|
||||
//get device name
|
||||
if(KERN_SUCCESS != IORegistryEntryGetName(device, deviceName))
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to get usb device name");
|
||||
|
||||
//set to unknown
|
||||
strncpy(deviceName, "<unknown>", sizeof(io_name_t)-1);
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
// log to file
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"[NEW EVENT] usb inserted: \"%s\"", deviceName]);
|
||||
|
||||
//process event
|
||||
// report to user, server, execute actions, etc.
|
||||
[triggers processEvent:DEVICE_TRIGGER info:@{KEY_DEVICE_NAME:[NSString stringWithUTF8String:deviceName]}];
|
||||
|
||||
//release device
|
||||
IOObjectRelease(device);
|
||||
|
||||
//unset
|
||||
device = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//log name/properties of a device
|
||||
-(void)logDeviceProperties:(io_service_t)device
|
||||
{
|
||||
//device name
|
||||
io_name_t deviceName = {0};
|
||||
|
||||
//device properties
|
||||
CFMutableDictionaryRef deviceProperties = NULL;
|
||||
|
||||
//get device name
|
||||
if(KERN_SUCCESS == IORegistryEntryGetName(device, deviceName))
|
||||
{
|
||||
//dbg msg & log
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"usb device name: %s", deviceName]);
|
||||
}
|
||||
|
||||
//get device properties
|
||||
if( (kIOReturnSuccess == IORegistryEntryCreateCFProperties(device, &deviceProperties, kCFAllocatorDefault, kNilOptions)) &&
|
||||
(NULL != deviceProperties) )
|
||||
{
|
||||
//dbg msg & log
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"usb device properties: %@", deviceProperties]);
|
||||
}
|
||||
|
||||
//release device props
|
||||
if(NULL != deviceProperties)
|
||||
{
|
||||
//release
|
||||
CFRelease(deviceProperties);
|
||||
|
||||
//unset
|
||||
deviceProperties = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// file: LidTrigger.h
|
||||
// project: DND (launch daemon)
|
||||
// description: monitor and alert logic for lid open events (header)
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Utilities.h"
|
||||
|
||||
@import Foundation;
|
||||
|
||||
#import <IOKit/IOKitLib.h>
|
||||
#import <IOKit/pwr_mgt/IOPM.h>
|
||||
|
||||
|
||||
/* CLASS INTERFACE */
|
||||
|
||||
@interface LidTrigger : NSObject
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* PROPERTIES */
|
||||
|
||||
//lid state
|
||||
@property LidState lidState;
|
||||
|
||||
//dispatch queue
|
||||
@property dispatch_queue_t dispatchQ;
|
||||
|
||||
//notification port
|
||||
@property IONotificationPortRef notificationPort;
|
||||
|
||||
//notification object
|
||||
@property io_object_t notification;
|
||||
|
||||
/* METHODS */
|
||||
|
||||
//register for notifications
|
||||
-(BOOL)toggle:(NSControlStateValue)state;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,325 @@
|
||||
// file: LidTrigger.m
|
||||
// project: DND (launch daemon)
|
||||
// description: monitor and alert logic for lid open events
|
||||
|
||||
// code inspired by:
|
||||
// https://github.com/zarigani/ClamshellWake/blob/master/ClamshellWake.cpp
|
||||
// https://github.com/dustinrue/ControlPlane/blob/master/Source/LaptopLidEvidenceSource.m
|
||||
|
||||
// note: manually get state from terminal via:
|
||||
// ioreg -r -k AppleClamshellState -d 4 | grep AppleClamshellState
|
||||
|
||||
#import "Consts.h"
|
||||
#import "Logging.h"
|
||||
#import "Triggers.h"
|
||||
#import "Utilities.h"
|
||||
#import "LidTrigger.h"
|
||||
#import "Preferences.h"
|
||||
|
||||
/* GLOBALS */
|
||||
|
||||
//last state
|
||||
// sometimes multiple notifications are delivered!?
|
||||
LidState lastLidState;
|
||||
|
||||
//triggers object
|
||||
extern Triggers* triggers;
|
||||
|
||||
//preferences obj
|
||||
extern Preferences* preferences;
|
||||
|
||||
//callback for power/lid events
|
||||
static void pmDomainChange(void *refcon, io_service_t service, uint32_t messageType, void *messageArgument)
|
||||
{
|
||||
//lid state
|
||||
int lidState = stateUnavailable;
|
||||
|
||||
//sleep bit
|
||||
int sleepState = -1;
|
||||
|
||||
//preferences
|
||||
NSDictionary* currentPrefs = nil;
|
||||
|
||||
//timestamp
|
||||
NSDate* timestamp = nil;
|
||||
|
||||
//init timestamp
|
||||
timestamp = [NSDate date];
|
||||
|
||||
//ignore any messages that are related to lid state
|
||||
if(kIOPMMessageClamshellStateChange != messageType)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"got 'kIOPMMessageClamshellStateChange' message");
|
||||
|
||||
//get prefs
|
||||
currentPrefs = [preferences get:nil];
|
||||
|
||||
//if user explicity set disabled
|
||||
// bail here, to ignore everything
|
||||
if(YES == [currentPrefs[PREF_IS_DISABLED] boolValue])
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"client disabled DND, so ignoring lid event");
|
||||
|
||||
//update 'prev' state?
|
||||
lastLidState = stateOpen;
|
||||
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//get state
|
||||
lidState = ((int) messageArgument & kClamshellStateBit);
|
||||
|
||||
//get sleep state
|
||||
sleepState = !!(((int)messageArgument & kClamshellSleepBit));
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"lid state: %@ (sleep bit: %d)", (lidState) ? @"closed" : @"open", sleepState]);
|
||||
|
||||
//(new) open?
|
||||
// OS sometimes delivers 2x events, so ignore same same
|
||||
if( (stateOpen == lidState) &&
|
||||
(stateOpen != lastLidState) )
|
||||
{
|
||||
//ignore if lid isn't really open
|
||||
// on reboot, OS may deliver 'open' message if external monitors are connected
|
||||
if(stateOpen != getLidState())
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//update 'prev' state
|
||||
lastLidState = stateOpen;
|
||||
|
||||
//dbg msg
|
||||
// log to file
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"[NEW EVENT] lid state: open (sleep state: %d)", sleepState]);
|
||||
|
||||
//process event
|
||||
// report to user, server, execute actions, etc.
|
||||
[triggers processEvent:LID_TRIGGER info:nil];
|
||||
}
|
||||
|
||||
//(new) close?
|
||||
// OS sometimes delivers 2x events, so ignore same same
|
||||
else if( (stateClosed == lidState) &&
|
||||
(stateClosed != lastLidState) )
|
||||
{
|
||||
//update 'prev' state
|
||||
lastLidState = stateClosed;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG|LOG_TO_FILE, [NSString stringWithFormat:@"[NEW EVENT] lid state: closed (sleep state: %d)", sleepState]);
|
||||
}
|
||||
|
||||
bail:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@implementation LidTrigger
|
||||
|
||||
@synthesize lidState;
|
||||
@synthesize dispatchQ;
|
||||
@synthesize notification;
|
||||
@synthesize notificationPort;
|
||||
|
||||
//init
|
||||
-(id)init
|
||||
{
|
||||
//super
|
||||
self = [super init];
|
||||
if(nil != self)
|
||||
{
|
||||
//init
|
||||
notificationPort = NULL;
|
||||
|
||||
//init
|
||||
notification = 0;
|
||||
|
||||
//init to current state
|
||||
lastLidState = getLidState();
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"initial lid state: %d", lastLidState]);
|
||||
|
||||
//init
|
||||
dispatchQ = NULL;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
//toggle lid notifications
|
||||
-(BOOL)toggle:(NSControlStateValue)state
|
||||
{
|
||||
//flag
|
||||
BOOL wasToggled = NO;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"toggling lid notifications: %lu", state]);
|
||||
|
||||
//on?
|
||||
// enable
|
||||
if(NSOnState == state)
|
||||
{
|
||||
//enable
|
||||
wasToggled = [self enable];
|
||||
}
|
||||
//off
|
||||
// disable
|
||||
else
|
||||
{
|
||||
//disable
|
||||
[self disable];
|
||||
|
||||
//manually set flag
|
||||
wasToggled = YES;
|
||||
}
|
||||
|
||||
return wasToggled;
|
||||
}
|
||||
|
||||
//register for notifications
|
||||
-(BOOL)enable
|
||||
{
|
||||
//return var
|
||||
BOOL registered = NO;
|
||||
|
||||
//status var
|
||||
kern_return_t status = kIOReturnError;
|
||||
|
||||
//root domain for power management
|
||||
io_service_t powerManagementRD = MACH_PORT_NULL;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"registering for lid notifications");
|
||||
|
||||
//make sure state is ok
|
||||
if(stateUnavailable == getLidState())
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to get lid state, so aborting lid notifications registration");
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//create queue
|
||||
dispatchQ = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
|
||||
if(NULL == dispatchQ)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to create dispatch queue for lid notifications");
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set target
|
||||
dispatch_set_target_queue(dispatchQ, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
|
||||
|
||||
//create notification port
|
||||
notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
|
||||
if(NULL == notificationPort)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to create notification port for lid notifications");
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set dispatch queue
|
||||
IONotificationPortSetDispatchQueue(notificationPort, dispatchQ);
|
||||
|
||||
//get matching service for power management root domain
|
||||
powerManagementRD = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPMrootDomain"));
|
||||
if(0 == powerManagementRD)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to get power management root domain for lid notifications");
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//add interest notification
|
||||
status = IOServiceAddInterestNotification(notificationPort, powerManagementRD, kIOGeneralInterest,
|
||||
pmDomainChange, &lidState, ¬ification);
|
||||
if(KERN_SUCCESS != status)
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, [NSString stringWithFormat:@"failed to get add interest notifcation for lid notifications (error: 0x:%x)", status]);
|
||||
|
||||
//error
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//happy
|
||||
registered = YES;
|
||||
|
||||
bail:
|
||||
|
||||
//release
|
||||
if(MACH_PORT_NULL != powerManagementRD)
|
||||
{
|
||||
//release
|
||||
IOObjectRelease(powerManagementRD);
|
||||
|
||||
//unset
|
||||
powerManagementRD = MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
return registered;
|
||||
}
|
||||
|
||||
//unregister for notifications
|
||||
-(void)disable
|
||||
{
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"unregistering lid notifications");
|
||||
|
||||
//release notification
|
||||
if(0 != notification)
|
||||
{
|
||||
//release
|
||||
IOObjectRelease(notification);
|
||||
|
||||
//unset
|
||||
notification = 0;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"released service interest notification");
|
||||
}
|
||||
|
||||
//destroy notification port
|
||||
if(NULL != notificationPort)
|
||||
{
|
||||
//set queue to NULL
|
||||
IONotificationPortSetDispatchQueue(notificationPort, NULL);
|
||||
|
||||
//unset dispatch queue
|
||||
dispatchQ = NULL;
|
||||
|
||||
//destroy port
|
||||
IONotificationPortDestroy(notificationPort);
|
||||
|
||||
//unset
|
||||
notificationPort = NULL;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"destroyed notification port");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// file: Power.m
|
||||
// project: DND (launch daemon)
|
||||
// description: monitor and alert logic for power events (header)
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
@import Cocoa;
|
||||
@import Foundation;
|
||||
|
||||
#import <IOKit/usb/IOUSBLib.h>
|
||||
|
||||
/* CLASS INTERFACE */
|
||||
|
||||
@interface PowerTrigger : NSObject
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* PROPERTIES */
|
||||
|
||||
//observer for screensaver off events
|
||||
@property(nonatomic, retain)id screenSaverNotification;
|
||||
|
||||
|
||||
|
||||
/* METHODS */
|
||||
|
||||
//register for notifications
|
||||
-(BOOL)toggle:(NSControlStateValue)state;
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,118 @@
|
||||
// file: Power.m
|
||||
// project: DND (launch daemon)
|
||||
// description: monitor and alert logic for power events (header)
|
||||
//
|
||||
// created by Patrick Wardle
|
||||
// copyright (c) 2018 Objective-See. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Consts.h"
|
||||
#import "Logging.h"
|
||||
#import "Triggers.h"
|
||||
#import "Utilities.h"
|
||||
#import "Preferences.h"
|
||||
#import "PowerTrigger.h"
|
||||
|
||||
/* GLOBALS */
|
||||
|
||||
//triggers object
|
||||
extern Triggers* triggers;
|
||||
|
||||
//preferences obj
|
||||
extern Preferences* preferences;
|
||||
|
||||
@implementation PowerTrigger
|
||||
|
||||
@synthesize screenSaverNotification;
|
||||
|
||||
|
||||
//toggle lid notifications
|
||||
-(BOOL)toggle:(NSControlStateValue)state
|
||||
{
|
||||
//flag
|
||||
BOOL wasToggled = NO;
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, [NSString stringWithFormat:@"toggling power notifications: %lu", state]);
|
||||
|
||||
//on?
|
||||
// enable
|
||||
if(NSOnState == state)
|
||||
{
|
||||
//enable
|
||||
wasToggled = [self enable];
|
||||
}
|
||||
//off
|
||||
// disable
|
||||
else
|
||||
{
|
||||
//disable
|
||||
[self disable];
|
||||
|
||||
//manually set flag
|
||||
wasToggled = YES;
|
||||
}
|
||||
|
||||
return wasToggled;
|
||||
}
|
||||
|
||||
//start power event monitoring
|
||||
-(BOOL)enable
|
||||
{
|
||||
//status
|
||||
BOOL initialized = NO;
|
||||
|
||||
/*
|
||||
com.apple.screensaver.didstart
|
||||
com.apple.screensaver.willstop
|
||||
com.apple.screensaver.didstop
|
||||
|
||||
*/
|
||||
|
||||
//add observer for screen save on
|
||||
// we don't get a screen save stop, so this will trigger process monitoring for exit of ScreenSaverEngine
|
||||
self.screenSaverNotification = [[NSDistributedNotificationCenter defaultCenter] addObserverForName:@"com.apple.screensaver.didlaunch" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification)
|
||||
{
|
||||
//TODO: trigger process monitoring
|
||||
|
||||
//dbg msg
|
||||
// log to file
|
||||
//logMsg(LOG_DEBUG|LOG_TO_FILE, @"[NEW EVENT] screen saver did stop");
|
||||
|
||||
//process event
|
||||
// report to user, server, execute actions, etc.
|
||||
//[triggers processEvent:POWER_TRIGGER info:@{KEY_POWER_TYPE:@"screen saver did stop"}];
|
||||
|
||||
}];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"enabled screen saver 'did launch'");
|
||||
|
||||
|
||||
bail:
|
||||
|
||||
return initialized;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//disable
|
||||
-(void)disable
|
||||
{
|
||||
//disable
|
||||
// screen saver start notification
|
||||
if(nil != self.screenSaverNotification)
|
||||
{
|
||||
//remove
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self.screenSaverNotification];
|
||||
|
||||
//unset
|
||||
self.screenSaverNotification = nil;
|
||||
}
|
||||
|
||||
//TODO: make sure to stop process monitoring, if it's still going
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -38,10 +38,6 @@
|
||||
// call daemon and block, then display, and repeat!
|
||||
while(YES)
|
||||
{
|
||||
//pool
|
||||
@autoreleasepool
|
||||
{
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"requesting alert(s) from daemon, will block");
|
||||
|
||||
@@ -84,8 +80,6 @@
|
||||
//wait for alert to be received
|
||||
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
|
||||
|
||||
}//pool
|
||||
|
||||
}//forevers
|
||||
|
||||
return;
|
||||
@@ -186,7 +180,29 @@
|
||||
notification.title = @"⚠️ Do Not Disturb Alert";
|
||||
|
||||
//set subtitle
|
||||
notification.subtitle = [NSString stringWithFormat:@"Lid Opened: %@", [dateFormat stringFromDate:alert[ALERT_TIMESTAMP]]];
|
||||
// based on trigger type (lid, usb, etc.)
|
||||
switch([alert[ALERT_TYPE] integerValue])
|
||||
{
|
||||
//lid
|
||||
case LID_TRIGGER:
|
||||
notification.subtitle = [NSString stringWithFormat:@"Lid Opened: %@", [dateFormat stringFromDate:alert[ALERT_TIMESTAMP]]];
|
||||
break;
|
||||
|
||||
//device
|
||||
case DEVICE_TRIGGER:
|
||||
notification.subtitle = [NSString stringWithFormat:@"Device Inserted: %@", alert[ALERT_INFO][KEY_DEVICE_NAME]];
|
||||
break;
|
||||
|
||||
//power
|
||||
case POWER_TRIGGER:
|
||||
notification.subtitle = [NSString stringWithFormat:@"Power Event: %@", alert[ALERT_INFO][KEY_POWER_TYPE]];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//set delegate to self
|
||||
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
7D564DEB1F1855E900B8AAD6 /* UpdateWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D564DE81F1855E900B8AAD6 /* UpdateWindow.xib */; };
|
||||
7D75537F1F22E40E0010FE88 /* PrefsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D75537D1F22E40E0010FE88 /* PrefsWindowController.m */; };
|
||||
7D7553801F22E40E0010FE88 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D75537E1F22E40E0010FE88 /* Preferences.xib */; };
|
||||
7D7553831F23199A0010FE88 /* prefsGeneral.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D7553811F23199A0010FE88 /* prefsGeneral.png */; };
|
||||
7D7553841F23199A0010FE88 /* prefsUpdate.png in Resources */ = {isa = PBXBuildFile; fileRef = 7D7553821F23199A0010FE88 /* prefsUpdate.png */; };
|
||||
7DD2BF461F1C2B4200B33214 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 7DD2BF431F1C2B4200B33214 /* logo.png */; };
|
||||
7DD2BF471F1C2B4200B33214 /* logoBG.png in Resources */ = {isa = PBXBuildFile; fileRef = 7DD2BF441F1C2B4200B33214 /* logoBG.png */; };
|
||||
@@ -45,6 +44,7 @@
|
||||
CD325425204DEAEA0059951B /* dndText@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = CD325424204DEAEA0059951B /* dndText@2x.png */; };
|
||||
CD325427204E0C500059951B /* close.png in Resources */ = {isa = PBXBuildFile; fileRef = CD325426204E0C500059951B /* close.png */; };
|
||||
CD32542B204E0E420059951B /* closeAlt.png in Resources */ = {isa = PBXBuildFile; fileRef = CD32542A204E0E420059951B /* closeAlt.png */; };
|
||||
CD68AEE02110CD9E0019E431 /* prefsTriggers.png in Resources */ = {isa = PBXBuildFile; fileRef = CD68AEDF2110CD9D0019E431 /* prefsTriggers.png */; };
|
||||
CDAAC213201D0CD90032F2E6 /* three.png in Resources */ = {isa = PBXBuildFile; fileRef = CDAAC212201D0CD80032F2E6 /* three.png */; };
|
||||
CDAAC215201D2DD30032F2E6 /* checkbox.png in Resources */ = {isa = PBXBuildFile; fileRef = CDAAC214201D2DD30032F2E6 /* checkbox.png */; };
|
||||
CDAAC217201D54C30032F2E6 /* prefsLink.png in Resources */ = {isa = PBXBuildFile; fileRef = CDAAC216201D54C20032F2E6 /* prefsLink.png */; };
|
||||
@@ -52,6 +52,8 @@
|
||||
CDAAC21C201D77390032F2E6 /* connected.png in Resources */ = {isa = PBXBuildFile; fileRef = CDAAC21A201D77390032F2E6 /* connected.png */; };
|
||||
CDAAC21D201D77390032F2E6 /* unconnected.png in Resources */ = {isa = PBXBuildFile; fileRef = CDAAC21B201D77390032F2E6 /* unconnected.png */; };
|
||||
CDAAC238201FD4660032F2E6 /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDAAC237201FD4660032F2E6 /* LocalAuthentication.framework */; };
|
||||
CDEADE52210214A0005054B0 /* usb.png in Resources */ = {isa = PBXBuildFile; fileRef = CDEADE502102149F005054B0 /* usb.png */; };
|
||||
CDEADE53210214A0005054B0 /* sleep.png in Resources */ = {isa = PBXBuildFile; fileRef = CDEADE51210214A0005054B0 /* sleep.png */; };
|
||||
CE0F559C1FD408BB00529259 /* dndText.png in Resources */ = {isa = PBXBuildFile; fileRef = CE0F559B1FD408BB00529259 /* dndText.png */; };
|
||||
CE133C5F1FD756CC00A29D67 /* dndIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = CE133C5E1FD756CC00A29D67 /* dndIcon.png */; };
|
||||
CE85D3FE1FDB47B200E116A5 /* settings.png in Resources */ = {isa = PBXBuildFile; fileRef = CE85D3FD1FDB47B200E116A5 /* settings.png */; };
|
||||
@@ -109,7 +111,6 @@
|
||||
7D75537C1F22E40E0010FE88 /* PrefsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrefsWindowController.h; sourceTree = "<group>"; };
|
||||
7D75537D1F22E40E0010FE88 /* PrefsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrefsWindowController.m; sourceTree = "<group>"; };
|
||||
7D75537E1F22E40E0010FE88 /* Preferences.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Preferences.xib; sourceTree = "<group>"; };
|
||||
7D7553811F23199A0010FE88 /* prefsGeneral.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = prefsGeneral.png; sourceTree = "<group>"; };
|
||||
7D7553821F23199A0010FE88 /* prefsUpdate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = prefsUpdate.png; sourceTree = "<group>"; };
|
||||
7DD2BF431F1C2B4200B33214 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo.png; sourceTree = "<group>"; };
|
||||
7DD2BF441F1C2B4200B33214 /* logoBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logoBG.png; sourceTree = "<group>"; };
|
||||
@@ -133,6 +134,7 @@
|
||||
CD325424204DEAEA0059951B /* dndText@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "dndText@2x.png"; path = "../../../shared/images/dndText@2x.png"; sourceTree = "<group>"; };
|
||||
CD325426204E0C500059951B /* close.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = close.png; sourceTree = "<group>"; };
|
||||
CD32542A204E0E420059951B /* closeAlt.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = closeAlt.png; sourceTree = "<group>"; };
|
||||
CD68AEDF2110CD9D0019E431 /* prefsTriggers.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = prefsTriggers.png; sourceTree = "<group>"; };
|
||||
CDAAC212201D0CD80032F2E6 /* three.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = three.png; sourceTree = "<group>"; };
|
||||
CDAAC214201D2DD30032F2E6 /* checkbox.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = checkbox.png; sourceTree = "<group>"; };
|
||||
CDAAC216201D54C20032F2E6 /* prefsLink.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = prefsLink.png; sourceTree = "<group>"; };
|
||||
@@ -140,6 +142,8 @@
|
||||
CDAAC21A201D77390032F2E6 /* connected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = connected.png; sourceTree = "<group>"; };
|
||||
CDAAC21B201D77390032F2E6 /* unconnected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unconnected.png; sourceTree = "<group>"; };
|
||||
CDAAC237201FD4660032F2E6 /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = System/Library/Frameworks/LocalAuthentication.framework; sourceTree = SDKROOT; };
|
||||
CDEADE502102149F005054B0 /* usb.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = usb.png; sourceTree = "<group>"; };
|
||||
CDEADE51210214A0005054B0 /* sleep.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = sleep.png; sourceTree = "<group>"; };
|
||||
CE0F559B1FD408BB00529259 /* dndText.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dndText.png; path = ../../../shared/images/dndText.png; sourceTree = "<group>"; };
|
||||
CE133C5E1FD756CC00A29D67 /* dndIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dndIcon.png; path = ../../../shared/images/dndIcon.png; sourceTree = "<group>"; };
|
||||
CE85D3FD1FDB47B200E116A5 /* settings.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = settings.png; sourceTree = "<group>"; };
|
||||
@@ -242,6 +246,9 @@
|
||||
7D564DD31F18441500B8AAD6 /* Images */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CD68AEDF2110CD9D0019E431 /* prefsTriggers.png */,
|
||||
CDEADE51210214A0005054B0 /* sleep.png */,
|
||||
CDEADE502102149F005054B0 /* usb.png */,
|
||||
CD32542A204E0E420059951B /* closeAlt.png */,
|
||||
CD325426204E0C500059951B /* close.png */,
|
||||
CD325424204DEAEA0059951B /* dndText@2x.png */,
|
||||
@@ -262,7 +269,6 @@
|
||||
CE133C5E1FD756CC00A29D67 /* dndIcon.png */,
|
||||
CE0F559B1FD408BB00529259 /* dndText.png */,
|
||||
CE968A9E1FCC66A300AD6B78 /* prefsAction.png */,
|
||||
7D7553811F23199A0010FE88 /* prefsGeneral.png */,
|
||||
7D7553821F23199A0010FE88 /* prefsUpdate.png */,
|
||||
7DD2BF431F1C2B4200B33214 /* logo.png */,
|
||||
7DD2BF441F1C2B4200B33214 /* logoBG.png */,
|
||||
@@ -368,6 +374,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CD32542B204E0E420059951B /* closeAlt.png in Resources */,
|
||||
CDEADE53210214A0005054B0 /* sleep.png in Resources */,
|
||||
CD17D56E20178DFC00F798D7 /* mobilePhone.png in Resources */,
|
||||
CD1FD56B2089224F00151D1C /* appStore.pdf in Resources */,
|
||||
CD2F407F204B417E0066673E /* alert.png in Resources */,
|
||||
@@ -382,13 +389,14 @@
|
||||
CDAAC213201D0CD90032F2E6 /* three.png in Resources */,
|
||||
CDAAC219201D72780032F2E6 /* linked.png in Resources */,
|
||||
CD325425204DEAEA0059951B /* dndText@2x.png in Resources */,
|
||||
CDEADE52210214A0005054B0 /* usb.png in Resources */,
|
||||
7DD2BF481F1C2B4200B33214 /* logoOver.png in Resources */,
|
||||
7D7553801F22E40E0010FE88 /* Preferences.xib in Resources */,
|
||||
7D7553831F23199A0010FE88 /* prefsGeneral.png in Resources */,
|
||||
CD17D5772017941C00F798D7 /* laptop.png in Resources */,
|
||||
CD17D58520179BC700F798D7 /* two.png in Resources */,
|
||||
CD325427204E0C500059951B /* close.png in Resources */,
|
||||
7D564DD61F18441500B8AAD6 /* Assets.xcassets in Resources */,
|
||||
CD68AEE02110CD9E0019E431 /* prefsTriggers.png in Resources */,
|
||||
CD17D57020178EB500F798D7 /* one.png in Resources */,
|
||||
7D7553841F23199A0010FE88 /* prefsUpdate.png in Resources */,
|
||||
7D564DDC1F18441500B8AAD6 /* AboutWindow.xib in Resources */,
|
||||
|
||||
@@ -56,9 +56,9 @@
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
@@ -75,6 +75,12 @@
|
||||
ReferencedContainer = "container:mainApp.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "-prefs"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 475 B After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14109" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14109"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
|
||||
<capability name="box content view" minToolsVersion="7.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@@ -24,6 +24,7 @@
|
||||
<outlet property="qrcPanel" destination="vdL-RT-p6a" id="KrV-Fe-sK0"/>
|
||||
<outlet property="qrcProgressIndicator" destination="pUS-KZ-De6" id="EYG-28-zkH"/>
|
||||
<outlet property="toolbar" destination="V8g-Ya-LK4" id="SH2-6E-QST"/>
|
||||
<outlet property="triggersView" destination="BuY-2M-Ecx" id="hrr-N9-ajg"/>
|
||||
<outlet property="updateButton" destination="Mtn-pi-zIl" id="Oe1-Jy-nMH"/>
|
||||
<outlet property="updateIndicator" destination="o0T-ra-4H0" id="DwL-OB-WQR"/>
|
||||
<outlet property="updateLabel" destination="Oe2-Ye-1s6" id="1gP-K0-cpP"/>
|
||||
@@ -52,22 +53,27 @@
|
||||
<allowedToolbarItems>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="J66-tT-qAf"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="6nW-4K-zf4"/>
|
||||
<toolbarItem implicitItemIdentifier="99F00439-5E3B-4FBB-BC65-3E1F7EBDDBC6" explicitItemIdentifier="general" label="general" paletteLabel="general" image="prefsGeneral" selectable="YES" id="Twx-TJ-y2Q">
|
||||
<toolbarItem implicitItemIdentifier="99F00439-5E3B-4FBB-BC65-3E1F7EBDDBC6" explicitItemIdentifier="general" label="general" paletteLabel="general" image="dndIcon" selectable="YES" id="Twx-TJ-y2Q">
|
||||
<connections>
|
||||
<action selector="toolbarButtonHandler:" target="-2" id="9JH-zR-BcH"/>
|
||||
</connections>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="48B3FCFA-8A19-4D19-A840-E21E6D564389" explicitItemIdentifier="action" label="action" paletteLabel="action" tag="1" image="prefsAction" selectable="YES" id="hqU-b9-59A">
|
||||
<toolbarItem implicitItemIdentifier="0204F7A2-F780-423C-89FB-28784C971A9A" explicitItemIdentifier="triggers" label="triggers" paletteLabel="triggers" tag="1" image="prefsTriggers" selectable="YES" id="pr7-Pz-jdz">
|
||||
<connections>
|
||||
<action selector="toolbarButtonHandler:" target="-2" id="jYk-kP-mSc"/>
|
||||
</connections>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="48B3FCFA-8A19-4D19-A840-E21E6D564389" explicitItemIdentifier="action" label="action" paletteLabel="action" tag="2" image="prefsAction" selectable="YES" id="hqU-b9-59A">
|
||||
<connections>
|
||||
<action selector="toolbarButtonHandler:" target="-2" id="dy9-vy-N89"/>
|
||||
</connections>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="B0FD7AF2-DAC5-45EF-A31B-2E2C7CB85294" explicitItemIdentifier="update" label="update" paletteLabel="update" tag="3" image="prefsUpdate" selectable="YES" id="2Fi-c8-fnE">
|
||||
<toolbarItem implicitItemIdentifier="B0FD7AF2-DAC5-45EF-A31B-2E2C7CB85294" explicitItemIdentifier="update" label="update" paletteLabel="update" tag="4" image="prefsUpdate" selectable="YES" id="2Fi-c8-fnE">
|
||||
<connections>
|
||||
<action selector="toolbarButtonHandler:" target="-2" id="jeu-wN-mgR"/>
|
||||
</connections>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="5DB39F09-CC43-4EC3-BF61-362FDA2DF782" explicitItemIdentifier="link" label="link" paletteLabel="link" tag="2" image="prefsLink" selectable="YES" id="43J-tU-rUa">
|
||||
<toolbarItem implicitItemIdentifier="5DB39F09-CC43-4EC3-BF61-362FDA2DF782" explicitItemIdentifier="link" label="link" paletteLabel="link" tag="3" image="prefsLink" selectable="YES" id="43J-tU-rUa">
|
||||
<connections>
|
||||
<action selector="toolbarButtonHandler:" target="-2" id="tSK-K0-f7H"/>
|
||||
</connections>
|
||||
@@ -76,6 +82,8 @@
|
||||
<defaultToolbarItems>
|
||||
<toolbarItem reference="Twx-TJ-y2Q"/>
|
||||
<toolbarItem reference="J66-tT-qAf"/>
|
||||
<toolbarItem reference="pr7-Pz-jdz"/>
|
||||
<toolbarItem reference="J66-tT-qAf"/>
|
||||
<toolbarItem reference="hqU-b9-59A"/>
|
||||
<toolbarItem reference="J66-tT-qAf"/>
|
||||
<toolbarItem reference="43J-tU-rUa"/>
|
||||
@@ -153,7 +161,7 @@
|
||||
<button fixedFrame="YES" tag="3" translatesAutoresizingMaskIntoConstraints="NO" id="ANF-lj-j0H">
|
||||
<rect key="frame" x="37" y="156" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" enabled="NO" inset="2" id="Fpb-6d-DfT">
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="Fpb-6d-DfT">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" size="14" name="Consolas-Bold"/>
|
||||
</buttonCell>
|
||||
@@ -164,7 +172,7 @@
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="F9r-H0-4xe">
|
||||
<rect key="frame" x="72" y="157" width="471" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="'Touch ID' Mode" id="l1H-sS-Md8">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Authentication Mode" id="l1H-sS-Md8">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -173,13 +181,13 @@
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="BhQ-tq-9gJ">
|
||||
<rect key="frame" x="72" y="138" width="508" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Suppress alerts if proceeded by a Touch ID login (10.13.4+)." id="yKN-Kc-8Q2">
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Ignore events if computer unlocked via Touch ID or Apple Watch." id="yKN-Kc-8Q2">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button fixedFrame="YES" tag="7" translatesAutoresizingMaskIntoConstraints="NO" id="OkJ-ds-qSY">
|
||||
<button fixedFrame="YES" tag="4" translatesAutoresizingMaskIntoConstraints="NO" id="OkJ-ds-qSY">
|
||||
<rect key="frame" x="37" y="99" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="HEY-GS-vSr">
|
||||
@@ -208,30 +216,95 @@
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button fixedFrame="YES" tag="4" translatesAutoresizingMaskIntoConstraints="NO" id="5ep-7h-VpU">
|
||||
<rect key="frame" x="37" y="42" width="29" height="18"/>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="852" y="437"/>
|
||||
</customView>
|
||||
<customView id="BuY-2M-Ecx" userLabel="Triggers">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="322"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<button fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="QSk-EX-Gs3">
|
||||
<rect key="frame" x="37" y="270" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="J3b-LL-38M">
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" enabled="NO" inset="2" id="4Ia-YW-I03">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" size="14" name="Consolas-Bold"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="togglePreference:" target="-2" id="5gO-Zo-43d"/>
|
||||
<action selector="togglePreference:" target="-2" id="ko3-U3-K1d"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Yza-iC-hAP">
|
||||
<rect key="frame" x="72" y="42" width="160" height="19"/>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="c2q-TO-7Hx">
|
||||
<rect key="frame" x="72" y="271" width="160" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Start at Login" id="ksD-bk-5jE">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Laptop Lid Open" id="svL-i1-bx7">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="LOC-tP-KQd">
|
||||
<rect key="frame" x="72" y="22" width="475" height="19"/>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="9cA-xI-Rkq">
|
||||
<rect key="frame" x="72" y="253" width="475" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Automatically start login item." id="k4V-lS-86b">
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Alert when your laptop lid is opened." id="eYK-5x-T41">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button fixedFrame="YES" tag="6" translatesAutoresizingMaskIntoConstraints="NO" id="Tdc-FL-Prs">
|
||||
<rect key="frame" x="37" y="213" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="Lxz-uf-N9R">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" size="14" name="Consolas-Bold"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="togglePreference:" target="-2" id="C4T-Ye-XAC"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wzx-aD-Ob5">
|
||||
<rect key="frame" x="72" y="214" width="161" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="USB Device Insertion" id="a2r-f0-Qw2">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="xBV-DA-rOc">
|
||||
<rect key="frame" x="72" y="195" width="475" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Alert when a USB device is plugged in." id="yaL-Sz-w38">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button fixedFrame="YES" tag="7" translatesAutoresizingMaskIntoConstraints="NO" id="G6G-cU-bdG">
|
||||
<rect key="frame" x="37" y="156" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="oKm-iS-CO8">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" size="14" name="Consolas-Bold"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="togglePreference:" target="-2" id="whf-Fn-MSZ"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="CjK-AK-Uzg">
|
||||
<rect key="frame" x="72" y="157" width="471" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Power Events" id="YR8-oc-TgU">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="7Cw-J0-A9x">
|
||||
<rect key="frame" x="72" y="118" width="490" height="38"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Alert when the your computer is powered on, awakened, or when the screen saver is stopped. " id="yW3-Uo-Ir7">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -244,7 +317,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="311"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<button fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="1z0-vD-5Vz">
|
||||
<button fixedFrame="YES" tag="8" translatesAutoresizingMaskIntoConstraints="NO" id="1z0-vD-5Vz">
|
||||
<rect key="frame" x="37" y="259" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="0eO-nb-SYy">
|
||||
@@ -273,8 +346,8 @@
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button fixedFrame="YES" tag="6" translatesAutoresizingMaskIntoConstraints="NO" id="Od2-P2-SXK">
|
||||
<rect key="frame" x="37" y="201" width="29" height="18"/>
|
||||
<button fixedFrame="YES" tag="9" translatesAutoresizingMaskIntoConstraints="NO" id="Od2-P2-SXK">
|
||||
<rect key="frame" x="37" y="202" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="qyn-YP-C2s">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
@@ -285,7 +358,7 @@
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BXf-fg-RpF">
|
||||
<rect key="frame" x="72" y="201" width="59" height="19"/>
|
||||
<rect key="frame" x="72" y="203" width="59" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Monitor" id="YH2-4b-Iv5">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
@@ -302,6 +375,26 @@
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button fixedFrame="YES" tag="10" translatesAutoresizingMaskIntoConstraints="NO" id="C6E-J8-lhh">
|
||||
<rect key="frame" x="37" y="132" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="ngn-La-kHu">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" size="14" name="Consolas-Bold"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="togglePreference:" target="-2" id="d0h-1p-AtX"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Np1-aP-w1p">
|
||||
<rect key="frame" x="72" y="133" width="98" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Snap Picture" id="BQ4-1f-ZXw">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eWd-63-7Gn">
|
||||
<rect key="frame" x="198" y="257" width="354" height="24"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
@@ -314,6 +407,15 @@
|
||||
<outlet property="delegate" destination="-2" id="DAs-b2-8Zb"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="cuP-oI-A6A">
|
||||
<rect key="frame" x="72" y="113" width="475" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Automatically take a picture via the webcam." id="7Xg-3U-FQp">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="911" y="901.5"/>
|
||||
</customView>
|
||||
@@ -366,7 +468,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="272"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<button fixedFrame="YES" tag="8" translatesAutoresizingMaskIntoConstraints="NO" id="dml-JS-liI">
|
||||
<button fixedFrame="YES" tag="11" translatesAutoresizingMaskIntoConstraints="NO" id="dml-JS-liI">
|
||||
<rect key="frame" x="37" y="220" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="ljs-bE-JTP">
|
||||
@@ -445,7 +547,7 @@
|
||||
<rect key="frame" x="322" y="115" width="258" height="153"/>
|
||||
<clipView key="contentView" id="FSf-NQ-BdZ">
|
||||
<rect key="frame" x="1" y="1" width="256" height="151"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView editable="NO" selectable="NO" importsGraphics="NO" verticallyResizable="YES" usesFontPanel="YES" findStyle="panel" continuousSpellChecking="YES" usesRuler="YES" allowsNonContiguousLayout="YES" quoteSubstitution="YES" dashSubstitution="YES" spellingCorrection="YES" smartInsertDelete="YES" id="9cB-rx-0JH">
|
||||
<rect key="frame" x="0.0" y="0.0" width="256" height="151"/>
|
||||
@@ -604,6 +706,7 @@
|
||||
<image name="close" width="24" height="24"/>
|
||||
<image name="closeAlt" width="24" height="24"/>
|
||||
<image name="connected" width="128" height="128"/>
|
||||
<image name="dndIcon" width="256" height="256"/>
|
||||
<image name="dndText" width="164.57142639160156" height="21.188571929931641"/>
|
||||
<image name="imageCell:eTI-5p-4rR:image" width="256" height="256">
|
||||
<mutableData key="keyedArchiveRepresentation">
|
||||
@@ -5125,9 +5228,9 @@ IGsABCB5AAQgfQAEIIQABCCJAAQglgAEIJkABCCmAAQgqwAEILMABCC2AAQguwAEIMMABCDGAAQg2AAE
|
||||
INsABCDgAAAAAAAABAEAAAAAAAAAVgAAAAAAAAAAAAAAAAAEIOI
|
||||
</mutableData>
|
||||
</image>
|
||||
<image name="prefsAction" width="32" height="32"/>
|
||||
<image name="prefsGeneral" width="32" height="32"/>
|
||||
<image name="prefsLink" width="32" height="32"/>
|
||||
<image name="prefsUpdate" width="32" height="32"/>
|
||||
<image name="prefsAction" width="256" height="256"/>
|
||||
<image name="prefsLink" width="256" height="256"/>
|
||||
<image name="prefsTriggers" width="224" height="205"/>
|
||||
<image name="prefsUpdate" width="256" height="256"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
#define TOOLBAR_GENERAL 0
|
||||
|
||||
//action view
|
||||
#define TOOLBAR_ACTION 1
|
||||
#define TOOLBAR_TRIGGERS 1
|
||||
|
||||
//action view
|
||||
#define TOOLBAR_ACTION 2
|
||||
|
||||
//link view
|
||||
#define TOOLBAR_LINK 2
|
||||
#define TOOLBAR_LINK 3
|
||||
|
||||
//update view
|
||||
#define TOOLBAR_UPDATE 3
|
||||
#define TOOLBAR_UPDATE 4
|
||||
|
||||
//tool bar id for 'general'
|
||||
#define TOOLBAR_GENERAL_ID @"general"
|
||||
@@ -34,23 +37,34 @@
|
||||
//no icon mode button
|
||||
#define BUTTON_NO_ICON_MODE 2
|
||||
|
||||
//touch id mode button
|
||||
#define BUTTON_TOUCHID_MODE 3
|
||||
//auth mode button
|
||||
#define BUTTON_AUTH_MODE 3
|
||||
|
||||
//remote tasking
|
||||
#define BUTTON_TASKING_MODE 4
|
||||
|
||||
|
||||
//lid open trigger
|
||||
#define BUTTON_LID_TRIGGER 5
|
||||
|
||||
//usb device trigger
|
||||
#define BUTTON_DEVICE_TRIGGER 6
|
||||
|
||||
//power events trigger
|
||||
#define BUTTON_POWER_TRIGGER 7
|
||||
|
||||
//start mode button
|
||||
#define BUTTON_START_MODE 4
|
||||
|
||||
//execute action button
|
||||
#define BUTTON_EXECUTE_ACTION 5
|
||||
#define BUTTON_EXECUTE_ACTION 8
|
||||
|
||||
//monitor button
|
||||
#define BUTTON_MONITOR_ACTION 6
|
||||
#define BUTTON_MONITOR_ACTION 9
|
||||
|
||||
//no remote tasking button
|
||||
#define BUTTON_NO_REMOTE_TASKING 7
|
||||
//snap picture button
|
||||
#define BUTTON_PHOTO_ACTION 10
|
||||
|
||||
//no updates button
|
||||
#define BUTTON_NO_UPDATES_MODE 8
|
||||
#define BUTTON_NO_UPDATES_MODE 11
|
||||
|
||||
@interface PrefsWindowController : NSWindowController <NSTextFieldDelegate, NSToolbarDelegate>
|
||||
|
||||
@@ -68,6 +82,9 @@
|
||||
//general prefs view
|
||||
@property (weak) IBOutlet NSView *generalView;
|
||||
|
||||
//triggers view
|
||||
@property (strong) IBOutlet NSView *triggersView;
|
||||
|
||||
//action view
|
||||
@property (weak) IBOutlet NSView *actionView;
|
||||
|
||||
|
||||
@@ -48,13 +48,12 @@
|
||||
//set general prefs as default
|
||||
[self toolbarButtonHandler:nil];
|
||||
|
||||
//enable touchID mode option
|
||||
// if: < 10.13.4 (check first!) && no touch bar
|
||||
if( (YES == [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 13, 4}]) &&
|
||||
(YES == hasTouchID()) )
|
||||
//clamshell?
|
||||
// enable laptop trigger option
|
||||
if(stateUnavailable != getLidState())
|
||||
{
|
||||
//enable button
|
||||
((NSButton*)[self.generalView viewWithTag:BUTTON_TOUCHID_MODE]).enabled = YES;
|
||||
((NSButton*)[self.triggersView viewWithTag:BUTTON_LID_TRIGGER]).enabled = YES;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -63,7 +62,7 @@
|
||||
//required for toolbar item enable/disable
|
||||
-(BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem
|
||||
{
|
||||
return [toolbarItem isEnabled] ;
|
||||
return [toolbarItem isEnabled];
|
||||
}
|
||||
|
||||
//toolbar view handler
|
||||
@@ -109,11 +108,29 @@
|
||||
((NSButton*)[view viewWithTag:BUTTON_NO_ICON_MODE]).state = [self.preferences[PREF_NO_ICON_MODE] boolValue];
|
||||
|
||||
//set 'touch id' button state
|
||||
((NSButton*)[view viewWithTag:BUTTON_TOUCHID_MODE]).state = [self.preferences[PREF_TOUCHID_MODE] boolValue];
|
||||
((NSButton*)[view viewWithTag:BUTTON_AUTH_MODE]).state = [self.preferences[PREF_AUTH_MODE] boolValue];
|
||||
|
||||
//set 'no remote tasking' button state
|
||||
((NSButton*)[view viewWithTag:BUTTON_TASKING_MODE]).state = [self.preferences[PREF_NO_REMOTE_TASKING] boolValue];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//triggers
|
||||
case TOOLBAR_TRIGGERS:
|
||||
{
|
||||
//set view
|
||||
view = self.triggersView;
|
||||
|
||||
//set 'lap lid' trigger button state
|
||||
((NSButton*)[view viewWithTag:BUTTON_LID_TRIGGER]).state = [self.preferences[PREF_LID_TRIGGER] boolValue];
|
||||
|
||||
//set 'usb device' trigger button state
|
||||
((NSButton*)[view viewWithTag:BUTTON_DEVICE_TRIGGER]).state = [self.preferences[PREF_DEVICE_TRIGGER] boolValue];
|
||||
|
||||
//set 'power events' trigger button state
|
||||
((NSButton*)[view viewWithTag:BUTTON_POWER_TRIGGER]).state = [self.preferences[PREF_POWER_TRIGGER] boolValue];
|
||||
|
||||
//set 'start mode' button state
|
||||
((NSButton*)[view viewWithTag:BUTTON_START_MODE]).state = [self.preferences[PREF_START_MODE] boolValue];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -139,8 +156,8 @@
|
||||
//set 'monitor' button state
|
||||
((NSButton*)[view viewWithTag:BUTTON_MONITOR_ACTION]).state = [self.preferences[PREF_MONITOR_ACTION] boolValue];
|
||||
|
||||
//set 'no remote tasking' button state
|
||||
((NSButton*)[view viewWithTag:BUTTON_NO_REMOTE_TASKING]).state = [self.preferences[PREF_NO_REMOTE_TASKING] boolValue];
|
||||
//set 'photo action' button state
|
||||
((NSButton*)[view viewWithTag:BUTTON_PHOTO_ACTION]).state = [self.preferences[PREF_PHOTO_ACTION] boolValue];
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -304,6 +321,8 @@
|
||||
//set appropriate preference
|
||||
switch(((NSButton*)sender).tag)
|
||||
{
|
||||
/* GENERAL PREFS */
|
||||
|
||||
//passive mode
|
||||
case BUTTON_PASSIVE_MODE:
|
||||
{
|
||||
@@ -323,35 +342,54 @@
|
||||
break;
|
||||
}
|
||||
|
||||
//touch id mode
|
||||
case BUTTON_TOUCHID_MODE:
|
||||
//auth mode
|
||||
case BUTTON_AUTH_MODE:
|
||||
{
|
||||
//set pref
|
||||
preferences[PREF_TOUCHID_MODE] = state;
|
||||
preferences[PREF_AUTH_MODE] = state;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//start mode
|
||||
// also toggle here...
|
||||
case BUTTON_START_MODE:
|
||||
//remote tasking
|
||||
case BUTTON_TASKING_MODE:
|
||||
{
|
||||
//set pref
|
||||
preferences[PREF_START_MODE] = state;
|
||||
|
||||
//toggle login item in background
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
|
||||
^{
|
||||
//toggle
|
||||
if(YES != toggleLoginItem([NSURL fileURLWithPath:[((AppDelegate*)[[NSApplication sharedApplication] delegate]) path2LoginItem]], [preferences[PREF_START_MODE] intValue]))
|
||||
{
|
||||
//err msg
|
||||
logMsg(LOG_ERR, @"failed to toggle login item");
|
||||
}
|
||||
});
|
||||
preferences[PREF_NO_REMOTE_TASKING] = state;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* TRIGGER PREFS */
|
||||
|
||||
//lid trigger
|
||||
case BUTTON_LID_TRIGGER:
|
||||
{
|
||||
//set pref
|
||||
preferences[PREF_LID_TRIGGER] = state;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//usb device trigger
|
||||
case BUTTON_DEVICE_TRIGGER:
|
||||
{
|
||||
//set pref
|
||||
preferences[PREF_DEVICE_TRIGGER] = state;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//power trigger
|
||||
case BUTTON_POWER_TRIGGER:
|
||||
{
|
||||
//set pref
|
||||
preferences[PREF_POWER_TRIGGER] = state;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* ACTION PREFS */
|
||||
|
||||
//execute action
|
||||
// also toggle state of path
|
||||
@@ -375,14 +413,16 @@
|
||||
break;
|
||||
}
|
||||
|
||||
//no camera
|
||||
case BUTTON_NO_REMOTE_TASKING:
|
||||
//monitor mode
|
||||
case BUTTON_PHOTO_ACTION:
|
||||
{
|
||||
//set pref
|
||||
preferences[PREF_NO_REMOTE_TASKING] = state;
|
||||
preferences[PREF_PHOTO_ACTION] = state;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* UPDATE PREFS */
|
||||
|
||||
//(no) update mode
|
||||
case BUTTON_NO_UPDATES_MODE:
|
||||
@@ -395,7 +435,7 @@
|
||||
}
|
||||
|
||||
//tell daemon to update preferences
|
||||
[daemonComms updatePreferences:preferences];
|
||||
[self.daemonComms updatePreferences:preferences];
|
||||
|
||||
//restart login item if user toggle'd icon state
|
||||
// note: this has to be done after the prefs are written out by the daemon
|
||||
|
||||
@@ -11,12 +11,16 @@
|
||||
<connections>
|
||||
<outlet property="activityIndicator" destination="12Q-wb-usj" id="OBk-O9-kxj"/>
|
||||
<outlet property="activityMessage" destination="fFv-Gr-YPE" id="ItR-ES-c5V"/>
|
||||
<outlet property="appInfo" destination="Saf-Qg-NBo" id="xs0-qj-7dm"/>
|
||||
<outlet property="appInfo" destination="uXX-Wf-ZLL" id="x8l-zh-2Ww"/>
|
||||
<outlet property="deviceName" destination="cwA-Cr-acf" id="2Iv-JH-zGS"/>
|
||||
<outlet property="deviceTrigger" destination="1yX-PX-O3F" id="0PZ-dS-dxu"/>
|
||||
<outlet property="hostName" destination="mFe-eu-nNm" id="oRs-cQ-NN6"/>
|
||||
<outlet property="lidTrigger" destination="HhM-Wb-jX6" id="mqX-9A-Tlu"/>
|
||||
<outlet property="linkedView" destination="Bbb-NZ-tuF" id="vGv-tV-8Mb"/>
|
||||
<outlet property="powerTrigger" destination="gTR-JD-PmX" id="lLC-rw-fi7"/>
|
||||
<outlet property="qrcImageView" destination="mos-zb-KRK" id="kKD-Ww-Bkx"/>
|
||||
<outlet property="qrcView" destination="klO-RE-i9P" id="30O-Tc-jSC"/>
|
||||
<outlet property="triggerView" destination="Saf-Qg-NBo" id="Aaf-2f-ehE"/>
|
||||
<outlet property="welcomeView" destination="vZ0-Uk-9P1" id="JgS-86-4S1"/>
|
||||
<outlet property="window" destination="F0z-JX-Cv5" id="gIp-Ho-8D9"/>
|
||||
</connections>
|
||||
@@ -27,7 +31,7 @@
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="800" height="500"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||
<value key="minSize" type="size" width="800" height="500"/>
|
||||
<value key="maxSize" type="size" width="800" height="500"/>
|
||||
<view key="contentView" wantsLayer="YES" id="se5-gp-TjO">
|
||||
@@ -97,7 +101,7 @@
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="cxG-zN-szL">
|
||||
<rect key="frame" x="31" y="180" width="738" height="117"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="'Do Not Disturb' attempts to detect 'evil maid' attacks,
alerting you if somebody tampers with your laptop!" id="tYf-YX-PsV">
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="'Do Not Disturb' attempts to detect 'evil maid' attacks,
alerting you if somebody tampers with your Mac!" id="tYf-YX-PsV">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -106,33 +110,14 @@
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="-156" y="647"/>
|
||||
</customView>
|
||||
<customView id="Saf-Qg-NBo" userLabel="App Info">
|
||||
<customView id="Saf-Qg-NBo" userLabel="Triggers">
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="qwA-lo-6xT">
|
||||
<rect key="frame" x="68" y="426" width="664" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="Let's link with your iPhone to enable mobile alerts" id="SFE-Jt-OYq">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hgC-yZ-fp2">
|
||||
<rect key="frame" x="342" y="292" width="116" height="73"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="unconnected" id="Mpj-kB-q4i"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tSA-l2-uw1">
|
||||
<rect key="frame" x="458" y="267" width="142" height="124"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="mobilePhone" id="ijd-WJ-9VT"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="388" translatesAutoresizingMaskIntoConstraints="NO" id="OFG-Gz-3rE">
|
||||
<rect key="frame" x="18" y="157" width="764" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Download 'Do Not Disturb' from the iOS App Store" id="MAH-fc-gnv">
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="What should trigger 'Do Not Disturb'?" id="SFE-Jt-OYq">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -145,18 +130,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" tag="2" translatesAutoresizingMaskIntoConstraints="NO" id="XhZ-7d-es8">
|
||||
<rect key="frame" x="14" y="6" width="81" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Skip" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="jHq-Ss-1eG">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="buttonHandler:" target="-2" id="skW-Zf-sd1"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" tag="3" translatesAutoresizingMaskIntoConstraints="NO" id="k0d-RO-RST">
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" tag="2" translatesAutoresizingMaskIntoConstraints="NO" id="k0d-RO-RST">
|
||||
<rect key="frame" x="715" y="6" width="81" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Next" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="7AI-8x-NIJ">
|
||||
@@ -172,19 +146,153 @@
|
||||
<color key="fillColor" red="0.57793885469999995" green="0.75859862570000003" blue="0.2368842065" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</box>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Stm-VG-w3v">
|
||||
<rect key="frame" x="206" y="267" width="138" height="124"/>
|
||||
<rect key="frame" x="76" y="150" width="180" height="200"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="laptop" id="tNr-00-iNk"/>
|
||||
</imageView>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9FN-FI-sj3">
|
||||
<button fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="HhM-Wb-jX6">
|
||||
<rect key="frame" x="86" y="143" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="6kw-r2-rmN">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" size="14" name="Consolas-Bold"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="e9r-Jq-TLi">
|
||||
<rect key="frame" x="111" y="143" width="140" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Laptop Lid Open" id="3rB-77-9nQ">
|
||||
<font key="font" size="15" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="gTR-JD-PmX">
|
||||
<rect key="frame" x="581" y="143" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="ok3-Cj-tDO">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" size="14" name="Consolas-Bold"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gYG-uo-2F5">
|
||||
<rect key="frame" x="315" y="165" width="170" height="170"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="usb" id="fcP-xx-A5f"/>
|
||||
</imageView>
|
||||
<button fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="1yX-PX-O3F">
|
||||
<rect key="frame" x="341" y="143" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="bJj-FO-Xp6">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" size="14" name="Consolas-Bold"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="93F-5x-Nuf">
|
||||
<rect key="frame" x="605" y="82" width="177" height="84"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Power On
Computer Wake
Screen Saver Off" id="uOY-7O-Nsb">
|
||||
<font key="font" size="15" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fTz-Wm-yY8">
|
||||
<rect key="frame" x="571" y="170" width="159" height="159"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="sleep" id="LyW-2I-nNG"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2Vd-M8-05L">
|
||||
<rect key="frame" x="365" y="143" width="122" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="USB Insertion" id="dHu-5b-Vk2">
|
||||
<font key="font" size="15" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="831" y="-530"/>
|
||||
</customView>
|
||||
<customView id="uXX-Wf-ZLL" userLabel="App Info">
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" preferredMaxLayoutWidth="660" translatesAutoresizingMaskIntoConstraints="NO" id="pzP-vr-mwp">
|
||||
<rect key="frame" x="68" y="426" width="664" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="Let's link with your iPhone to enable mobile alerts" id="b7f-6P-fss">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3Ko-5I-ZkQ">
|
||||
<rect key="frame" x="342" y="292" width="116" height="73"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="unconnected" id="biq-NY-wHH"/>
|
||||
</imageView>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Rla-hF-y7t">
|
||||
<rect key="frame" x="458" y="267" width="142" height="124"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="mobilePhone" id="ks4-qM-EJX"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="388" translatesAutoresizingMaskIntoConstraints="NO" id="1NC-nB-9TF">
|
||||
<rect key="frame" x="18" y="157" width="764" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Download 'Do Not Disturb' from the iOS App Store" id="xMO-kA-ubY">
|
||||
<font key="font" size="32" name="AvenirNextCondensed-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<box fixedFrame="YES" boxType="custom" borderType="none" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="2wk-PX-com">
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<view key="contentView" ambiguous="YES" id="Cvt-0u-Fn9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" tag="3" translatesAutoresizingMaskIntoConstraints="NO" id="SzW-hq-Cay">
|
||||
<rect key="frame" x="14" y="6" width="81" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Skip" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="F4D-7D-b7M">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="buttonHandler:" target="-2" id="Q9F-RZ-B16"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" tag="4" translatesAutoresizingMaskIntoConstraints="NO" id="IYF-UZ-e79">
|
||||
<rect key="frame" x="715" y="6" width="81" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Next" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="KzN-1a-Bgl">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="buttonHandler:" target="-2" id="4kt-qR-EdK"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</view>
|
||||
<color key="fillColor" red="0.57793885469999995" green="0.75859862570000003" blue="0.2368842065" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</box>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pne-xe-SXP">
|
||||
<rect key="frame" x="206" y="267" width="138" height="124"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="laptop" id="Yka-Wc-tqb"/>
|
||||
</imageView>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SIf-al-GRB">
|
||||
<rect key="frame" x="337" y="94" width="127" height="55"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="appStore" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" inset="2" id="cPG-lr-39E">
|
||||
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="appStore" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" inset="2" id="rpd-Oh-aLh">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="downloadApp:" target="-2" id="IrW-7u-1OG"/>
|
||||
<action selector="downloadApp:" target="-2" id="u1k-Ns-xde"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
@@ -295,7 +403,7 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" tag="4" translatesAutoresizingMaskIntoConstraints="NO" id="SCr-nL-4pA">
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="SCr-nL-4pA">
|
||||
<rect key="frame" x="705" y="6" width="81" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Done" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Jhe-Eu-d4x">
|
||||
@@ -4853,6 +4961,8 @@ INsABCDgAAAAAAAABAEAAAAAAAAAVgAAAAAAAAAAAAAAAAAEIOI
|
||||
<image name="laptop" width="256" height="256"/>
|
||||
<image name="linked" width="256" height="467"/>
|
||||
<image name="mobilePhone" width="512" height="512"/>
|
||||
<image name="sleep" width="256" height="256"/>
|
||||
<image name="unconnected" width="128" height="128"/>
|
||||
<image name="usb" width="256" height="256"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -17,12 +17,27 @@
|
||||
//welcome view
|
||||
@property (strong) IBOutlet NSView *welcomeView;
|
||||
|
||||
//app info view
|
||||
@property (strong) IBOutlet NSView *triggerView;
|
||||
|
||||
//app info view
|
||||
@property (strong) IBOutlet NSView *appInfo;
|
||||
|
||||
//config view
|
||||
@property (strong) IBOutlet NSView *qrcView;
|
||||
|
||||
//button
|
||||
// trigger for lid opens
|
||||
@property (weak) IBOutlet NSButton *lidTrigger;
|
||||
|
||||
//button
|
||||
// trigger for device insertions
|
||||
@property (weak) IBOutlet NSButton *deviceTrigger;
|
||||
|
||||
//button
|
||||
// trigger for power events
|
||||
@property (weak) IBOutlet NSButton *powerTrigger;
|
||||
|
||||
//activity indicator
|
||||
@property (weak) IBOutlet NSProgressIndicator *activityIndicator;
|
||||
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
#import "WelcomeWindowController.h"
|
||||
|
||||
#define VIEW_WELCOME 0
|
||||
#define VIEW_APP_INFO 1
|
||||
#define SKIP_LINKING 2
|
||||
#define VIEW_QRC 3
|
||||
#define VIEW_LINKED 4
|
||||
#define SELECT_TRIGGERS 1
|
||||
#define VIEW_APP_INFO 2
|
||||
#define SKIP_LINKING 3
|
||||
#define VIEW_QRC 4
|
||||
#define VIEW_LINKED 5
|
||||
|
||||
@implementation WelcomeWindowController
|
||||
|
||||
@@ -75,16 +76,48 @@
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
|
||||
|
||||
//set first responder
|
||||
[self.window makeFirstResponder:[self.welcomeView viewWithTag:VIEW_APP_INFO]];
|
||||
[self.window makeFirstResponder:[self.welcomeView viewWithTag:SELECT_TRIGGERS]];
|
||||
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//select triggers info
|
||||
case SELECT_TRIGGERS:
|
||||
{
|
||||
//remove prev. subview
|
||||
[[[self.window.contentView subviews] lastObject] removeFromSuperview];
|
||||
|
||||
//no a laptop?
|
||||
// uncheck and disable laptop lid trigger
|
||||
if(stateUnavailable == getLidState())
|
||||
{
|
||||
//uncheck
|
||||
self.lidTrigger.state = NSOffState;
|
||||
|
||||
//disable
|
||||
self.lidTrigger.enabled = NO;
|
||||
}
|
||||
|
||||
//set view
|
||||
[self.window.contentView addSubview:self.triggerView];
|
||||
|
||||
//make 'next' button first responder
|
||||
[self.window makeFirstResponder:[self.triggerView viewWithTag:VIEW_APP_INFO]];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//app info
|
||||
case VIEW_APP_INFO:
|
||||
{
|
||||
//save trigger prefs
|
||||
[self setTriggers];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"saved triggers");
|
||||
|
||||
//remove prev. subview
|
||||
[[[self.window.contentView subviews] lastObject] removeFromSuperview];
|
||||
|
||||
@@ -130,6 +163,29 @@
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//get user's prefs for triggers
|
||||
// then send them to daemon to save into prefs
|
||||
-(void)setTriggers
|
||||
{
|
||||
//daemon comms
|
||||
DaemonComms* daemonComms = nil;
|
||||
|
||||
//alloc/init
|
||||
daemonComms = [[DaemonComms alloc] init];
|
||||
|
||||
//dbg msg
|
||||
logMsg(LOG_DEBUG, @"setting trigger prefs");
|
||||
|
||||
//send to daemon
|
||||
// will update preferences
|
||||
[daemonComms updatePreferences:@{PREF_LID_TRIGGER:[NSNumber numberWithInteger:self.lidTrigger.state],
|
||||
PREF_DEVICE_TRIGGER:[NSNumber numberWithInteger:self.deviceTrigger.state],
|
||||
PREF_POWER_TRIGGER:[NSNumber numberWithInteger:self.powerTrigger.state]}];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#import "Logging.h"
|
||||
#import "Utilities.h"
|
||||
|
||||
#import <ServiceManagement/ServiceManagement.h>
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
|
||||
@@ -148,6 +148,18 @@
|
||||
// status
|
||||
#define PREF_IS_DISABLED @"disabled"
|
||||
|
||||
//prefs
|
||||
// lid trigger
|
||||
#define PREF_LID_TRIGGER @"lidTrigger"
|
||||
|
||||
//prefs
|
||||
// device trigger
|
||||
#define PREF_DEVICE_TRIGGER @"deviceTrigger"
|
||||
|
||||
//prefs
|
||||
// power trigger
|
||||
#define PREF_POWER_TRIGGER @"powerTrigger"
|
||||
|
||||
//prefs
|
||||
// passive mode
|
||||
#define PREF_PASSIVE_MODE @"passiveMode"
|
||||
@@ -157,8 +169,8 @@
|
||||
#define PREF_NO_ICON_MODE @"noIconMode"
|
||||
|
||||
//prefs
|
||||
// touchID mode
|
||||
#define PREF_TOUCHID_MODE @"touchIDMode"
|
||||
// auth mode
|
||||
#define PREF_AUTH_MODE @"touchIDMode"
|
||||
|
||||
//prefs
|
||||
// start mode
|
||||
@@ -180,6 +192,10 @@
|
||||
// monitor stuff
|
||||
#define PREF_MONITOR_ACTION @"monitorAction"
|
||||
|
||||
//pref
|
||||
// auto take photo
|
||||
#define PREF_PHOTO_ACTION @"photoAction"
|
||||
|
||||
//pref
|
||||
// no remote tasking
|
||||
#define PREF_NO_REMOTE_TASKING @"noRemoteTasking"
|
||||
@@ -188,6 +204,19 @@
|
||||
// update mode
|
||||
#define PREF_NO_UPDATES_MODE @"noUpdatesMode"
|
||||
|
||||
//trigger: all
|
||||
// based on prefs
|
||||
#define ALL_TRIGGERS 0x0
|
||||
|
||||
//trigger: lid
|
||||
#define LID_TRIGGER 0x1
|
||||
|
||||
//trigger: devices
|
||||
#define DEVICE_TRIGGER 0x2
|
||||
|
||||
//trigger: power
|
||||
#define POWER_TRIGGER 0x3
|
||||
|
||||
//log file
|
||||
#define LOG_FILE_NAME @"DND.log"
|
||||
|
||||
@@ -195,9 +224,20 @@
|
||||
// timestamp
|
||||
#define ALERT_TIMESTAMP @"timestamp"
|
||||
|
||||
//alert key
|
||||
// type (lid, usb, power)
|
||||
#define ALERT_TYPE @"eventType"
|
||||
|
||||
//alert key
|
||||
// info (specific to event type)
|
||||
#define ALERT_INFO @"info"
|
||||
|
||||
//key for device name
|
||||
#define KEY_DEVICE_NAME @"deviceName"
|
||||
|
||||
//key for power type
|
||||
#define KEY_POWER_TYPE @"powerType"
|
||||
|
||||
//key for host name
|
||||
#define KEY_HOST_NAME @"hostName"
|
||||
|
||||
|
||||