terminal-notifier 2.0.0 → 3.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.
- checksums.yaml +5 -5
- data/README.markdown +53 -2
- data/bin/terminal-notifier +4 -9
- data/lib/terminal-notifier/cli.rb +21 -0
- data/lib/terminal-notifier/version.rb +10 -0
- data/lib/terminal-notifier.rb +174 -38
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/Info.plist +3 -32
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/MacOS/terminal-notifier +0 -0
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/_CodeSignature/CodeResources +146 -0
- metadata +18 -88
- data/vendor/terminal-notifier/LICENSE.md +0 -9
- data/vendor/terminal-notifier/README.markdown +0 -256
- data/vendor/terminal-notifier/Ruby/Gemfile +0 -2
- data/vendor/terminal-notifier/Ruby/Gemfile.lock +0 -23
- 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 -124
- 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/AppDelegate.h +0 -4
- data/vendor/terminal-notifier/Terminal Notifier/AppDelegate.m +0 -382
- 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 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.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/Resources/en.lproj/Credits.rtf +0 -29
- data/vendor/terminal-notifier/terminal-notifier.app/Contents/Resources/en.lproj/MainMenu.nib +0 -0
- /data/{vendor/terminal-notifier/Ruby/LICENSE → LICENSE} +0 -0
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
require 'rubygems'
|
|
2
|
-
require 'bacon'
|
|
3
|
-
require 'mocha'
|
|
4
|
-
require 'mocha-on-bacon'
|
|
5
|
-
|
|
6
|
-
Bacon.summary_at_exit
|
|
7
|
-
|
|
8
|
-
$:.unshift File.expand_path('../../lib', __FILE__)
|
|
9
|
-
require 'terminal-notifier'
|
|
10
|
-
|
|
11
|
-
describe "TerminalNotifier" do
|
|
12
|
-
it "executes the tool with the given options and properly escapes the message" do
|
|
13
|
-
command = [TerminalNotifier::BIN_PATH, '-message', '\[ZOMG] "OH YEAH"']
|
|
14
|
-
command = Shellwords.join(command) if RUBY_VERSION < '1.9'
|
|
15
|
-
IO.expects(:popen).with(command).yields(StringIO.new('output'))
|
|
16
|
-
TerminalNotifier.execute(false, :message => '[ZOMG] "OH YEAH"')
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it "correctly escapes arguments that start with a dash" do
|
|
20
|
-
command = [TerminalNotifier::BIN_PATH, '-message', ' -kittens', '-title', ' -rule']
|
|
21
|
-
command = Shellwords.join(command) if RUBY_VERSION < '1.9'
|
|
22
|
-
IO.expects(:popen).with(command).yields(StringIO.new('output'))
|
|
23
|
-
TerminalNotifier.execute(false, :message => '-kittens', :title => '-rule')
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it "returns the result output of the command" do
|
|
27
|
-
TerminalNotifier.execute(false, 'help' => '').should == `'#{TerminalNotifier::BIN_PATH}' -help`
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it "sends a notification" do
|
|
31
|
-
TerminalNotifier.expects(:execute).with(false, :message => 'ZOMG', :group => 'important stuff')
|
|
32
|
-
TerminalNotifier.notify('ZOMG', :group => 'important stuff')
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it "removes a notification" do
|
|
36
|
-
TerminalNotifier.expects(:execute).with(false, :remove => 'important stuff')
|
|
37
|
-
TerminalNotifier.remove('important stuff')
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it "by default removes all the notifications" do
|
|
41
|
-
TerminalNotifier.expects(:execute).with(false, :remove => 'ALL')
|
|
42
|
-
TerminalNotifier.remove
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
it "returns `nil` if no notification was found to list info for" do
|
|
46
|
-
TerminalNotifier.expects(:execute).with(false, :list => 'important stuff').returns('')
|
|
47
|
-
TerminalNotifier.list('important stuff').should == nil
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it "returns info about a notification posted in a specific group" do
|
|
51
|
-
TerminalNotifier.expects(:execute).with(false, :list => 'important stuff').
|
|
52
|
-
returns("GroupID\tTitle\tSubtitle\tMessage\tDelivered At\n" \
|
|
53
|
-
"important stuff\tTerminal\t(null)\tExecute: rake spec\t2012-08-06 19:45:30 +0000")
|
|
54
|
-
TerminalNotifier.list('important stuff').should == {
|
|
55
|
-
:group => 'important stuff',
|
|
56
|
-
:title => 'Terminal', :subtitle => nil, :message => 'Execute: rake spec',
|
|
57
|
-
:delivered_at => Time.parse('2012-08-06 19:45:30 +0000')
|
|
58
|
-
}
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
it "by default returns a list of all notification" do
|
|
62
|
-
TerminalNotifier.expects(:execute).with(false, :list => 'ALL').
|
|
63
|
-
returns("GroupID\tTitle\tSubtitle\tMessage\tDelivered At\n" \
|
|
64
|
-
"important stuff\tTerminal\t(null)\tExecute: rake spec\t2012-08-06 19:45:30 +0000\n" \
|
|
65
|
-
"(null)\t(null)\tSubtle\tBe subtle!\t2012-08-07 19:45:30 +0000")
|
|
66
|
-
TerminalNotifier.list.should == [
|
|
67
|
-
{
|
|
68
|
-
:group => 'important stuff',
|
|
69
|
-
:title => 'Terminal', :subtitle => nil, :message => 'Execute: rake spec',
|
|
70
|
-
:delivered_at => Time.parse('2012-08-06 19:45:30 +0000')
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
:group => nil,
|
|
74
|
-
:title => nil, :subtitle => 'Subtle', :message => 'Be subtle!',
|
|
75
|
-
:delivered_at => Time.parse('2012-08-07 19:45:30 +0000')
|
|
76
|
-
}
|
|
77
|
-
]
|
|
78
|
-
end
|
|
79
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
plist = File.expand_path('../../Terminal Notifier/Terminal Notifier-Info.plist', __FILE__)
|
|
3
|
-
# Also run on non-OSX machines, otherwise bundle installs directly from the repo will fail.
|
|
4
|
-
# version = `/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' '#{plist}'`.strip
|
|
5
|
-
version = File.read(plist).match(%r{<string>(\d+\.\d+\.\d+)</string>})[1]
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Gem::Specification.new do |gem|
|
|
9
|
-
gem.name = "terminal-notifier"
|
|
10
|
-
gem.version = version
|
|
11
|
-
gem.summary = 'Send User Notifications on macOS 10.10 or higher.'
|
|
12
|
-
gem.authors = ["Eloy Duran", "Julien Blanchard"]
|
|
13
|
-
gem.email = ["eloy.de.enige@gmail.com", "julien@sideburns.eu"]
|
|
14
|
-
gem.homepage = 'https://github.com/julienXX/terminal-notifier'
|
|
15
|
-
gem.license = 'MIT'
|
|
16
|
-
|
|
17
|
-
gem.executables = ['terminal-notifier']
|
|
18
|
-
gem.files = ['bin/terminal-notifier', 'lib/terminal-notifier.rb'] + Dir.glob('vendor/terminal-notifier/**/*')
|
|
19
|
-
gem.require_paths = ['lib']
|
|
20
|
-
|
|
21
|
-
gem.extra_rdoc_files = ['README.markdown']
|
|
22
|
-
|
|
23
|
-
gem.add_development_dependency 'bacon'
|
|
24
|
-
gem.add_development_dependency 'mocha'
|
|
25
|
-
gem.add_development_dependency 'mocha-on-bacon'
|
|
26
|
-
end
|
|
@@ -1,382 +0,0 @@
|
|
|
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
|
|
@@ -1,43 +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>CFBundleDevelopmentRegion</key>
|
|
6
|
-
<string>en</string>
|
|
7
|
-
<key>CFBundleExecutable</key>
|
|
8
|
-
<string>${EXECUTABLE_NAME}</string>
|
|
9
|
-
<key>CFBundleIconFile</key>
|
|
10
|
-
<string>Terminal</string>
|
|
11
|
-
<key>CFBundleIdentifier</key>
|
|
12
|
-
<string>fr.julienxx.oss.terminal-notifier</string>
|
|
13
|
-
<key>CFBundleInfoDictionaryVersion</key>
|
|
14
|
-
<string>6.0</string>
|
|
15
|
-
<key>CFBundleName</key>
|
|
16
|
-
<string>${PRODUCT_NAME}</string>
|
|
17
|
-
<key>CFBundlePackageType</key>
|
|
18
|
-
<string>APPL</string>
|
|
19
|
-
<key>CFBundleShortVersionString</key>
|
|
20
|
-
<string>2.0.0</string>
|
|
21
|
-
<key>CFBundleSignature</key>
|
|
22
|
-
<string>????</string>
|
|
23
|
-
<key>CFBundleVersion</key>
|
|
24
|
-
<string>15</string>
|
|
25
|
-
<key>LSMinimumSystemVersion</key>
|
|
26
|
-
<string>10.10</string>
|
|
27
|
-
<key>LSUIElement</key>
|
|
28
|
-
<true/>
|
|
29
|
-
<key>NSHumanReadableCopyright</key>
|
|
30
|
-
<string>Copyright © 2012-2017 Eloy Durán, Julien Blanchard. All rights reserved.</string>
|
|
31
|
-
<key>NSMainNibFile</key>
|
|
32
|
-
<string>MainMenu</string>
|
|
33
|
-
<key>NSPrincipalClass</key>
|
|
34
|
-
<string>NSApplication</string>
|
|
35
|
-
<key>NSAppTransportSecurity</key>
|
|
36
|
-
<dict>
|
|
37
|
-
<key>NSAllowsArbitraryLoads</key>
|
|
38
|
-
<true/>
|
|
39
|
-
</dict>
|
|
40
|
-
<key>NSUserNotificationAlertStyle</key>
|
|
41
|
-
<string>banner</string>
|
|
42
|
-
</dict>
|
|
43
|
-
</plist>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;}
|
|
2
|
-
{\colortbl;\red255\green255\blue255;}
|
|
3
|
-
\paperw9840\paperh8400
|
|
4
|
-
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural
|
|
5
|
-
|
|
6
|
-
\f0\b\fs24 \cf0 Engineering:
|
|
7
|
-
\b0 \
|
|
8
|
-
Some people\
|
|
9
|
-
\
|
|
10
|
-
|
|
11
|
-
\b Human Interface Design:
|
|
12
|
-
\b0 \
|
|
13
|
-
Some other people\
|
|
14
|
-
\
|
|
15
|
-
|
|
16
|
-
\b Testing:
|
|
17
|
-
\b0 \
|
|
18
|
-
Hopefully not nobody\
|
|
19
|
-
\
|
|
20
|
-
|
|
21
|
-
\b Documentation:
|
|
22
|
-
\b0 \
|
|
23
|
-
Whoever\
|
|
24
|
-
\
|
|
25
|
-
|
|
26
|
-
\b With special thanks to:
|
|
27
|
-
\b0 \
|
|
28
|
-
Mom\
|
|
29
|
-
}
|