terminal-notifier 1.8.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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