terminal-notifier 1.7.2 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.markdown +1 -1
- data/lib/terminal-notifier.rb +5 -4
- data/vendor/terminal-notifier +0 -0
- metadata +6 -44
- data/vendor/terminal-notifier/LICENSE.md +0 -9
- data/vendor/terminal-notifier/README.markdown +0 -301
- data/vendor/terminal-notifier/Ruby/Gemfile +0 -2
- data/vendor/terminal-notifier/Ruby/Gemfile.lock +0 -23
- data/vendor/terminal-notifier/Ruby/LICENSE +0 -24
- data/vendor/terminal-notifier/Ruby/README.markdown +0 -48
- data/vendor/terminal-notifier/Ruby/Rakefile +0 -48
- data/vendor/terminal-notifier/Ruby/bin/terminal-notifier +0 -13
- data/vendor/terminal-notifier/Ruby/lib/terminal-notifier.rb +0 -92
- data/vendor/terminal-notifier/Ruby/spec/terminal-notifier_spec.rb +0 -79
- data/vendor/terminal-notifier/Ruby/terminal-notifier.gemspec +0 -26
- data/vendor/terminal-notifier/Terminal Notifier.xcodeproj/project.pbxproj +0 -315
- data/vendor/terminal-notifier/Terminal Notifier.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- data/vendor/terminal-notifier/Terminal Notifier.xcodeproj/project.xcworkspace/xcshareddata/Terminal Notifier.xccheckout +0 -41
- data/vendor/terminal-notifier/Terminal Notifier.xcodeproj/xcshareddata/xcschemes/Terminal Notifier.xcscheme +0 -140
- data/vendor/terminal-notifier/Terminal Notifier/AppDelegate.h +0 -4
- data/vendor/terminal-notifier/Terminal Notifier/AppDelegate.m +0 -594
- data/vendor/terminal-notifier/Terminal Notifier/Terminal Notifier-Info.plist +0 -43
- data/vendor/terminal-notifier/Terminal Notifier/Terminal Notifier-Prefix.pch +0 -7
- data/vendor/terminal-notifier/Terminal Notifier/en.lproj/Credits.rtf +0 -29
- data/vendor/terminal-notifier/Terminal Notifier/en.lproj/InfoPlist.strings +0 -2
- data/vendor/terminal-notifier/Terminal Notifier/en.lproj/MainMenu.xib +0 -3387
- data/vendor/terminal-notifier/Terminal Notifier/main.m +0 -6
- data/vendor/terminal-notifier/Terminal.icns +0 -0
- data/vendor/terminal-notifier/assets/Example_1.png +0 -0
- data/vendor/terminal-notifier/assets/Example_2.png +0 -0
- data/vendor/terminal-notifier/assets/Example_3.png +0 -0
- data/vendor/terminal-notifier/assets/Example_4.png +0 -0
- data/vendor/terminal-notifier/assets/Example_5.png +0 -0
- data/vendor/terminal-notifier/assets/System_prefs.png +0 -0
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/Info.plist +0 -63
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/MacOS/terminal-notifier +0 -0
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/PkgInfo +0 -1
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/Terminal.icns +0 -0
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/en.lproj/Credits.rtf +0 -29
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/en.lproj/MainMenu.nib +0 -0
@@ -1,41 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
-
<plist version="1.0">
|
4
|
-
<dict>
|
5
|
-
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
|
6
|
-
<false/>
|
7
|
-
<key>IDESourceControlProjectIdentifier</key>
|
8
|
-
<string>A55309C1-2ABD-460A-B080-5A322DCAF4B5</string>
|
9
|
-
<key>IDESourceControlProjectName</key>
|
10
|
-
<string>Terminal Notifier</string>
|
11
|
-
<key>IDESourceControlProjectOriginsDictionary</key>
|
12
|
-
<dict>
|
13
|
-
<key>9F67DD19109869B0F5A85172DA9B0D3E8F7EF383</key>
|
14
|
-
<string>github.com:alloy/terminal-notifier.git</string>
|
15
|
-
</dict>
|
16
|
-
<key>IDESourceControlProjectPath</key>
|
17
|
-
<string>Terminal Notifier.xcodeproj</string>
|
18
|
-
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
|
19
|
-
<dict>
|
20
|
-
<key>9F67DD19109869B0F5A85172DA9B0D3E8F7EF383</key>
|
21
|
-
<string>../..</string>
|
22
|
-
</dict>
|
23
|
-
<key>IDESourceControlProjectURL</key>
|
24
|
-
<string>github.com:alloy/terminal-notifier.git</string>
|
25
|
-
<key>IDESourceControlProjectVersion</key>
|
26
|
-
<integer>111</integer>
|
27
|
-
<key>IDESourceControlProjectWCCIdentifier</key>
|
28
|
-
<string>9F67DD19109869B0F5A85172DA9B0D3E8F7EF383</string>
|
29
|
-
<key>IDESourceControlProjectWCConfigurations</key>
|
30
|
-
<array>
|
31
|
-
<dict>
|
32
|
-
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
|
33
|
-
<string>public.vcs.git</string>
|
34
|
-
<key>IDESourceControlWCCIdentifierKey</key>
|
35
|
-
<string>9F67DD19109869B0F5A85172DA9B0D3E8F7EF383</string>
|
36
|
-
<key>IDESourceControlWCCName</key>
|
37
|
-
<string>terminal-notifier</string>
|
38
|
-
</dict>
|
39
|
-
</array>
|
40
|
-
</dict>
|
41
|
-
</plist>
|
@@ -1,140 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<Scheme
|
3
|
-
LastUpgradeVersion = "0440"
|
4
|
-
version = "1.3">
|
5
|
-
<BuildAction
|
6
|
-
parallelizeBuildables = "YES"
|
7
|
-
buildImplicitDependencies = "YES">
|
8
|
-
<BuildActionEntries>
|
9
|
-
<BuildActionEntry
|
10
|
-
buildForTesting = "YES"
|
11
|
-
buildForRunning = "YES"
|
12
|
-
buildForProfiling = "YES"
|
13
|
-
buildForArchiving = "YES"
|
14
|
-
buildForAnalyzing = "YES">
|
15
|
-
<BuildableReference
|
16
|
-
BuildableIdentifier = "primary"
|
17
|
-
BlueprintIdentifier = "5199791315B1F92B003AFC57"
|
18
|
-
BuildableName = "terminal-notifier.app"
|
19
|
-
BlueprintName = "terminal-notifier"
|
20
|
-
ReferencedContainer = "container:Terminal Notifier.xcodeproj">
|
21
|
-
</BuildableReference>
|
22
|
-
</BuildActionEntry>
|
23
|
-
</BuildActionEntries>
|
24
|
-
</BuildAction>
|
25
|
-
<TestAction
|
26
|
-
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
27
|
-
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
28
|
-
shouldUseLaunchSchemeArgsEnv = "YES"
|
29
|
-
buildConfiguration = "Debug">
|
30
|
-
<Testables>
|
31
|
-
</Testables>
|
32
|
-
<MacroExpansion>
|
33
|
-
<BuildableReference
|
34
|
-
BuildableIdentifier = "primary"
|
35
|
-
BlueprintIdentifier = "5199791315B1F92B003AFC57"
|
36
|
-
BuildableName = "terminal-notifier.app"
|
37
|
-
BlueprintName = "terminal-notifier"
|
38
|
-
ReferencedContainer = "container:Terminal Notifier.xcodeproj">
|
39
|
-
</BuildableReference>
|
40
|
-
</MacroExpansion>
|
41
|
-
</TestAction>
|
42
|
-
<LaunchAction
|
43
|
-
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
44
|
-
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
45
|
-
launchStyle = "0"
|
46
|
-
useCustomWorkingDirectory = "NO"
|
47
|
-
buildConfiguration = "Release"
|
48
|
-
ignoresPersistentStateOnLaunch = "NO"
|
49
|
-
debugDocumentVersioning = "NO"
|
50
|
-
allowLocationSimulation = "YES">
|
51
|
-
<BuildableProductRunnable>
|
52
|
-
<BuildableReference
|
53
|
-
BuildableIdentifier = "primary"
|
54
|
-
BlueprintIdentifier = "5199791315B1F92B003AFC57"
|
55
|
-
BuildableName = "terminal-notifier.app"
|
56
|
-
BlueprintName = "terminal-notifier"
|
57
|
-
ReferencedContainer = "container:Terminal Notifier.xcodeproj">
|
58
|
-
</BuildableReference>
|
59
|
-
</BuildableProductRunnable>
|
60
|
-
<CommandLineArguments>
|
61
|
-
<CommandLineArgument
|
62
|
-
argument = "-group abcde"
|
63
|
-
isEnabled = "NO">
|
64
|
-
</CommandLineArgument>
|
65
|
-
<CommandLineArgument
|
66
|
-
argument = "-help"
|
67
|
-
isEnabled = "NO">
|
68
|
-
</CommandLineArgument>
|
69
|
-
<CommandLineArgument
|
70
|
-
argument = "-sound default"
|
71
|
-
isEnabled = "NO">
|
72
|
-
</CommandLineArgument>
|
73
|
-
<CommandLineArgument
|
74
|
-
argument = "-list ALL"
|
75
|
-
isEnabled = "NO">
|
76
|
-
</CommandLineArgument>
|
77
|
-
<CommandLineArgument
|
78
|
-
argument = "-list abcde"
|
79
|
-
isEnabled = "NO">
|
80
|
-
</CommandLineArgument>
|
81
|
-
<CommandLineArgument
|
82
|
-
argument = "-remove abcde"
|
83
|
-
isEnabled = "NO">
|
84
|
-
</CommandLineArgument>
|
85
|
-
<CommandLineArgument
|
86
|
-
argument = "-open 'http://google.com/search?q=http status codes'"
|
87
|
-
isEnabled = "YES">
|
88
|
-
</CommandLineArgument>
|
89
|
-
<CommandLineArgument
|
90
|
-
argument = "-execute 'say "OMG"'"
|
91
|
-
isEnabled = "NO">
|
92
|
-
</CommandLineArgument>
|
93
|
-
<CommandLineArgument
|
94
|
-
argument = "-execute 'ls -l'"
|
95
|
-
isEnabled = "NO">
|
96
|
-
</CommandLineArgument>
|
97
|
-
<CommandLineArgument
|
98
|
-
argument = "-title Kicker"
|
99
|
-
isEnabled = "NO">
|
100
|
-
</CommandLineArgument>
|
101
|
-
<CommandLineArgument
|
102
|
-
argument = "-message 'Execute: rake spec'"
|
103
|
-
isEnabled = "NO">
|
104
|
-
</CommandLineArgument>
|
105
|
-
<CommandLineArgument
|
106
|
-
argument = "-activate com.apple.Safari"
|
107
|
-
isEnabled = "NO">
|
108
|
-
</CommandLineArgument>
|
109
|
-
<CommandLineArgument
|
110
|
-
argument = "-sender com.apple.Safari"
|
111
|
-
isEnabled = "NO">
|
112
|
-
</CommandLineArgument>
|
113
|
-
</CommandLineArguments>
|
114
|
-
<AdditionalOptions>
|
115
|
-
</AdditionalOptions>
|
116
|
-
</LaunchAction>
|
117
|
-
<ProfileAction
|
118
|
-
shouldUseLaunchSchemeArgsEnv = "YES"
|
119
|
-
savedToolIdentifier = ""
|
120
|
-
useCustomWorkingDirectory = "NO"
|
121
|
-
buildConfiguration = "Release"
|
122
|
-
debugDocumentVersioning = "YES">
|
123
|
-
<BuildableProductRunnable>
|
124
|
-
<BuildableReference
|
125
|
-
BuildableIdentifier = "primary"
|
126
|
-
BlueprintIdentifier = "5199791315B1F92B003AFC57"
|
127
|
-
BuildableName = "terminal-notifier.app"
|
128
|
-
BlueprintName = "terminal-notifier"
|
129
|
-
ReferencedContainer = "container:Terminal Notifier.xcodeproj">
|
130
|
-
</BuildableReference>
|
131
|
-
</BuildableProductRunnable>
|
132
|
-
</ProfileAction>
|
133
|
-
<AnalyzeAction
|
134
|
-
buildConfiguration = "Debug">
|
135
|
-
</AnalyzeAction>
|
136
|
-
<ArchiveAction
|
137
|
-
buildConfiguration = "Release"
|
138
|
-
revealArchiveInOrganizer = "YES">
|
139
|
-
</ArchiveAction>
|
140
|
-
</Scheme>
|
@@ -1,594 +0,0 @@
|
|
1
|
-
#import "AppDelegate.h"
|
2
|
-
#import <ScriptingBridge/ScriptingBridge.h>
|
3
|
-
#import <objc/runtime.h>
|
4
|
-
|
5
|
-
NSString * const TerminalNotifierBundleID = @"nl.superalloy.oss.terminal-notifier";
|
6
|
-
NSString * const NotificationCenterUIBundleID = @"com.apple.notificationcenterui";
|
7
|
-
|
8
|
-
// Set OS Params
|
9
|
-
#define NSAppKitVersionNumber10_8 1187
|
10
|
-
#define NSAppKitVersionNumber10_9 1265
|
11
|
-
|
12
|
-
#define contains(str1, str2) ([str1 rangeOfString: str2 ].location != NSNotFound)
|
13
|
-
|
14
|
-
NSString *_fakeBundleIdentifier = nil;
|
15
|
-
NSUserNotification *currentNotification = nil;
|
16
|
-
|
17
|
-
@implementation NSBundle (FakeBundleIdentifier)
|
18
|
-
|
19
|
-
// Overriding bundleIdentifier works, but overriding NSUserNotificationAlertStyle does not work.
|
20
|
-
|
21
|
-
- (NSString *)__bundleIdentifier;
|
22
|
-
{
|
23
|
-
if (self == [NSBundle mainBundle]) {
|
24
|
-
return _fakeBundleIdentifier ? _fakeBundleIdentifier : TerminalNotifierBundleID;
|
25
|
-
} else {
|
26
|
-
return [self __bundleIdentifier];
|
27
|
-
}
|
28
|
-
}
|
29
|
-
|
30
|
-
@end
|
31
|
-
|
32
|
-
static BOOL
|
33
|
-
InstallFakeBundleIdentifierHook()
|
34
|
-
{
|
35
|
-
Class class = objc_getClass("NSBundle");
|
36
|
-
if (class) {
|
37
|
-
method_exchangeImplementations(class_getInstanceMethod(class, @selector(bundleIdentifier)),
|
38
|
-
class_getInstanceMethod(class, @selector(__bundleIdentifier)));
|
39
|
-
return YES;
|
40
|
-
}
|
41
|
-
return NO;
|
42
|
-
}
|
43
|
-
|
44
|
-
static BOOL
|
45
|
-
isMavericks()
|
46
|
-
{
|
47
|
-
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_8) {
|
48
|
-
/* On a 10.8 - 10.8.x system */
|
49
|
-
return NO;
|
50
|
-
} else {
|
51
|
-
/* 10.9 or later system */
|
52
|
-
return YES;
|
53
|
-
}
|
54
|
-
}
|
55
|
-
|
56
|
-
@implementation NSUserDefaults (SubscriptAndUnescape)
|
57
|
-
- (id)objectForKeyedSubscript:(id)key;
|
58
|
-
{
|
59
|
-
id obj = [self objectForKey:key];
|
60
|
-
if ([obj isKindOfClass:[NSString class]] && [(NSString *)obj hasPrefix:@"\\"]) {
|
61
|
-
obj = [(NSString *)obj substringFromIndex:1];
|
62
|
-
}
|
63
|
-
return obj;
|
64
|
-
}
|
65
|
-
@end
|
66
|
-
|
67
|
-
|
68
|
-
@implementation AppDelegate
|
69
|
-
|
70
|
-
+(void)initializeUserDefaults
|
71
|
-
{
|
72
|
-
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
73
|
-
|
74
|
-
// initialize the dictionary with default values depending on OS level
|
75
|
-
NSDictionary *appDefaults;
|
76
|
-
|
77
|
-
if (isMavericks()) {
|
78
|
-
//10.9
|
79
|
-
appDefaults = @{@"sender": @"com.apple.Terminal"};
|
80
|
-
} else {
|
81
|
-
//10.8
|
82
|
-
appDefaults = @{@"": @"message"};
|
83
|
-
}
|
84
|
-
|
85
|
-
// and set them appropriately
|
86
|
-
[defaults registerDefaults:appDefaults];
|
87
|
-
}
|
88
|
-
|
89
|
-
- (void)printHelpBanner;
|
90
|
-
{
|
91
|
-
const char *appName = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String];
|
92
|
-
const char *appVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] UTF8String];
|
93
|
-
printf("%s (%s) is a command-line tool to send OS X User Notifications.\n" \
|
94
|
-
"\n" \
|
95
|
-
"Usage: %s -[message|list|remove] [VALUE|ID|ID] [options]\n" \
|
96
|
-
"\n" \
|
97
|
-
" Either of these is required (unless message data is piped to the tool):\n" \
|
98
|
-
"\n" \
|
99
|
-
" -help Display this help banner.\n" \
|
100
|
-
" -message VALUE The notification message.\n" \
|
101
|
-
" -remove ID Removes a notification with the specified ‘group’ ID.\n" \
|
102
|
-
" -list ID If the specified ‘group’ ID exists show when it was delivered,\n" \
|
103
|
-
" or use ‘ALL’ as ID to see all notifications.\n" \
|
104
|
-
" The output is a tab-separated list.\n"
|
105
|
-
"\n" \
|
106
|
-
" Reply type notification:\n" \
|
107
|
-
"\n" \
|
108
|
-
" -reply VALUE The notification will be displayed as a reply type alert, VALUE used as placeholder.\n" \
|
109
|
-
"\n" \
|
110
|
-
" Actions type notification:\n" \
|
111
|
-
"\n" \
|
112
|
-
" -actions VALUE1,VALUE2.\n" \
|
113
|
-
" The notification actions avalaible.\n" \
|
114
|
-
" When you provide more than one value, a dropdown will be displayed.\n" \
|
115
|
-
" You can customize this dropdown label with the next option.\n" \
|
116
|
-
" -dropdownLabel VALUE\n" \
|
117
|
-
" The notification actions dropdown title (only when multiples actions are provided).\n" \
|
118
|
-
" Notification style must be set to Alert.\n" \
|
119
|
-
"\n" \
|
120
|
-
" Optional:\n" \
|
121
|
-
"\n" \
|
122
|
-
" -title VALUE The notification title. Defaults to ‘Terminal’.\n" \
|
123
|
-
" -subtitle VALUE The notification subtitle.\n" \
|
124
|
-
" -closeLabel VALUE The notification close button label.\n" \
|
125
|
-
" -sound NAME The name of a sound to play when the notification appears. The names are listed\n" \
|
126
|
-
" in Sound Preferences. Use 'default' for the default notification sound.\n" \
|
127
|
-
" -group ID A string which identifies the group the notifications belong to.\n" \
|
128
|
-
" Old notifications with the same ID will be removed.\n" \
|
129
|
-
" -activate ID The bundle identifier of the application to activate when the user clicks the notification.\n" \
|
130
|
-
" -sender ID The bundle identifier of the application that should be shown as the sender, including its icon.\n" \
|
131
|
-
" -appIcon URL The URL of a image to display instead of the application icon (Mavericks+ only)\n" \
|
132
|
-
" -contentImage URL The URL of a image to display attached to the notification (Mavericks+ only)\n" \
|
133
|
-
" -open URL The URL of a resource to open when the user clicks the notification.\n" \
|
134
|
-
" -execute COMMAND A shell command to perform when the user clicks the notification.\n" \
|
135
|
-
" -timeout NUMBER Close the notification after NUMBER seconds.\n" \
|
136
|
-
" -json Output event or value to stdout as JSON \n" \
|
137
|
-
"\n" \
|
138
|
-
"When the user activates a notification, the results are logged to the system logs.\n" \
|
139
|
-
"Use Console.app to view these logs.\n" \
|
140
|
-
"\n" \
|
141
|
-
"Note that in some circumstances the first character of a message has to be escaped in order to be recognized.\n" \
|
142
|
-
"An example of this is when using an open bracket, which has to be escaped like so: ‘\\[’.\n" \
|
143
|
-
"\n" \
|
144
|
-
"For more information see https://github.com/julienXX/terminal-notifier.\n",
|
145
|
-
appName, appVersion, appName);
|
146
|
-
}
|
147
|
-
|
148
|
-
- (void)applicationDidFinishLaunching:(NSNotification *)notification;
|
149
|
-
{
|
150
|
-
NSUserNotification *userNotification = notification.userInfo[NSApplicationLaunchUserNotificationKey];
|
151
|
-
if (userNotification) {
|
152
|
-
[self userActivatedNotification:userNotification];
|
153
|
-
|
154
|
-
} else {
|
155
|
-
if ([[[NSProcessInfo processInfo] arguments] indexOfObject:@"-help"] != NSNotFound) {
|
156
|
-
[self printHelpBanner];
|
157
|
-
exit(0);
|
158
|
-
}
|
159
|
-
|
160
|
-
NSArray *runningProcesses = [[[NSWorkspace sharedWorkspace] runningApplications] valueForKey:@"bundleIdentifier"];
|
161
|
-
if ([runningProcesses indexOfObject:NotificationCenterUIBundleID] == NSNotFound) {
|
162
|
-
NSLog(@"[!] Unable to post a notification for the current user (%@), as it has no running NotificationCenter instance.", NSUserName());
|
163
|
-
exit(1);
|
164
|
-
}
|
165
|
-
|
166
|
-
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
167
|
-
|
168
|
-
NSString *subtitle = defaults[@"subtitle"];
|
169
|
-
NSString *message = defaults[@"message"];
|
170
|
-
NSString *remove = defaults[@"remove"];
|
171
|
-
NSString *list = defaults[@"list"];
|
172
|
-
NSString *sound = defaults[@"sound"];
|
173
|
-
|
174
|
-
// If there is no message and data is piped to the application, use that
|
175
|
-
// instead.
|
176
|
-
if (message == nil && !isatty(STDIN_FILENO)) {
|
177
|
-
NSData *inputData = [NSData dataWithData:[[NSFileHandle fileHandleWithStandardInput] readDataToEndOfFile]];
|
178
|
-
message = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];
|
179
|
-
}
|
180
|
-
|
181
|
-
if (message == nil && remove == nil && list == nil) {
|
182
|
-
[self printHelpBanner];
|
183
|
-
exit(1);
|
184
|
-
}
|
185
|
-
|
186
|
-
if (list) {
|
187
|
-
[self listNotificationWithGroupID:list];
|
188
|
-
exit(0);
|
189
|
-
}
|
190
|
-
|
191
|
-
// Install the fake bundle ID hook so we can fake the sender. This also
|
192
|
-
// needs to be done to be able to remove a message.
|
193
|
-
if (defaults[@"sender"]) {
|
194
|
-
@autoreleasepool {
|
195
|
-
if (InstallFakeBundleIdentifierHook()) {
|
196
|
-
_fakeBundleIdentifier = defaults[@"sender"];
|
197
|
-
}
|
198
|
-
}
|
199
|
-
}
|
200
|
-
|
201
|
-
if (remove) {
|
202
|
-
[self removeNotificationWithGroupID:remove];
|
203
|
-
if (message == nil) exit(0);
|
204
|
-
}
|
205
|
-
|
206
|
-
if (message) {
|
207
|
-
NSMutableDictionary *options = [NSMutableDictionary dictionary];
|
208
|
-
if (defaults[@"activate"]) options[@"bundleID"] = defaults[@"activate"];
|
209
|
-
if (defaults[@"group"]) options[@"groupID"] = defaults[@"group"];
|
210
|
-
if (defaults[@"execute"]) options[@"command"] = defaults[@"execute"];
|
211
|
-
if (defaults[@"appIcon"]) options[@"appIcon"] = defaults[@"appIcon"];
|
212
|
-
if (defaults[@"contentImage"]) options[@"contentImage"] = defaults[@"contentImage"];
|
213
|
-
if (defaults[@"closeLabel"]) options[@"closeLabel"] = defaults[@"closeLabel"];
|
214
|
-
if (defaults[@"dropdownLabel"]) options[@"dropdownLabel"] = defaults[@"dropdownLabel"];
|
215
|
-
if (defaults[@"actions"]) options[@"actions"] = defaults[@"actions"];
|
216
|
-
|
217
|
-
if([[[NSProcessInfo processInfo] arguments] containsObject:@"-reply"] == true) {
|
218
|
-
options[@"reply"] = @"Reply";
|
219
|
-
if (defaults[@"reply"]) options[@"reply"] = defaults[@"reply"];
|
220
|
-
}
|
221
|
-
|
222
|
-
options[@"output"] = @"outputEvent";
|
223
|
-
if([[[NSProcessInfo processInfo] arguments] containsObject:@"-json"] == true) {
|
224
|
-
options[@"output"] = @"json";
|
225
|
-
}
|
226
|
-
|
227
|
-
options[@"uuid"] = [NSString stringWithFormat:@"%ld", self.hash];
|
228
|
-
options[@"timeout"] = defaults[@"timeout"] ? defaults[@"timeout"] : @"0";
|
229
|
-
|
230
|
-
if (options[@"reply"] || defaults[@"timeout"] || defaults[@"actions"]) options[@"waitForResponse"] = @YES;
|
231
|
-
|
232
|
-
if (defaults[@"open"]) {
|
233
|
-
/*
|
234
|
-
* it may be better to use stringByAddingPercentEncodingWithAllowedCharacters instead of stringByAddingPercentEscapesUsingEncoding,
|
235
|
-
* but stringByAddingPercentEncodingWithAllowedCharacters is only available on OS X 10.9 or higher.
|
236
|
-
*/
|
237
|
-
NSString *encodedURL = [defaults[@"open"] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
238
|
-
NSURL *url = [NSURL URLWithString:defaults[@"open"]];
|
239
|
-
NSString *fragment = [url fragment];
|
240
|
-
if (fragment) {
|
241
|
-
options[@"open"] = [self decodeFragmentInURL:encodedURL fragment:fragment];
|
242
|
-
} else {
|
243
|
-
options[@"open"] = encodedURL;
|
244
|
-
}
|
245
|
-
}
|
246
|
-
|
247
|
-
options[@"uuid"] = [NSString stringWithFormat:@"%ld", self.hash];
|
248
|
-
|
249
|
-
[self deliverNotificationWithTitle:defaults[@"title"] ?: @"Terminal"
|
250
|
-
subtitle:subtitle
|
251
|
-
message:message
|
252
|
-
options:options
|
253
|
-
sound:sound];
|
254
|
-
}
|
255
|
-
}
|
256
|
-
}
|
257
|
-
|
258
|
-
- (NSImage*)getImageFromURL:(NSString *) url;
|
259
|
-
{
|
260
|
-
NSURL *imageURL = [NSURL URLWithString:url];
|
261
|
-
if([[imageURL scheme] length] == 0){
|
262
|
-
// Prefix 'file://' if no scheme
|
263
|
-
imageURL = [NSURL fileURLWithPath:url];
|
264
|
-
}
|
265
|
-
return [[NSImage alloc] initWithContentsOfURL:imageURL];
|
266
|
-
}
|
267
|
-
|
268
|
-
/**
|
269
|
-
* Decode fragment identifier
|
270
|
-
*
|
271
|
-
* @see http://tools.ietf.org/html/rfc3986#section-2.1
|
272
|
-
* @see http://en.wikipedia.org/wiki/URI_scheme
|
273
|
-
*/
|
274
|
-
- (NSString*)decodeFragmentInURL:(NSString *) encodedURL fragment:(NSString *) framgent
|
275
|
-
{
|
276
|
-
NSString *beforeStr = [@"%23" stringByAppendingString:framgent];
|
277
|
-
NSString *afterStr = [@"#" stringByAppendingString:framgent];
|
278
|
-
NSString *decodedURL = [encodedURL stringByReplacingOccurrencesOfString:beforeStr withString:afterStr];
|
279
|
-
return decodedURL;
|
280
|
-
}
|
281
|
-
|
282
|
-
- (void)deliverNotificationWithTitle:(NSString *)title
|
283
|
-
subtitle:(NSString *)subtitle
|
284
|
-
message:(NSString *)message
|
285
|
-
options:(NSDictionary *)options
|
286
|
-
sound:(NSString *)sound;
|
287
|
-
{
|
288
|
-
// First remove earlier notification with the same group ID.
|
289
|
-
if (options[@"groupID"]) [self removeNotificationWithGroupID:options[@"groupID"]];
|
290
|
-
|
291
|
-
NSUserNotification *userNotification = [NSUserNotification new];
|
292
|
-
userNotification.title = title;
|
293
|
-
userNotification.subtitle = subtitle;
|
294
|
-
userNotification.informativeText = message;
|
295
|
-
userNotification.userInfo = options;
|
296
|
-
|
297
|
-
if(isMavericks()){
|
298
|
-
// Mavericks options
|
299
|
-
if(options[@"appIcon"]){
|
300
|
-
// replacement app icon
|
301
|
-
[userNotification setValue:[self getImageFromURL:options[@"appIcon"]] forKey:@"_identityImage"];
|
302
|
-
[userNotification setValue:@(false) forKey:@"_identityImageHasBorder"];
|
303
|
-
}
|
304
|
-
if(options[@"contentImage"]){
|
305
|
-
// content image
|
306
|
-
userNotification.contentImage = [self getImageFromURL:options[@"contentImage"]];
|
307
|
-
}
|
308
|
-
// Actions
|
309
|
-
if (options[@"actions"]){
|
310
|
-
[userNotification setValue:@YES forKey:@"_showsButtons"];
|
311
|
-
NSArray *myActions = [options[@"actions"] componentsSeparatedByString:@","];
|
312
|
-
if (myActions.count > 1) {
|
313
|
-
[userNotification setValue:@YES forKey:@"_alwaysShowAlternateActionMenu"];
|
314
|
-
[userNotification setValue:myActions forKey:@"_alternateActionButtonTitles"];
|
315
|
-
|
316
|
-
//Main Actions Title
|
317
|
-
if(options[@"dropdownLabel"]){
|
318
|
-
userNotification.actionButtonTitle = options[@"dropdownLabel"];
|
319
|
-
userNotification.hasActionButton = true;
|
320
|
-
}
|
321
|
-
}else{
|
322
|
-
userNotification.actionButtonTitle = options[@"actions"];
|
323
|
-
}
|
324
|
-
}else if (options[@"reply"]) {
|
325
|
-
[userNotification setValue:@YES forKey:@"_showsButtons"];
|
326
|
-
userNotification.hasReplyButton = 1;
|
327
|
-
userNotification.responsePlaceholder = options[@"reply"];
|
328
|
-
}
|
329
|
-
|
330
|
-
// Close button
|
331
|
-
if(options[@"closeLabel"]){
|
332
|
-
userNotification.otherButtonTitle = options[@"closeLabel"];
|
333
|
-
}
|
334
|
-
}
|
335
|
-
|
336
|
-
if (sound != nil) {
|
337
|
-
userNotification.soundName = [sound isEqualToString: @"default"] ? NSUserNotificationDefaultSoundName : sound;
|
338
|
-
}
|
339
|
-
|
340
|
-
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
341
|
-
center.delegate = self;
|
342
|
-
[center deliverNotification:userNotification];
|
343
|
-
}
|
344
|
-
|
345
|
-
- (void)removeNotificationWithGroupID:(NSString *)groupID;
|
346
|
-
{
|
347
|
-
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
348
|
-
for (NSUserNotification *userNotification in center.deliveredNotifications) {
|
349
|
-
if ([@"ALL" isEqualToString:groupID] || [userNotification.userInfo[@"groupID"] isEqualToString:groupID]) {
|
350
|
-
[center removeDeliveredNotification:userNotification];
|
351
|
-
}
|
352
|
-
}
|
353
|
-
}
|
354
|
-
|
355
|
-
- (void)userActivatedNotification:(NSUserNotification *)userNotification;
|
356
|
-
{
|
357
|
-
[[NSUserNotificationCenter defaultUserNotificationCenter] removeDeliveredNotification:userNotification];
|
358
|
-
|
359
|
-
NSString *groupID = userNotification.userInfo[@"groupID"];
|
360
|
-
NSString *bundleID = userNotification.userInfo[@"bundleID"];
|
361
|
-
NSString *command = userNotification.userInfo[@"command"];
|
362
|
-
NSString *open = userNotification.userInfo[@"open"];
|
363
|
-
|
364
|
-
if (bundleID) [self activateAppWithBundleID:bundleID];
|
365
|
-
if (command) [self executeShellCommand:command];
|
366
|
-
if (open) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:open]];
|
367
|
-
}
|
368
|
-
|
369
|
-
- (BOOL)activateAppWithBundleID:(NSString *)bundleID;
|
370
|
-
{
|
371
|
-
id app = [SBApplication applicationWithBundleIdentifier:bundleID];
|
372
|
-
if (app) {
|
373
|
-
[app activate];
|
374
|
-
return YES;
|
375
|
-
|
376
|
-
} else {
|
377
|
-
NSLog(@"Unable to find an application with the specified bundle indentifier.");
|
378
|
-
return NO;
|
379
|
-
}
|
380
|
-
}
|
381
|
-
|
382
|
-
- (BOOL)executeShellCommand:(NSString *)command;
|
383
|
-
{
|
384
|
-
NSPipe *pipe = [NSPipe pipe];
|
385
|
-
NSFileHandle *fileHandle = [pipe fileHandleForReading];
|
386
|
-
|
387
|
-
NSTask *task = [NSTask new];
|
388
|
-
task.launchPath = @"/bin/sh";
|
389
|
-
task.arguments = @[@"-c", command];
|
390
|
-
task.standardOutput = pipe;
|
391
|
-
task.standardError = pipe;
|
392
|
-
[task launch];
|
393
|
-
|
394
|
-
NSData *data = nil;
|
395
|
-
NSMutableData *accumulatedData = [NSMutableData data];
|
396
|
-
while ((data = [fileHandle availableData]) && [data length]) {
|
397
|
-
[accumulatedData appendData:data];
|
398
|
-
}
|
399
|
-
|
400
|
-
[task waitUntilExit];
|
401
|
-
NSLog(@"command output:\n%@", [[NSString alloc] initWithData:accumulatedData encoding:NSUTF8StringEncoding]);
|
402
|
-
return [task terminationStatus] == 0;
|
403
|
-
}
|
404
|
-
|
405
|
-
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
|
406
|
-
shouldPresentNotification:(NSUserNotification *)notification;
|
407
|
-
{
|
408
|
-
return YES;
|
409
|
-
}
|
410
|
-
|
411
|
-
// Once the notification is delivered we can exit. (Only if no actions or reply)
|
412
|
-
- (void)userNotificationCenter:(NSUserNotificationCenter *)center
|
413
|
-
didDeliverNotification:(NSUserNotification *)userNotification;
|
414
|
-
{
|
415
|
-
if (!userNotification.userInfo[@"waitForResponse"]) exit(0);
|
416
|
-
|
417
|
-
currentNotification = userNotification;
|
418
|
-
|
419
|
-
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
|
420
|
-
^{
|
421
|
-
__block BOOL notificationStillPresent;
|
422
|
-
do {
|
423
|
-
@autoreleasepool {
|
424
|
-
notificationStillPresent = NO;
|
425
|
-
for (NSUserNotification *nox in [[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications]) {
|
426
|
-
if ([nox.userInfo[@"uuid"] isEqualToString:[NSString stringWithFormat:@"%ld", self.hash] ]) notificationStillPresent = YES;
|
427
|
-
}
|
428
|
-
if (notificationStillPresent) [NSThread sleepForTimeInterval:0.20f];
|
429
|
-
}
|
430
|
-
} while (notificationStillPresent);
|
431
|
-
|
432
|
-
dispatch_async(dispatch_get_main_queue(), ^{
|
433
|
-
NSDictionary *udict = @{@"activationType" : @"closed", @"activationValue" : userNotification.otherButtonTitle};
|
434
|
-
[self Quit:udict notification:userNotification];
|
435
|
-
exit(0);
|
436
|
-
});
|
437
|
-
});
|
438
|
-
|
439
|
-
if ([userNotification.userInfo[@"timeout"] integerValue] > 0){
|
440
|
-
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
|
441
|
-
^{
|
442
|
-
[NSThread sleepForTimeInterval:[userNotification.userInfo[@"timeout"] integerValue]];
|
443
|
-
[center removeDeliveredNotification:currentNotification];
|
444
|
-
[center removeDeliveredNotification:userNotification];
|
445
|
-
NSDictionary *udict = @{@"activationType" : @"timeout"};
|
446
|
-
[self Quit:udict notification:userNotification];
|
447
|
-
exit(0);
|
448
|
-
});
|
449
|
-
}
|
450
|
-
}
|
451
|
-
|
452
|
-
- (void)userNotificationCenter:(NSUserNotificationCenter *)center
|
453
|
-
didActivateNotification:(NSUserNotification *)notification {
|
454
|
-
|
455
|
-
if ([notification.userInfo[@"uuid"] isNotEqualTo:[NSString stringWithFormat:@"%ld", self.hash] ]) {
|
456
|
-
return;
|
457
|
-
};
|
458
|
-
|
459
|
-
unsigned long long additionalActionIndex = ULLONG_MAX;
|
460
|
-
|
461
|
-
NSString* ActionsClicked = @"";
|
462
|
-
switch (notification.activationType) {
|
463
|
-
|
464
|
-
case NSUserNotificationActivationTypeAdditionalActionClicked:
|
465
|
-
case NSUserNotificationActivationTypeActionButtonClicked:
|
466
|
-
if ([[(NSObject*)notification valueForKey:@"_alternateActionButtonTitles"] count] > 1 ){
|
467
|
-
NSNumber *alternateActionIndex = [(NSObject*)notification valueForKey:@"_alternateActionIndex"];
|
468
|
-
additionalActionIndex = [alternateActionIndex unsignedLongLongValue];
|
469
|
-
ActionsClicked = [(NSObject*)notification valueForKey:@"_alternateActionButtonTitles"][additionalActionIndex];
|
470
|
-
|
471
|
-
NSDictionary *udict = @{@"activationType" : @"actionClicked", @"activationValue" : ActionsClicked, @"activationValueIndex" :[NSString stringWithFormat:@"%llu", additionalActionIndex]};
|
472
|
-
[self Quit:udict notification:notification];
|
473
|
-
}else{
|
474
|
-
NSDictionary *udict = @{@"activationType" : @"actionClicked", @"activationValue" : notification.actionButtonTitle};
|
475
|
-
[self Quit:udict notification:notification];
|
476
|
-
}
|
477
|
-
break;
|
478
|
-
|
479
|
-
case NSUserNotificationActivationTypeContentsClicked:
|
480
|
-
[self userActivatedNotification:notification];
|
481
|
-
[self Quit:@{@"activationType" : @"contentsClicked"} notification:notification];
|
482
|
-
break;
|
483
|
-
|
484
|
-
case NSUserNotificationActivationTypeReplied:
|
485
|
-
[self Quit:@{@"activationType" : @"replied",@"activationValue":notification.response.string} notification:notification];
|
486
|
-
break;
|
487
|
-
case NSUserNotificationActivationTypeNone:
|
488
|
-
default:
|
489
|
-
[self Quit:@{@"activationType" : @"none"} notification:notification];
|
490
|
-
break;
|
491
|
-
}
|
492
|
-
|
493
|
-
[center removeDeliveredNotification:notification];
|
494
|
-
[center removeDeliveredNotification:currentNotification];
|
495
|
-
exit(0);
|
496
|
-
}
|
497
|
-
|
498
|
-
- (BOOL)Quit:(NSDictionary *)udict notification:(NSUserNotification *)notification;
|
499
|
-
{
|
500
|
-
if ([notification.userInfo[@"output"] isEqualToString:@"outputEvent"]) {
|
501
|
-
if ([udict[@"activationType"] isEqualToString:@"closed"]) {
|
502
|
-
if ([udict[@"activationValue"] isEqualToString:@""]) {
|
503
|
-
printf("%s", "@CLOSED" );
|
504
|
-
}else{
|
505
|
-
printf("%s", [udict[@"activationValue"] UTF8String] );
|
506
|
-
}
|
507
|
-
} else if ([udict[@"activationType"] isEqualToString:@"timeout"]) {
|
508
|
-
printf("%s", "@TIMEOUT" );
|
509
|
-
} else if ([udict[@"activationType"] isEqualToString:@"contentsClicked"]) {
|
510
|
-
printf("%s", "@CONTENTCLICKED" );
|
511
|
-
} else{
|
512
|
-
if ([udict[@"activationValue"] isEqualToString:@""]) {
|
513
|
-
printf("%s", "@ACTIONCLICKED" );
|
514
|
-
}else{
|
515
|
-
printf("%s", [udict[@"activationValue"] UTF8String] );
|
516
|
-
}
|
517
|
-
}
|
518
|
-
|
519
|
-
return 1;
|
520
|
-
}
|
521
|
-
|
522
|
-
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
523
|
-
dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss Z";
|
524
|
-
|
525
|
-
// Dictionary with several key/value pairs and the above array of arrays
|
526
|
-
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
527
|
-
[dict addEntriesFromDictionary:udict];
|
528
|
-
[dict setValue:[dateFormatter stringFromDate:notification.actualDeliveryDate] forKey:@"deliveredAt"];
|
529
|
-
[dict setValue:[dateFormatter stringFromDate:[NSDate new]] forKey:@"activationAt"];
|
530
|
-
|
531
|
-
NSError *error = nil;
|
532
|
-
NSData *json;
|
533
|
-
|
534
|
-
// Dictionary convertable to JSON ?
|
535
|
-
if ([NSJSONSerialization isValidJSONObject:dict])
|
536
|
-
{
|
537
|
-
// Serialize the dictionary
|
538
|
-
json = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
|
539
|
-
|
540
|
-
// If no errors, let's view the JSON
|
541
|
-
if (json != nil && error == nil)
|
542
|
-
{
|
543
|
-
NSString *jsonString = [[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding];
|
544
|
-
printf("%s", [jsonString cStringUsingEncoding:NSUTF8StringEncoding]);
|
545
|
-
}
|
546
|
-
}
|
547
|
-
|
548
|
-
return 1;
|
549
|
-
}
|
550
|
-
|
551
|
-
- (void)listNotificationWithGroupID:(NSString *)listGroupID;
|
552
|
-
{
|
553
|
-
NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
|
554
|
-
|
555
|
-
NSMutableArray *lines = [NSMutableArray array];
|
556
|
-
for (NSUserNotification *userNotification in center.deliveredNotifications) {
|
557
|
-
NSString *deliveredgroupID = userNotification.userInfo[@"groupID"];
|
558
|
-
NSString *title = userNotification.title;
|
559
|
-
NSString *subtitle = userNotification.subtitle;
|
560
|
-
NSString *message = userNotification.informativeText;
|
561
|
-
NSString *deliveredAt = [userNotification.actualDeliveryDate description];
|
562
|
-
|
563
|
-
if ([@"ALL" isEqualToString:listGroupID] || [deliveredgroupID isEqualToString:listGroupID]) {
|
564
|
-
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
565
|
-
[dict setValue:deliveredgroupID forKey:@"GroupID"];
|
566
|
-
[dict setValue:title forKey:@"Title"];
|
567
|
-
[dict setValue:subtitle forKey:@"subtitle"];
|
568
|
-
[dict setValue:message forKey:@"message"];
|
569
|
-
[dict setValue:deliveredAt forKey:@"deliveredAt"];
|
570
|
-
[lines addObject:dict];
|
571
|
-
}
|
572
|
-
}
|
573
|
-
|
574
|
-
if (lines.count > 0) {
|
575
|
-
NSData *json;
|
576
|
-
NSError *error = nil;
|
577
|
-
// Dictionary convertable to JSON ?
|
578
|
-
if ([NSJSONSerialization isValidJSONObject:lines])
|
579
|
-
{
|
580
|
-
// Serialize the dictionary
|
581
|
-
json = [NSJSONSerialization dataWithJSONObject:lines options:NSJSONWritingPrettyPrinted error:&error];
|
582
|
-
|
583
|
-
// If no errors, let's view the JSON
|
584
|
-
if (json != nil && error == nil)
|
585
|
-
{
|
586
|
-
NSString *jsonString = [[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding];
|
587
|
-
printf("%s", [jsonString cStringUsingEncoding:NSUTF8StringEncoding]);
|
588
|
-
}
|
589
|
-
}
|
590
|
-
|
591
|
-
}
|
592
|
-
}
|
593
|
-
|
594
|
-
@end
|