terminal-notifier 1.8.0 → 2.0.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.markdown +5 -5
  3. data/lib/terminal-notifier.rb +39 -8
  4. data/vendor/terminal-notifier/LICENSE.md +9 -0
  5. data/vendor/terminal-notifier/README.markdown +256 -0
  6. data/vendor/terminal-notifier/Ruby/Gemfile +2 -0
  7. data/vendor/terminal-notifier/Ruby/Gemfile.lock +23 -0
  8. data/vendor/terminal-notifier/Ruby/LICENSE +24 -0
  9. data/vendor/terminal-notifier/Ruby/README.markdown +48 -0
  10. data/vendor/terminal-notifier/Ruby/Rakefile +48 -0
  11. data/vendor/terminal-notifier/Ruby/bin/terminal-notifier +13 -0
  12. data/vendor/terminal-notifier/Ruby/lib/terminal-notifier.rb +124 -0
  13. data/vendor/terminal-notifier/Ruby/spec/terminal-notifier_spec.rb +79 -0
  14. data/vendor/terminal-notifier/Ruby/terminal-notifier.gemspec +26 -0
  15. data/vendor/terminal-notifier/Terminal Notifier.xcodeproj/project.pbxproj +315 -0
  16. data/vendor/terminal-notifier/Terminal Notifier.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  17. data/vendor/terminal-notifier/Terminal Notifier.xcodeproj/project.xcworkspace/xcshareddata/Terminal Notifier.xccheckout +41 -0
  18. data/vendor/terminal-notifier/Terminal Notifier.xcodeproj/xcshareddata/xcschemes/Terminal Notifier.xcscheme +140 -0
  19. data/vendor/terminal-notifier/Terminal Notifier/AppDelegate.h +4 -0
  20. data/vendor/terminal-notifier/Terminal Notifier/AppDelegate.m +382 -0
  21. data/vendor/terminal-notifier/Terminal Notifier/Terminal Notifier-Info.plist +43 -0
  22. data/vendor/terminal-notifier/Terminal Notifier/Terminal Notifier-Prefix.pch +7 -0
  23. data/vendor/terminal-notifier/Terminal Notifier/en.lproj/Credits.rtf +29 -0
  24. data/vendor/terminal-notifier/Terminal Notifier/en.lproj/InfoPlist.strings +2 -0
  25. data/vendor/terminal-notifier/Terminal Notifier/en.lproj/MainMenu.xib +3387 -0
  26. data/vendor/terminal-notifier/Terminal Notifier/main.m +6 -0
  27. data/vendor/terminal-notifier/Terminal.icns +0 -0
  28. data/vendor/terminal-notifier/assets/Example_1.png +0 -0
  29. data/vendor/terminal-notifier/assets/Example_2.png +0 -0
  30. data/vendor/terminal-notifier/assets/Example_3.png +0 -0
  31. data/vendor/terminal-notifier/assets/Example_4.png +0 -0
  32. data/vendor/terminal-notifier/assets/Example_5.png +0 -0
  33. data/vendor/terminal-notifier/assets/System_prefs.png +0 -0
  34. data/vendor/terminal-notifier/terminal-notifier.app/Contents/Info.plist +63 -0
  35. data/vendor/terminal-notifier/terminal-notifier.app/Contents/MacOS/terminal-notifier +0 -0
  36. data/vendor/terminal-notifier/terminal-notifier.app/Contents/PkgInfo +1 -0
  37. data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/Terminal.icns +0 -0
  38. data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/en.lproj/Credits.rtf +29 -0
  39. data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  40. data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/en.lproj/MainMenu.nib +0 -0
  41. metadata +42 -4
  42. data/vendor/terminal-notifier +0 -0
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Workspace
3
+ version = "1.0">
4
+ <FileRef
5
+ location = "self:Terminal Notifier.xcodeproj">
6
+ </FileRef>
7
+ </Workspace>
@@ -0,0 +1,41 @@
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:julienXX/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:julienXX/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>
@@ -0,0 +1,140 @@
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 &apos;http://google.com/search?q=http status codes&apos;"
87
+ isEnabled = "YES">
88
+ </CommandLineArgument>
89
+ <CommandLineArgument
90
+ argument = "-execute &apos;say &quot;OMG&quot;&apos;"
91
+ isEnabled = "NO">
92
+ </CommandLineArgument>
93
+ <CommandLineArgument
94
+ argument = "-execute &apos;ls -l&apos;"
95
+ isEnabled = "NO">
96
+ </CommandLineArgument>
97
+ <CommandLineArgument
98
+ argument = "-title Kicker"
99
+ isEnabled = "NO">
100
+ </CommandLineArgument>
101
+ <CommandLineArgument
102
+ argument = "-message &apos;Execute: rake spec&apos;"
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>
@@ -0,0 +1,4 @@
1
+ #import <Cocoa/Cocoa.h>
2
+
3
+ @interface AppDelegate : NSObject <NSApplicationDelegate, NSUserNotificationCenterDelegate>
4
+ @end
@@ -0,0 +1,382 @@
1
+ #import "AppDelegate.h"
2
+ #import <ScriptingBridge/ScriptingBridge.h>
3
+ #import <objc/runtime.h>
4
+
5
+ NSString * const TerminalNotifierBundleID = @"fr.julienxx.oss.terminal-notifier";
6
+ NSString * const NotificationCenterUIBundleID = @"com.apple.notificationcenterui";
7
+
8
+ NSString *_fakeBundleIdentifier = nil;
9
+
10
+ @implementation NSBundle (FakeBundleIdentifier)
11
+
12
+ // Overriding bundleIdentifier works, but overriding NSUserNotificationAlertStyle does not work.
13
+
14
+ - (NSString *)__bundleIdentifier;
15
+ {
16
+ if (self == [NSBundle mainBundle]) {
17
+ return _fakeBundleIdentifier ? _fakeBundleIdentifier : TerminalNotifierBundleID;
18
+ } else {
19
+ return [self __bundleIdentifier];
20
+ }
21
+ }
22
+
23
+ @end
24
+
25
+ static BOOL
26
+ InstallFakeBundleIdentifierHook()
27
+ {
28
+ Class class = objc_getClass("NSBundle");
29
+ if (class) {
30
+ method_exchangeImplementations(class_getInstanceMethod(class, @selector(bundleIdentifier)),
31
+ class_getInstanceMethod(class, @selector(__bundleIdentifier)));
32
+ return YES;
33
+ }
34
+ return NO;
35
+ }
36
+
37
+ @implementation NSUserDefaults (SubscriptAndUnescape)
38
+ - (id)objectForKeyedSubscript:(id)key;
39
+ {
40
+ id obj = [self objectForKey:key];
41
+ if ([obj isKindOfClass:[NSString class]] && [(NSString *)obj hasPrefix:@"\\"]) {
42
+ obj = [(NSString *)obj substringFromIndex:1];
43
+ }
44
+ return obj;
45
+ }
46
+ @end
47
+
48
+
49
+ @implementation AppDelegate
50
+
51
+ +(void)initializeUserDefaults
52
+ {
53
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
54
+
55
+ // initialize the dictionary with default values depending on OS level
56
+ NSDictionary *appDefaults;
57
+ appDefaults = @{@"sender": @"com.apple.Terminal"};
58
+
59
+ // and set them appropriately
60
+ [defaults registerDefaults:appDefaults];
61
+ }
62
+
63
+ - (void)printHelpBanner;
64
+ {
65
+ const char *appName = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String];
66
+ const char *appVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] UTF8String];
67
+ printf("%s (%s) is a command-line tool to send macOS User Notifications.\n" \
68
+ "\n" \
69
+ "Usage: %s -[message|list|remove] [VALUE|ID|ID] [options]\n" \
70
+ "\n" \
71
+ " Either of these is required (unless message data is piped to the tool):\n" \
72
+ "\n" \
73
+ " -help Display this help banner.\n" \
74
+ " -version Display terminal-notifier version.\n" \
75
+ " -message VALUE The notification message.\n" \
76
+ " -remove ID Removes a notification with the specified ‘group’ ID.\n" \
77
+ " -list ID If the specified ‘group’ ID exists show when it was delivered,\n" \
78
+ " or use ‘ALL’ as ID to see all notifications.\n" \
79
+ " The output is a tab-separated list.\n"
80
+ "\n" \
81
+ " Optional:\n" \
82
+ "\n" \
83
+ " -title VALUE The notification title. Defaults to ‘Terminal’.\n" \
84
+ " -subtitle VALUE The notification subtitle.\n" \
85
+ " -sound NAME The name of a sound to play when the notification appears. The names are listed\n" \
86
+ " in Sound Preferences. Use 'default' for the default notification sound.\n" \
87
+ " -group ID A string which identifies the group the notifications belong to.\n" \
88
+ " Old notifications with the same ID will be removed.\n" \
89
+ " -activate ID The bundle identifier of the application to activate when the user clicks the notification.\n" \
90
+ " -sender ID The bundle identifier of the application that should be shown as the sender, including its icon.\n" \
91
+ " -appIcon URL The URL of a image to display instead of the application icon (Mavericks+ only)\n" \
92
+ " -contentImage URL The URL of a image to display attached to the notification (Mavericks+ only)\n" \
93
+ " -open URL The URL of a resource to open when the user clicks the notification.\n" \
94
+ " -execute COMMAND A shell command to perform when the user clicks the notification.\n" \
95
+ " -ignoreDnD Send notification even if Do Not Disturb is enabled.\n" \
96
+ "\n" \
97
+ "When the user activates a notification, the results are logged to the system logs.\n" \
98
+ "Use Console.app to view these logs.\n" \
99
+ "\n" \
100
+ "Note that in some circumstances the first character of a message has to be escaped in order to be recognized.\n" \
101
+ "An example of this is when using an open bracket, which has to be escaped like so: ‘\\[’.\n" \
102
+ "\n" \
103
+ "For more information see https://github.com/julienXX/terminal-notifier.\n",
104
+ appName, appVersion, appName);
105
+ }
106
+
107
+ - (void)printVersion;
108
+ {
109
+ const char *appName = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String];
110
+ const char *appVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] UTF8String];
111
+ printf("%s %s.\n", appName, appVersion);
112
+ }
113
+
114
+ - (void)applicationDidFinishLaunching:(NSNotification *)notification;
115
+ {
116
+ NSUserNotification *userNotification = notification.userInfo[NSApplicationLaunchUserNotificationKey];
117
+ if (userNotification) {
118
+ [self userActivatedNotification:userNotification];
119
+
120
+ } else {
121
+ if ([[[NSProcessInfo processInfo] arguments] indexOfObject:@"-help"] != NSNotFound) {
122
+ [self printHelpBanner];
123
+ exit(0);
124
+ }
125
+
126
+ if ([[[NSProcessInfo processInfo] arguments] indexOfObject:@"-version"] != NSNotFound) {
127
+ [self printVersion];
128
+ exit(0);
129
+ }
130
+
131
+ NSArray *runningProcesses = [[[NSWorkspace sharedWorkspace] runningApplications] valueForKey:@"bundleIdentifier"];
132
+ if ([runningProcesses indexOfObject:NotificationCenterUIBundleID] == NSNotFound) {
133
+ NSLog(@"[!] Unable to post a notification for the current user (%@), as it has no running NotificationCenter instance.", NSUserName());
134
+ exit(1);
135
+ }
136
+
137
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
138
+
139
+ NSString *subtitle = defaults[@"subtitle"];
140
+ NSString *message = defaults[@"message"];
141
+ NSString *remove = defaults[@"remove"];
142
+ NSString *list = defaults[@"list"];
143
+ NSString *sound = defaults[@"sound"];
144
+
145
+ // If there is no message and data is piped to the application, use that
146
+ // instead.
147
+ if (message == nil && !isatty(STDIN_FILENO)) {
148
+ NSData *inputData = [NSData dataWithData:[[NSFileHandle fileHandleWithStandardInput] readDataToEndOfFile]];
149
+ message = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];
150
+ }
151
+
152
+ if (message == nil && remove == nil && list == nil) {
153
+ [self printHelpBanner];
154
+ exit(1);
155
+ }
156
+
157
+ if (list) {
158
+ [self listNotificationWithGroupID:list];
159
+ exit(0);
160
+ }
161
+
162
+ // Install the fake bundle ID hook so we can fake the sender. This also
163
+ // needs to be done to be able to remove a message.
164
+ if (defaults[@"sender"]) {
165
+ @autoreleasepool {
166
+ if (InstallFakeBundleIdentifierHook()) {
167
+ _fakeBundleIdentifier = defaults[@"sender"];
168
+ }
169
+ }
170
+ }
171
+
172
+ if (remove) {
173
+ [self removeNotificationWithGroupID:remove];
174
+ if (message == nil || ([message length] == 0)) {
175
+ exit(0);
176
+ }
177
+ }
178
+
179
+ if (message) {
180
+ NSMutableDictionary *options = [NSMutableDictionary dictionary];
181
+ if (defaults[@"activate"]) options[@"bundleID"] = defaults[@"activate"];
182
+ if (defaults[@"group"]) options[@"groupID"] = defaults[@"group"];
183
+ if (defaults[@"execute"]) options[@"command"] = defaults[@"execute"];
184
+ if (defaults[@"appIcon"]) options[@"appIcon"] = defaults[@"appIcon"];
185
+ if (defaults[@"contentImage"]) options[@"contentImage"] = defaults[@"contentImage"];
186
+
187
+ if (defaults[@"open"]) {
188
+ NSURL *url = [NSURL URLWithString:defaults[@"open"]];
189
+ if ((url && url.scheme && url.host) || [url isFileURL]) {
190
+ options[@"open"] = defaults[@"open"];
191
+ }else{
192
+ NSLog(@"'%@' is not a valid URI.", defaults[@"open"]);
193
+ exit(1);
194
+ }
195
+ }
196
+
197
+ if([[[NSProcessInfo processInfo] arguments] containsObject:@"-ignoreDnD"] == true) {
198
+ options[@"ignoreDnD"] = @YES;
199
+ }
200
+
201
+ [self deliverNotificationWithTitle:defaults[@"title"] ?: @"Terminal"
202
+ subtitle:subtitle
203
+ message:message
204
+ options:options
205
+ sound:sound];
206
+ }
207
+ }
208
+ }
209
+
210
+ - (NSImage*)getImageFromURL:(NSString *) url;
211
+ {
212
+ NSURL *imageURL = [NSURL URLWithString:url];
213
+ if([[imageURL scheme] length] == 0){
214
+ // Prefix 'file://' if no scheme
215
+ imageURL = [NSURL fileURLWithPath:url];
216
+ }
217
+ return [[NSImage alloc] initWithContentsOfURL:imageURL];
218
+ }
219
+
220
+ /**
221
+ * Decode fragment identifier
222
+ *
223
+ * @see http://tools.ietf.org/html/rfc3986#section-2.1
224
+ * @see http://en.wikipedia.org/wiki/URI_scheme
225
+ */
226
+ - (NSString*)decodeFragmentInURL:(NSString *) encodedURL fragment:(NSString *) framgent
227
+ {
228
+ NSString *beforeStr = [@"%23" stringByAppendingString:framgent];
229
+ NSString *afterStr = [@"#" stringByAppendingString:framgent];
230
+ NSString *decodedURL = [encodedURL stringByReplacingOccurrencesOfString:beforeStr withString:afterStr];
231
+ return decodedURL;
232
+ }
233
+
234
+ - (void)deliverNotificationWithTitle:(NSString *)title
235
+ subtitle:(NSString *)subtitle
236
+ message:(NSString *)message
237
+ options:(NSDictionary *)options
238
+ sound:(NSString *)sound;
239
+ {
240
+ // First remove earlier notification with the same group ID.
241
+ if (options[@"groupID"]) [self removeNotificationWithGroupID:options[@"groupID"]];
242
+
243
+ NSUserNotification *userNotification = [NSUserNotification new];
244
+ userNotification.title = title;
245
+ userNotification.subtitle = subtitle;
246
+ userNotification.informativeText = message;
247
+ userNotification.userInfo = options;
248
+
249
+ if(options[@"appIcon"]){
250
+ [userNotification setValue:[self getImageFromURL:options[@"appIcon"]] forKey:@"_identityImage"];
251
+ [userNotification setValue:@(false) forKey:@"_identityImageHasBorder"];
252
+ }
253
+ if(options[@"contentImage"]){
254
+ userNotification.contentImage = [self getImageFromURL:options[@"contentImage"]];
255
+ }
256
+
257
+ if (sound != nil) {
258
+ userNotification.soundName = [sound isEqualToString: @"default"] ? NSUserNotificationDefaultSoundName : sound ;
259
+ }
260
+
261
+ if(options[@"ignoreDnD"]){
262
+ [userNotification setValue:@YES forKey:@"_ignoresDoNotDisturb"];
263
+ }
264
+
265
+ NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
266
+ center.delegate = self;
267
+ [center scheduleNotification:userNotification];
268
+ }
269
+
270
+ - (void)removeNotificationWithGroupID:(NSString *)groupID;
271
+ {
272
+ NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
273
+ for (NSUserNotification *userNotification in center.deliveredNotifications) {
274
+ if ([@"ALL" isEqualToString:groupID] || [userNotification.userInfo[@"groupID"] isEqualToString:groupID]) {
275
+ NSString *deliveredAt = [userNotification.actualDeliveryDate description];
276
+ printf("* Removing previously sent notification, which was sent on: %s\n", [deliveredAt UTF8String]);
277
+ [center removeDeliveredNotification:userNotification];
278
+ }
279
+ }
280
+ }
281
+
282
+ - (void)listNotificationWithGroupID:(NSString *)listGroupID;
283
+ {
284
+ NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
285
+
286
+ NSMutableArray *lines = [NSMutableArray array];
287
+ for (NSUserNotification *userNotification in center.deliveredNotifications) {
288
+ NSString *deliveredgroupID = userNotification.userInfo[@"groupID"];
289
+ NSString *title = userNotification.title;
290
+ NSString *subtitle = userNotification.subtitle;
291
+ NSString *message = userNotification.informativeText;
292
+ NSString *deliveredAt = [userNotification.actualDeliveryDate description];
293
+ if ([@"ALL" isEqualToString:listGroupID] || [deliveredgroupID isEqualToString:listGroupID]) {
294
+ [lines addObject:[NSString stringWithFormat:@"%@\t%@\t%@\t%@\t%@", deliveredgroupID, title, subtitle, message, deliveredAt]];
295
+ }
296
+ }
297
+
298
+ if (lines.count > 0) {
299
+ printf("GroupID\tTitle\tSubtitle\tMessage\tDelivered At\n");
300
+ for (NSString *line in lines) {
301
+ printf("%s\n", [line UTF8String]);
302
+ }
303
+ }
304
+ }
305
+
306
+
307
+ - (void)userActivatedNotification:(NSUserNotification *)userNotification;
308
+ {
309
+ [[NSUserNotificationCenter defaultUserNotificationCenter] removeDeliveredNotification:userNotification];
310
+
311
+ NSString *groupID = userNotification.userInfo[@"groupID"];
312
+ NSString *bundleID = userNotification.userInfo[@"bundleID"];
313
+ NSString *command = userNotification.userInfo[@"command"];
314
+ NSString *open = userNotification.userInfo[@"open"];
315
+
316
+ NSLog(@"User activated notification:");
317
+ NSLog(@" group ID: %@", groupID);
318
+ NSLog(@" title: %@", userNotification.title);
319
+ NSLog(@" subtitle: %@", userNotification.subtitle);
320
+ NSLog(@" message: %@", userNotification.informativeText);
321
+ NSLog(@"bundle ID: %@", bundleID);
322
+ NSLog(@" command: %@", command);
323
+ NSLog(@" open: %@", open);
324
+
325
+ BOOL success = YES;
326
+ if (bundleID) success &= [self activateAppWithBundleID:bundleID];
327
+ if (command) success &= [self executeShellCommand:command];
328
+ if (open) success &= [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:open]];
329
+
330
+ exit(success ? 0 : 1);
331
+ }
332
+
333
+ - (BOOL)activateAppWithBundleID:(NSString *)bundleID;
334
+ {
335
+ id app = [SBApplication applicationWithBundleIdentifier:bundleID];
336
+ if (app) {
337
+ [app activate];
338
+ return YES;
339
+
340
+ } else {
341
+ NSLog(@"Unable to find an application with the specified bundle indentifier.");
342
+ return NO;
343
+ }
344
+ }
345
+
346
+ - (BOOL)executeShellCommand:(NSString *)command;
347
+ {
348
+ NSPipe *pipe = [NSPipe pipe];
349
+ NSFileHandle *fileHandle = [pipe fileHandleForReading];
350
+
351
+ NSTask *task = [NSTask new];
352
+ task.launchPath = @"/bin/sh";
353
+ task.arguments = @[@"-c", command];
354
+ task.standardOutput = pipe;
355
+ task.standardError = pipe;
356
+ [task launch];
357
+
358
+ NSData *data = nil;
359
+ NSMutableData *accumulatedData = [NSMutableData data];
360
+ while ((data = [fileHandle availableData]) && [data length]) {
361
+ [accumulatedData appendData:data];
362
+ }
363
+
364
+ [task waitUntilExit];
365
+ NSLog(@"command output:\n%@", [[NSString alloc] initWithData:accumulatedData encoding:NSUTF8StringEncoding]);
366
+ return [task terminationStatus] == 0;
367
+ }
368
+
369
+ - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center
370
+ shouldPresentNotification:(NSUserNotification *)userNotification;
371
+ {
372
+ return YES;
373
+ }
374
+
375
+ // Once the notification is delivered we can exit.
376
+ - (void)userNotificationCenter:(NSUserNotificationCenter *)center
377
+ didDeliverNotification:(NSUserNotification *)userNotification;
378
+ {
379
+ exit(0);
380
+ }
381
+
382
+ @end