-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMPTPluginMacros.h
More file actions
530 lines (475 loc) · 28.2 KB
/
MPTPluginMacros.h
File metadata and controls
530 lines (475 loc) · 28.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
//
// MPTPluginMacros.h
// Mail Bundle Manager
//
// Created by Scott Little on 10/10/2011.
// Copyright (c) 2011 Little Known Software. All rights reserved.
//
#import <Foundation/Foundation.h>
#if __has_feature(objc_arc)
#define MPT_MACRO_RELEASE(x) while (0) {}
#else
#define MPT_MACRO_RELEASE(x) [x release];
#endif
typedef void(^MPTResultNotificationBlock)(NSDictionary *infoResults);
typedef void(^MPTLaunchResultBlock)(NSError *launchError);
typedef void(^MPTUpdateTestingCompleteBlock)(void);
#pragma mark Dictionary Keys
// Keys for historical UUID plist
#define MPT_UUID_COMPLETE_LIST_KEY @"all-uuids"
#define MPT_UUID_LATEST_SUPPORTED_UUID_KEY @"latest-supported-uuid-dict"
#define MPT_UUID_FIRST_UNSUPPORTED_UUID_KEY @"first-unsupported-uuid-dict"
#define MPT_UUID_TYPE_KEY @"type"
#define MPT_UUID_EARLIEST_OS_VERSION_DISPLAY_KEY @"earliest-os-version-display"
#define MPT_UUID_LATEST_OS_VERSION_DISPLAY_KEY @"latest-os-version-display"
#define MPT_UUID_LATEST_VERSION_KEY @"latest-version-comparator"
#define MPT_UUID_TYPE_VALUE_MAIL @"mail"
#define MPT_UUID_TYPE_VALUE_MESSAGE @"message"
// Keys for System Information dictionary
#define MPT_SYSINFO_ANONYMOUS_ID_KEY @"anonymous-id"
#define MPT_SYSINFO_SYSTEM_KEY @"system"
#define MPT_SYSINFO_MAIL_KEY @"mail"
#define MPT_SYSINFO_MESSAGE_KEY @"message"
#define MPT_SYSINFO_HARDWARE_KEY @"hardware"
#define MPT_SYSINFO_INSTALLED_PLUGINS_KEY @"installed"
#define MPT_SYSINFO_DISABLED_PLUGINS_KEY @"disabled"
#define MPT_SYSINFO_VERSION_KEY @"version"
#define MPT_SYSINFO_BUILD_KEY @"build"
#define MPT_SYSINFO_UUID_KEY @"uuid"
#define MPT_SYSINFO_NAME_KEY @"name"
#define MPT_SYSINFO_PATH_KEY @"path"
// Notification string for when Sparkle modifies defaults outside of app
#define MPT_DEFAULTS_CHANGE_DIST_NOTIFICATION @"LKSSUPluginDefaultsChanged"
// Preferences key for when to suppres alert about MPM missing (stored in Mail's Preferences)
#define MPT_SUPPRESS_MISSING_MPM_ALERT_KEY @"MPTSuppressMissingMPMAlert"
#ifdef MCCErr
#define MCCErrMacro(macro, frmt, ...) MCCErr(@"[%@ %@] Macro(%@): %@", [self className], NSStringFromSelector(_cmd), macro, [NSString stringWithFormat:frmt, ##__VA_ARGS__])
#else
#define MCCErrMacro(macro, frmt, ...) NSLog(@"[%@ %@] Macro(%@): %@", [self className], NSStringFromSelector(_cmd), macro, [NSString stringWithFormat:frmt, ##__VA_ARGS__])
#endif
#pragma mark Command List
#define MPT_SEND_MAIL_INFO_TEXT @"-mail-info"
#define MPT_SEND_UUID_LIST_TEXT @"-uuid-list"
#define MPT_UNINSTALL_TEXT @"-uninstall"
#define MPT_UPDATE_TEXT @"-update"
#define MPT_CRASH_REPORTS_TEXT @"-send-crash-reports"
#define MPT_UPDATE_CRASH_REPORTS_TEXT @"-update-and-crash-reports"
#define MPT_INSTALL_LAUNCH_AGENT_TEXT @"-add-launch-agent"
#define MPT_REMOVE_LAUNCH_AGENT_TEXT @"-del-launch-agent"
#define MPT_INSTALL_SCRIPT_TEXT @"-install-script"
#define MPT_REMOVE_SCRIPT_TEXT @"-remove-script"
#define MPT_FREQUENCY_OPTION @"-freq"
#define MPT_SPARKLE_DICT_OPTION @"-sparkle-value"
#pragma mark Internal Values
#define MPT_LKS_BUNDLE_START @"com.littleknownsoftware."
#define MPT_BUNDLE_UPDATE_STATUS_NOTIFICATION [MPT_LKS_BUNDLE_START stringByAppendingString:@"MPCBundleUpdateStatusDistNotification"]
#define MPT_BUNDLE_WILL_INSTALL_NOTIFICATION [MPT_LKS_BUNDLE_START stringByAppendingString:@"MPCBundleWillInstallDistNotification"]
#define MPT_BUNDLE_UNINSTALL_STATUS_NOTIFICATION [MPT_LKS_BUNDLE_START stringByAppendingString:@"MPCBundleUninstallStatusDistNotification"]
#define MPT_SYSTEM_INFO_NOTIFICATION [MPT_LKS_BUNDLE_START stringByAppendingString:@"MPTSystemInfoDistNotification"]
#define MPT_UUID_LIST_NOTIFICATION [MPT_LKS_BUNDLE_START stringByAppendingString:@"MPTUUIDListDistNotification"]
#define MPT_LAUNCHD_DONE_NOTIFICATION [MPT_LKS_BUNDLE_START stringByAppendingString:@"MPTUUIDLaunchdDoneNotification"]
#define MPT_TOOL_NAME @"MailPluginTool"
#define MPT_TOOL_IDENTIFIER [MPT_LKS_BUNDLE_START stringByAppendingString:MPT_TOOL_NAME]
#define MPT_MANAGER_IDENTIFIER [MPT_LKS_BUNDLE_START stringByAppendingString:@"MailPluginManager"]
#define MPT_APP_RESOURCES_PATH @"Contents/Resources"
#define MPT_APP_CODE_PATH @"Contents/MacOS"
#define MPT_LAUNCHD_ERROR_DOMAIN_NAME @"LKLaunchAgentConfigurator"
#define MPT_LAUNCHD_BAD_ARGUMENTS_ERROR_CODE 100
#define MPT_LAUNCHD_INSTALL_FAILED_ERROR_CODE 101
#define MPT_LAUNCHD_REMOVE_FAILED_ERROR_CODE 102
#define MPT_MANAGER_APP_NAME @"Mail Plugin Manager.app"
#define MPT_MAIL_MPT_FOLDER_PATH @"Mail/MPT"
#define MPT_PERFORM_ACTION_EXTENSION @"mtperform"
#define MPT_ACTION_KEY @"action"
#define MPT_PLUGIN_PATH_KEY @"plugin-path"
#define MPT_FREQUENCY_KEY @"frequency"
#define MPT_SCRIPT_KEY @"script-path"
#define MPT_RUN_SCRIPT_KEY @"should-run-script"
#define MPT_SCRIPT_DESTINATION_KEY @"script-destination"
#define MPT_SCRIPT_FOLDER_NAME_KEY @"script-folder-name"
#define MPT_OTHER_VALUES_KEY @"other-values"
#define MPT_LAUNCHD_LABEL_KEY @"label"
#define MPT_LAUNCHD_CONFIG_DICT_KEY @"launchd-config"
#define MPT_REPLACE_LAUNCHD_KEY @"replace-launchd-flag"
#define MPT_LAUNCH_ERROR_KEY @"launch-error"
#pragma mark - Reused Macros
#define MPTPerformFolderPath() \
[[[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:MPT_MAIL_MPT_FOLDER_PATH] stringByExpandingTildeInPath]
#define MPTGetLikelyToolPath(mptBundle) MPTGetLikelyToolPathPreferInBundle(mptBundle, YES)
#define MPTGetLikelyToolPathNotInBundle(mptBundle) MPTGetLikelyToolPathPreferInBundle(mptBundle, NO)
#define MPTGetLikelyToolPathPreferInBundle(mptBundle, mptPreferInBundle) \
NSFileManager *mptManager = [NSFileManager defaultManager]; \
NSString *mptPluginToolPath = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:MPT_TOOL_IDENTIFIER]; \
NSString *mptPluginManagerPath = [[NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES) lastObject] stringByAppendingPathComponent:MPT_MANAGER_APP_NAME]; \
{ \
if (![mptManager fileExistsAtPath:mptPluginManagerPath]) { \
mptPluginManagerPath = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:MPT_MANAGER_IDENTIFIER]; \
} \
if ((mptPluginToolPath == nil) || ((mptPluginManagerPath != nil) && ![mptPluginToolPath hasPrefix:mptPluginManagerPath])) { \
/* See if we can get the tool path inside the managerPath */ \
NSString *mptProposedPath = [mptPluginManagerPath stringByAppendingPathComponent:MPT_APP_RESOURCES_PATH]; \
mptProposedPath = [mptProposedPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.app", MPT_TOOL_NAME]]; \
if ((mptProposedPath != nil) && [[NSFileManager defaultManager] fileExistsAtPath:mptProposedPath]) { \
mptPluginToolPath = mptProposedPath; \
} \
} \
if (mptPreferInBundle && [mptManager fileExistsAtPath:[mptBundle bundlePath]]) { \
/* See if we can get the tool path inside the mail bundle's path */ \
NSString *mptProposedPath = [[mptBundle bundlePath] stringByAppendingPathComponent:MPT_APP_RESOURCES_PATH]; \
mptProposedPath = [mptProposedPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.app", MPT_TOOL_NAME]]; \
if ((mptProposedPath != nil) && [mptManager fileExistsAtPath:mptProposedPath]) { \
mptPluginToolPath = mptProposedPath; \
MCCErrMacro(@"MPTGetLikelyToolPath", @"Logging that the likely tool path found is in the bundle: %@", mptPluginToolPath); \
} \
} \
}
#define MPTPresentDialogForMissingPluginManager(mptBundle) \
do { \
NSUserDefaults *missingDefaults = [NSUserDefaults standardUserDefaults]; \
if (![missingDefaults boolForKey:MPT_SUPPRESS_MISSING_MPM_ALERT_KEY]) { \
NSString *missingPluginName = [[mptBundle infoDictionary] valueForKey:(NSString *)kCFBundleNameKey]; \
NSString *missingMessageText = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"The Plugin ‘%@’ is trying to update, however the ‘Mail Plugin Manager’ app is missing.\n\nIt is required by '%@' to look for updates.\n", nil, mptBundle, @"Text telling user the that MPM is not installed"), missingPluginName, missingPluginName]; \
NSString *missingInfoText = NSLocalizedStringFromTableInBundle(@"Click ‘Download’ to download the latest version, then put it into your Applications folder.", nil, mptBundle, @"Text telling user why MPM is useful and how to get it."); \
NSAlert *mptBundleUpToDateAlert = [[NSAlert alloc] init]; \
mptBundleUpToDateAlert.messageText = missingMessageText; \
mptBundleUpToDateAlert.informativeText = missingInfoText; \
mptBundleUpToDateAlert.icon = [[NSWorkspace sharedWorkspace] iconForFile:[mptBundle bundlePath]]; \
mptBundleUpToDateAlert.showsSuppressionButton = YES; \
[mptBundleUpToDateAlert addButtonWithTitle:NSLocalizedStringFromTableInBundle(@"Download", nil, mptBundle, @"Download button")]; \
[mptBundleUpToDateAlert addButtonWithTitle:NSLocalizedStringFromTableInBundle(@"Cancel", nil, mptBundle, @"Cancel button")]; \
MCCErrMacro(@"MPTPresentDialogForMissingPluginManager", @"Mail Plugin Manager or the tool are not available during update."); \
dispatch_async(dispatch_get_main_queue(), ^{ \
NSInteger mptQueueResult = [mptBundleUpToDateAlert runModal]; \
if (mptQueueResult == NSAlertFirstButtonReturn) { \
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://smallcubed.com/download/mpm"]]; \
} \
if ([[mptBundleUpToDateAlert suppressionButton] state] == NSOnState) { \
[missingDefaults setBool:YES forKey:MPT_SUPPRESS_MISSING_MPM_ALERT_KEY]; \
} \
}); \
} \
} while (NO); \
#define MPTLaunchCommandForBundle(mptCommand, mptMailBundle, mptOptionDict) \
{ \
if (mptMailBundle != nil) { \
MPTGetLikelyToolPathNotInBundle(mptMailBundle); \
if (mptPluginToolPath != nil) { \
NSMutableDictionary *mptPerformDict = [NSMutableDictionary dictionaryWithCapacity:3]; \
[mptPerformDict setObject:mptCommand forKey:MPT_ACTION_KEY]; \
[mptPerformDict setObject:[mptMailBundle bundlePath] forKey:MPT_PLUGIN_PATH_KEY]; \
if (mptOptionDict != nil) { \
[mptPerformDict addEntriesFromDictionary:mptOptionDict]; \
} \
NSString *mptPlistPath = MPTPerformFolderPath(); \
BOOL mptIsDir = NO; \
/* Ensure that we have a directory */ \
if (![mptManager fileExistsAtPath:mptPlistPath isDirectory:&mptIsDir] || !mptIsDir) { \
if ([mptManager createDirectoryAtPath:mptPlistPath withIntermediateDirectories:NO attributes:nil error:NULL]) { \
mptIsDir = YES; \
} \
} \
/* If we do, then try to create our file */ \
if (mptIsDir) { \
NSString *mptTempfileName = [[[NSProcessInfo processInfo] globallyUniqueString] stringByAppendingPathExtension:MPT_PERFORM_ACTION_EXTENSION]; \
if (![mptPerformDict writeToFile:[mptPlistPath stringByAppendingPathComponent:mptTempfileName] atomically:NO]) { \
MCCErrMacro(@"MPTLaunchCommandForBundle", @"Unable to write the contents of the action file"); \
} \
} \
else { \
MCCErrMacro(@"MPTLaunchCommandForBundle", @"Unable to create the action file, since the required folder doesn't exist and I can't create it"); \
} \
} \
else { \
MCCErrMacro(@"MPTLaunchCommandForBundle", @"ERROR in MPTLaunchCommandForBundle() Macro: MailPluginTool application wasn't found anywhere"); \
MPTPresentDialogForMissingPluginManager(mptMailBundle); \
} \
} \
else { \
MCCErrMacro(@"MPTLaunchCommandForBundle", @"ERROR in MPTLaunchCommandForBundle() Macro: Cannot pass a nil bundle"); \
} \
}
#define MPTCallToolCommandForBundleWithBlock(mptCommand, mptMailBundle, mptNotificationBlock) \
{ \
NSString *callLikelyToolPath = nil; \
{ \
MPTGetLikelyToolPathNotInBundle(mptMailBundle); \
callLikelyToolPath = mptPluginToolPath; \
} \
if (callLikelyToolPath != nil) { \
if (mptMailBundle != nil) { \
NSString *mptNotificationName = [mptCommand isEqualToString:MPT_SEND_MAIL_INFO_TEXT]?MPT_SYSTEM_INFO_NOTIFICATION:MPT_UUID_LIST_NOTIFICATION; \
/* Set up the notification watch */ \
NSOperationQueue *mptQueue = [[NSOperationQueue alloc] init]; \
__block id mptObserver; \
mptObserver = [[NSDistributedNotificationCenter defaultCenter] addObserverForName:mptNotificationName object:nil queue:mptQueue usingBlock:^(NSNotification *note) { \
/* If this was aimed at us, then perform the block and remove the observer */ \
if ([[note object] isEqualToString:[mptMailBundle bundleIdentifier]]) { \
if (mptNotificationBlock != nil) { \
mptNotificationBlock([note userInfo]); \
} \
[[NSDistributedNotificationCenter defaultCenter] removeObserver:mptObserver]; \
} \
}]; \
/* Then actually launch the app to get the information back */ \
MPTLaunchCommandForBundle(mptCommand, mptMailBundle, @{}); \
MPT_MACRO_RELEASE(mptQueue); \
} \
else { \
MCCErrMacro(@"MPTCallToolCommandForBundleWithBlock", @"ERROR in MPTCallToolCommandForBundleWithBlock() Macro: Cannot pass a nil bundle"); \
} \
} \
else { \
if (mptNotificationBlock != nil) { \
mptNotificationBlock(nil); \
} \
MPTPresentDialogForMissingPluginManager(mptMailBundle); \
} \
}
#pragma mark LaunchD Configuration
#define MPTManageLaunchAgentWithBlock(mptCommand, mptMailBundle, mptOtherDict, mptResultBlock) \
{ \
if (mptMailBundle != nil) { \
MPTGetLikelyToolPathNotInBundle(mptMailBundle); \
if (mptPluginToolPath != nil) { \
NSMutableDictionary *mptPerformDict = [NSMutableDictionary dictionaryWithCapacity:3]; \
[mptPerformDict setObject:mptCommand forKey:MPT_ACTION_KEY]; \
[mptPerformDict setObject:[mptMailBundle bundlePath] forKey:MPT_PLUGIN_PATH_KEY]; \
[mptPerformDict setObject:mptOtherDict forKey:MPT_OTHER_VALUES_KEY]; \
NSString *mptPlistPath = MPTPerformFolderPath(); \
BOOL mptIsDir = NO; \
/* Ensure that we have a directory */ \
if (![mptManager fileExistsAtPath:mptPlistPath isDirectory:&mptIsDir] || !mptIsDir) { \
if ([mptManager createDirectoryAtPath:mptPlistPath withIntermediateDirectories:NO attributes:nil error:NULL]) { \
mptIsDir = YES; \
} \
} \
/* If we do, then try to create our file */ \
if (mptIsDir) { \
if (mptResultBlock != nil) { \
/* Set up the notification watch */ \
NSOperationQueue *mptQueue = [[NSOperationQueue alloc] init]; \
__block id mptObserver; \
mptObserver = [[NSDistributedNotificationCenter defaultCenter] addObserverForName:MPT_LAUNCHD_DONE_NOTIFICATION object:nil queue:mptQueue usingBlock:^(NSNotification *note) { \
/* If this was aimed at us, then perform the block and remove the observer */ \
if ([[note object] isEqualToString:[mptMailBundle bundleIdentifier]]) { \
NSError *mptLaunchError = nil; \
if ([note userInfo] != nil) { \
mptLaunchError = [[note userInfo] valueForKey:MPT_LAUNCH_ERROR_KEY]; \
} \
mptResultBlock(mptLaunchError); \
[[NSDistributedNotificationCenter defaultCenter] removeObserver:mptObserver]; \
} \
}]; \
/* This will release the memeory in non-ARC environments */ \
MPT_MACRO_RELEASE(mptQueue); \
} \
NSString *mptTempfileName = [[[NSProcessInfo processInfo] globallyUniqueString] stringByAppendingPathExtension:MPT_PERFORM_ACTION_EXTENSION]; \
if (![mptPerformDict writeToFile:[mptPlistPath stringByAppendingPathComponent:mptTempfileName] atomically:NO]) { \
MCCErrMacro(@"MPTManageLaunchAgentWithBlock", @"Unable to write the contents of the action file"); \
} \
} \
else { \
MCCErrMacro(@"MPTManageLaunchAgentWithBlock", @"Unable to create the action file, since the required folder doesn't exist and I can't create it"); \
} \
} \
else { \
MCCErrMacro(@"MPTManageLaunchAgentWithBlock", @"ERROR in MPTLaunchCommandForBundle() Macro: MailPluginTool application wasn't found anywhere"); \
MPTPresentDialogForMissingPluginManager(mptMailBundle); \
} \
} \
else { \
MCCErrMacro(@"MPTManageLaunchAgentWithBlock", @"ERROR in MPTLaunchCommandForBundle() Macro: Cannot pass a nil bundle"); \
} \
}
#define MPTInstallLaunchAgent(mptMailBundle, mptAgentConfig, mptReplaceExisting, mptResultBlock) MPTManageLaunchAgentWithBlock(MPT_INSTALL_LAUNCH_AGENT_TEXT, mptMailBundle, ([NSDictionary dictionaryWithObjectsAndKeys:mptAgentConfig, MPT_LAUNCHD_CONFIG_DICT_KEY, [NSNumber numberWithBool:mptReplaceExisting], MPT_REPLACE_LAUNCHD_KEY, nil]), mptResultBlock)
#define MPTRemoveLaunchAgent(mptMailBundle, mptAgentLabel, mptResultBlock) MPTManageLaunchAgentWithBlock(MPT_REMOVE_LAUNCH_AGENT_TEXT, mptMailBundle, ([NSDictionary dictionaryWithObjectsAndKeys:mptAgentLabel, MPT_LAUNCHD_LABEL_KEY, nil]), mptResultBlock)
#pragma mark Update Feedback Macros
#define MPTClosePrefsWindowIfInstalling(mptBundle) \
{ \
MPTGetLikelyToolPath(mptBundle); \
/* Ensure that the update check will happen first */ \
if (mptPluginToolPath != nil) { \
NSOperationQueue *mptQueue = [[NSOperationQueue alloc] init]; \
[mptQueue setName:[MPT_LKS_BUNDLE_START stringByAppendingString:@"BundleWillInstallQueue"]]; \
__block id mptBundleObserver; \
__block id mptBlockSelf = self; \
mptBundleObserver = [[NSDistributedNotificationCenter defaultCenter] addObserverForName:MPT_BUNDLE_WILL_INSTALL_NOTIFICATION object:[mptBundle bundleIdentifier] queue:mptQueue usingBlock:^(NSNotification *note) { \
/* If the preferences are open then close them */ \
NSPreferences *prefs = [NSPreferences sharedPreferences]; \
BOOL panelIsVisible = [[prefs valueForKey:@"preferencesPanel"] isVisible]; \
if (panelIsVisible && (prefs != nil)) { \
dispatch_async(dispatch_get_main_queue(), ^{ \
[prefs performSelector:@selector(cancel:) withObject:mptBlockSelf]; \
}); \
} \
/* Always remove the observer */ \
[[NSDistributedNotificationCenter defaultCenter] removeObserver:mptBundleObserver]; \
}]; \
MPT_MACRO_RELEASE(mptQueue); \
} \
}
#define MPTPresentDialogGeneric(mptBundle, mptSheetWindow, mptMessageDict) \
{ \
NSString *mptPDGMessageText = mptMessageDict[@"message"]; \
NSString *mptPDGInfoText = mptMessageDict[@"info"]; \
if (mptPDGInfoText == nil) { mptPDGInfoText = @""; } \
NSAlert *mptBundleUpToDateAlert = [[NSAlert alloc] init]; \
mptBundleUpToDateAlert.messageText = mptPDGMessageText; \
mptBundleUpToDateAlert.informativeText = mptPDGInfoText; \
[mptBundleUpToDateAlert addButtonWithTitle:NSLocalizedStringFromTableInBundle(@"OK", nil, mptBundle, @"Okay button")]; \
MCCErrMacro(@"MPTPresentDialogGeneric", @"MPT_ERROR:\n\tMessage: %@\n\tInfo: %@", mptPDGMessageText, mptPDGInfoText);\
[mptBundleUpToDateAlert setIcon:[[NSWorkspace sharedWorkspace] iconForFile:[mptBundle bundlePath]]]; \
if (mptSheetWindow != nil) { \
dispatch_async(dispatch_get_main_queue(), ^{ \
[mptBundleUpToDateAlert beginSheetModalForWindow:mptSheetWindow completionHandler:nil]; \
}); \
} \
else { \
if ([NSThread isMainThread]) { \
[mptBundleUpToDateAlert runModal]; \
} \
else { \
dispatch_sync(dispatch_get_main_queue(), ^{ \
[mptBundleUpToDateAlert runModal]; \
}); \
} \
} \
}
#define MPTPresentDialogWhenUninstallFailsUsingWindow(mptBundle, mptSheetWindow, mptFinishBlock) \
{ \
MPTGetLikelyToolPath(mptBundle); \
/* Ensure that the update check will happen first */ \
if (mptPluginToolPath != nil) { \
NSOperationQueue *mptQueue = [[NSOperationQueue alloc] init]; \
[mptQueue setName:[MPT_LKS_BUNDLE_START stringByAppendingString:@"BundleUpdateStatusQueue"]]; \
__block id mptBundleObserver; \
mptBundleObserver = [[NSDistributedNotificationCenter defaultCenter] addObserverForName:MPT_BUNDLE_UNINSTALL_STATUS_NOTIFICATION object:[mptBundle bundleIdentifier] queue:mptQueue usingBlock:^(NSNotification *note) { \
/* Test to see if uninstall could not be done */ \
if (note.userInfo[@"error"]) { \
NSDictionary *localDict = @{@"message": @"There was problem uninstalling.", @"info": note.userInfo[@"error"]}; \
MPTPresentDialogGeneric(mptBundle, mptSheetWindow, localDict); \
} \
if (mptFinishBlock != nil) { \
if ([NSThread isMainThread]) { \
mptFinishBlock(); \
} \
else { \
dispatch_sync(dispatch_get_main_queue(), ^{ \
mptFinishBlock(); \
}); \
} \
} \
/* Always remove the observer */ \
[[NSDistributedNotificationCenter defaultCenter] removeObserver:mptBundleObserver]; \
}]; \
MPT_MACRO_RELEASE(mptQueue); \
} \
else { \
/* If there is no plugin tool, just call the block if it is not nil */ \
if (mptFinishBlock != nil) { \
if ([NSThread isMainThread]) { \
mptFinishBlock(); \
} \
else { \
dispatch_sync(dispatch_get_main_queue(), ^{ \
mptFinishBlock(); \
}); \
} \
} \
} \
}
#define MPTPresentDialogWhenUpToDateUsingWindow(mptBundle, mptSheetWindow, mptFinishBlock) \
{ \
MPTGetLikelyToolPath(mptBundle); \
/* Ensure that the update check will happen first */ \
if (mptPluginToolPath != nil) { \
NSOperationQueue *mptQueue = [[NSOperationQueue alloc] init]; \
[mptQueue setName:[MPT_LKS_BUNDLE_START stringByAppendingString:@"BundleUpdateStatusQueue"]]; \
__block id mptBundleObserver; \
mptBundleObserver = [[NSDistributedNotificationCenter defaultCenter] addObserverForName:MPT_BUNDLE_UPDATE_STATUS_NOTIFICATION object:[mptBundle bundleIdentifier] queue:mptQueue usingBlock:^(NSNotification *note) { \
/* Test to see if the plugin is up to date */ \
if ([note.userInfo[@"uptodate"] boolValue]) { \
NSString *messageText = [NSString stringWithFormat:NSLocalizedStringFromTableInBundle(@"You have the most recent version of %@.", nil, mptBundle, @"Text telling user the plugin is up to date"), mptBundle.infoDictionary[(NSString *)kCFBundleNameKey]]; \
NSDictionary *localDict = @{@"message": messageText}; \
MPTPresentDialogGeneric(mptBundle, mptSheetWindow, localDict); \
} \
/* Test to see if the plugin could not be updated */ \
else if (note.userInfo[@"error"]) { \
NSDictionary *localDict = @{@"message": @"There was an issue while checking for the update.", @"info": note.userInfo[@"error"]}; \
MPTPresentDialogGeneric(mptBundle, mptSheetWindow, localDict); \
} \
if (mptFinishBlock != nil) { \
if ([NSThread isMainThread]) { \
mptFinishBlock(); \
} \
else { \
dispatch_sync(dispatch_get_main_queue(), ^{ \
mptFinishBlock(); \
}); \
} \
} \
/* Always remove the observer */ \
[[NSDistributedNotificationCenter defaultCenter] removeObserver:mptBundleObserver]; \
}]; \
MPT_MACRO_RELEASE(mptQueue); \
} \
else { \
/* If there is no plugin tool, just call the block if it is not nil */ \
if (mptFinishBlock != nil) { \
if ([NSThread isMainThread]) { \
mptFinishBlock(); \
} \
else { \
dispatch_sync(dispatch_get_main_queue(), ^{ \
mptFinishBlock(); \
}); \
} \
} \
} \
}
#define MPTRunHelperWithErrorCompletion(mptScriptURL, mptScriptArguments, mptErrorBlock) \
do { \
NSError *mptScriptError = nil; \
NSUserUnixTask *mptScriptTask = [[NSUserUnixTask alloc] initWithURL:mptScriptURL error:&mptScriptError]; \
[mptScriptTask executeWithArguments:mptScriptArguments completionHandler:^(NSError *mptExecuteError) { \
if (mptExecuteError) { \
if ([NSThread isMainThread]) { \
mptErrorBlock(mptExecuteError); \
} \
else { \
dispatch_sync(dispatch_get_main_queue(), ^{ \
mptErrorBlock(mptExecuteError); \
}); \
} \
MCCErrMacro(@"MPTRunHelperWithErrorCompletion", @"Error: %@", mptExecuteError); \
} \
}]; \
} while (NO)
#pragma mark - Plugin Macros
#pragma mark UpToDate Dialog
#define MPTPresentModalDialogWhenUpToDate(mptBundle) MPTPresentDialogWhenUpToDateUsingWindow(mptBundle, nil, nil);
#define MPTPresentModalDialogWhenUpToDateWithBlock(mptBundle, mptFinishBlock) MPTPresentDialogWhenUpToDateUsingWindow(mptBundle, nil, mptFinishBlock);
#pragma mark Launch and Forget
#define MPTUninstallForBundle(mptMailBundle) MPTLaunchCommandForBundle(MPT_UNINSTALL_TEXT, mptMailBundle, [NSDictionary dictionary]);
#define MPTCheckForUpdatesForBundle(mptMailBundle) MPTLaunchCommandForBundle(MPT_UPDATE_TEXT, mptMailBundle, [NSDictionary dictionary]);
#define MPTCheckForUpdatesForBundleNow(mptMailBundle) MPTLaunchCommandForBundle(MPT_UPDATE_TEXT, mptMailBundle, (@{MPT_FREQUENCY_KEY: @"now"}));
#define MPTSendCrashReportsForBundle(mptMailBundle) MPTLaunchCommandForBundle(MPT_CRASH_REPORTS_TEXT, mptMailBundle, [NSDictionary dictionary]);
#define MPTUpdateAndSendReportsForBundle(mptMailBundle) MPTLaunchCommandForBundle(MPT_UPDATE_CRASH_REPORTS_TEXT, mptMailBundle, [NSDictionary dictionary]);
#define MPTUpdateAndSendReportsForBundleNow(mptMailBundle) MPTLaunchCommandForBundle(MPT_UPDATE_CRASH_REPORTS_TEXT, mptMailBundle, (@{MPT_FREQUENCY_KEY: @"now"}));
#define MPTCheckForUpdatesForBundleWithFrequency(mptMailBundle, mptFreq) MPTLaunchCommandForBundle(MPT_UPDATE_TEXT, mptMailBundle, (@{MPT_FREQUENCY_KEY: mptFreq}));
#define MPTSendCrashReportsForBundleWithFrequency(mptMailBundle, mptFreq) MPTLaunchCommandForBundle(MPT_CRASH_REPORTS_TEXT, mptMailBundle, (@{MPT_FREQUENCY_KEY: mptFreq}));
#define MPTUpdateAndSendReportsForBundleWithFrequency(mptMailBundle, mptFreq) MPTLaunchCommandForBundle(MPT_UPDATE_CRASH_REPORTS_TEXT, mptMailBundle, (@{MPT_FREQUENCY_KEY: mptFreq}));
#define MPTCheckForUpdatesForBundleSparkleDict(mptMailBundle, sparkleDict) MPTLaunchCommandForBundle(MPT_UPDATE_TEXT, mptMailBundle, @{MPT_SPARKLE_DICT_OPTION: sparkleDict});
#define MPTCheckForUpdatesForBundleNowSparkleDict(mptMailBundle, sparkleDict) MPTLaunchCommandForBundle(MPT_UPDATE_TEXT, mptMailBundle, (@{MPT_FREQUENCY_KEY: @"now", MPT_SPARKLE_DICT_OPTION: sparkleDict}));
#define MPTUpdateAndSendReportsForBundleSparkleDict(mptMailBundle, sparkleDict) MPTLaunchCommandForBundle(MPT_UPDATE_CRASH_REPORTS_TEXT, mptMailBundle, @{MPT_SPARKLE_DICT_OPTION: sparkleDict});
#define MPTUpdateAndSendReportsForBundleNowSparkleDict(mptMailBundle, sparkleDict) MPTLaunchCommandForBundle(MPT_UPDATE_CRASH_REPORTS_TEXT, mptMailBundle, (@{MPT_FREQUENCY_KEY: @"now", MPT_SPARKLE_DICT_OPTION: sparkleDict}));
#define MPTCheckForUpdatesForBundleWithFrequencySparkleDict(mptMailBundle, mptFreq, sparkleDict) MPTLaunchCommandForBundle(MPT_UPDATE_TEXT, mptMailBundle, (@{MPT_FREQUENCY_KEY: mptFreq, MPT_SPARKLE_DICT_OPTION: sparkleDict}));
#define MPTUpdateAndSendReportsForBundleWithFrequencySparkleDict(mptMailBundle, mptFreq, sparkleDict) MPTLaunchCommandForBundle(MPT_UPDATE_CRASH_REPORTS_TEXT, mptMailBundle, (@{MPT_FREQUENCY_KEY: mptFreq, MPT_SPARKLE_DICT_OPTION: sparkleDict}));
#define MPTInstallScript(mptMailBundle, mptScriptPath, mptFolderName) MPTLaunchCommandForBundle(MPT_INSTALL_SCRIPT_TEXT, mptMailBundle, (@{MPT_OTHER_VALUES_KEY: (@{MPT_SCRIPT_KEY: mptScriptPath, MPT_RUN_SCRIPT_KEY: @NO, MPT_SCRIPT_FOLDER_NAME_KEY: mptFolderName})}));
#define MPTInstallScriptAndRun(mptMailBundle, mptScriptPath, mptFolderName) MPTLaunchCommandForBundle(MPT_INSTALL_SCRIPT_TEXT, mptMailBundle, (@{MPT_OTHER_VALUES_KEY: (@{MPT_SCRIPT_KEY: mptScriptPath, MPT_RUN_SCRIPT_KEY: @YES, MPT_SCRIPT_FOLDER_NAME_KEY: mptFolderName})}));
#define MPTInstallScriptTo(mptMailBundle, mptScriptPath, mptDestPath) MPTLaunchCommandForBundle(MPT_INSTALL_SCRIPT_TEXT, mptMailBundle, (@{MPT_OTHER_VALUES_KEY: (@{MPT_SCRIPT_KEY: mptScriptPath, MPT_RUN_SCRIPT_KEY: @NO, MPT_SCRIPT_DESTINATION_KEY: mptDestPath})}));
#define MPTInstallScriptToAndRun(mptMailBundle, mptScriptPath, mptDestPath) MPTLaunchCommandForBundle(MPT_INSTALL_SCRIPT_TEXT, mptMailBundle, (@{MPT_OTHER_VALUES_KEY: (@{MPT_SCRIPT_KEY: mptScriptPath, MPT_RUN_SCRIPT_KEY: @YES, MPT_SCRIPT_DESTINATION_KEY: mptDestPath})}));
#define MPTRemoveScript(mptMailBundle, mptScriptPath) MPTLaunchCommandForBundle(MPT_REMOVE_SCRIPT_TEXT, mptMailBundle, (@{MPT_OTHER_VALUES_KEY: (@{MPT_SCRIPT_KEY: mptScriptPath})}));
#pragma mark Notification Block
#define MPTMailInformationForBundleWithBlock(mptMailBundle, mptNotificationBlock) MPTCallToolCommandForBundleWithBlock(MPT_SEND_MAIL_INFO_TEXT, mptMailBundle, mptNotificationBlock);
#define MPTUUIDListForBundleWithBlock(mptMailBundle, mptNotificationBlock) MPTCallToolCommandForBundleWithBlock(MPT_SEND_UUID_LIST_TEXT, mptMailBundle, mptNotificationBlock);