-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathSimplePluginBundle.m
204 lines (162 loc) · 6.86 KB
/
SimplePluginBundle.m
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
//
// SimplePluginBundle.m
// SimplePlugin
//
// Created by Sergey Vinogradov on 30.10.13.
//
//
#import "SimplePluginBundle.h"
#import "SimplePluginPreferences.h"
#import "NSToolbar+SimplePlugin.h"
#import "MVMailBundle.h"
#import <objc/message.h>
#import <objc/runtime.h>
#import "JRLPSwizzle.h"
@implementation SimplePluginBundle
#pragma mark - Init, dealloc etc.
+ (void)initialize {
if(self != [SimplePluginBundle class])
return;
Class mvMailBundleClass = NSClassFromString(@"MVMailBundle");
// If this class is not available that means Mail.app
// doesn't allow plugins anymore. Fingers crossed that this
// never happens!
if(!mvMailBundleClass)
return;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
class_setSuperclass([self class], mvMailBundleClass);
#pragma GCC diagnostic pop
// Initialize the bundle by swizzling methods, loading keys, ...
SimplePluginBundle *instance = [SimplePluginBundle sharedInstance];
//swizzle, old style
{
const NSString *swizzleClassName = @"SimplePluginClass";
NSArray *swizzleMap = [NSArray arrayWithObjects:
//preferences
[NSDictionary dictionaryWithObjectsAndKeys:
@"NSPreferences", @"class",
[NSArray arrayWithObjects:
@"sharedPreferences",
@"windowWillResize:toSize:",
@"toolbarItemClicked:",
@"showPreferencesPanelForOwner:",
nil], @"selectors", nil],
//toolbar
[NSDictionary dictionaryWithObjectsAndKeys:
@"NSToolbar",@"class",
[NSArray arrayWithObjects:
@"configureToolbarItems",
nil],@"selectors",nil],
nil];
NSError *error = nil;
for(NSDictionary *swizzleInfo in swizzleMap) {
Class mailClass = NSClassFromString([swizzleInfo objectForKey:@"class"]);
if([swizzleInfo objectForKey:swizzleClassName]) {
Class PowerbotMailClass = NSClassFromString([swizzleInfo objectForKey:swizzleClassName]);
if(!mailClass) {
NSLog(@"WARNING: Class %@ doesn't exist. Powerbot might behave weirdly!", [swizzleInfo objectForKey:@"class"]);
continue;
}
if(!PowerbotMailClass) {
NSLog(@"WARNING: Class %@ doesn't exist. Powerbot might behave weirdly!", [swizzleInfo objectForKey:@"PowerbotClass"]);
continue;
}
[mailClass jrlp_addMethodsFromClass:PowerbotMailClass error:&error];
if(error)
NSLog(@"[DEBUG] %s Error: %@", __PRETTY_FUNCTION__, error);
error = nil;
}
for(NSString *method in [swizzleInfo objectForKey:@"selectors"]) {
error = nil;
NSString *PowerbotMethod = [NSString stringWithFormat:@"SP%@%@",
[[method substringToIndex:1] uppercaseString],
[method substringFromIndex:1]];
[mailClass jrlp_swizzleMethod:NSSelectorFromString(method)
withMethod:NSSelectorFromString(PowerbotMethod)
error:&error];
if(error) {
error = nil;
// Try swizzling as class method on error.
[mailClass jrlp_swizzleClassMethod:NSSelectorFromString(method)
withClassMethod:NSSelectorFromString(PowerbotMethod)
error:&error];
if(error)
NSLog(@"[DEBUG] %s Class Error: %@", __PRETTY_FUNCTION__, error);
}
}
}
}
[[((MVMailBundle *)self) class] registerBundle]; // To force registering composeAccessoryView and preferences
}
- (id)init {
if (self = [super init]) {
NSLog(@"Loaded SimplePlugin %@", [self version]);
// Load all necessary images.
[self _loadImages];
// Inject the plugin code.
#warning TODO1
// [SimplePluginInjector injectUsingMethodPrefix:GPGMailSwizzledMethodPrefix];
}
return self;
}
- (void)dealloc {
}
- (void)_loadImages {
/**
* Loads all images which are used in the User interface.
*/
// We need to load images and name them, because all images are searched by their name; as they are not located in the main bundle,
// +[NSImage imageNamed:] does not find them.
NSBundle *myBundle = [SimplePluginBundle bundle];
[(NSImage *)[[NSImage alloc] initByReferencingFile:[myBundle pathForImageResource:@"teapotPreferences"]] setName:@"SimplePluginPreferences"];
NSArray *bundleImageNames = @[@"GreenDot",
@"YellowDot",
@"RedDot"];
NSMutableArray *bundleImages = [[NSMutableArray alloc] initWithCapacity:[bundleImageNames count]];
for (NSString *name in bundleImageNames) {
NSImage *image = [[NSImage alloc] initByReferencingFile:[myBundle pathForImageResource:name]];
// Shoud an image not exist, log a warning, but don't crash because of inserting
// nil!
if(!image) {
NSLog(@"GPGMail: Image %@ not found in bundle resources.", name);
continue;
}
[image setName:name];
[bundleImages addObject:image];
}
_bundleImages = bundleImages;
}
#pragma mark - General Infos
+ (NSBundle *)bundle {
static NSBundle *bundle;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
bundle = [NSBundle bundleForClass:[SimplePluginBundle class]];
});
return bundle;
}
- (NSString *)version {
return [[SimplePluginBundle bundle] infoDictionary][@"CFBundleShortVersionString"];
}
+ (NSString *)bundleVersion {
/**
Returns the version of the bundle as string.
*/
return [[[SimplePluginBundle bundle] infoDictionary] valueForKey:@"CFBundleVersion"];
}
+ (NSNumber *)bundleBuildNumber {
return [[[SimplePluginBundle bundle] infoDictionary] valueForKey:@"BuildNumber"];
}
#pragma mark - Preferences
+ (BOOL)hasPreferencesPanel {
// LEOPARD Invoked on +initialize. Else, invoked from +registerBundle.
return YES;
}
+ (NSString *)preferencesOwnerClassName {
return NSStringFromClass([SimplePluginPreferences class]);
}
+ (NSString *)preferencesPanelName {
return @"Simple plugin preferences";
}
@end