adium 5397:acd4ea48abd0: Implement basic support for xtra plugin...
commits at adium.im
commits at adium.im
Wed Mar 20 13:51:26 UTC 2013
details: http://hg.adium.im/adium/rev/acd4ea48abd0
revision: 5397:acd4ea48abd0
branch: JSXtras
author: Thijs Alkemade <me at thijsalkema.de>
date: Wed Mar 20 14:50:47 2013 +0100
Implement basic support for xtra plugins written in JavaScript. These get injected into every message view on load.
This should make it easier to write plugins that add features to the message view that are more involved than normal content filters.
diffs (219 lines):
diff -r 2219add65094 -r acd4ea48abd0 Frameworks/Adium Framework/Source/AICorePluginLoader.h
--- a/Frameworks/Adium Framework/Source/AICorePluginLoader.h Wed Mar 20 01:02:22 2013 +0100
+++ b/Frameworks/Adium Framework/Source/AICorePluginLoader.h Wed Mar 20 14:50:47 2013 +0100
@@ -24,6 +24,7 @@
+ (void)loadPluginAtPath:(NSString *)pluginName confirmLoading:(BOOL)confirmLoading pluginArray:(NSMutableArray *)pluginArray;
- (id <AIPlugin>)pluginWithClassName:(NSString *)className;
++ (NSArray *)jsPlugins;
+ (void)moveXtra:(NSString *)pluginPath toDisabledFolder:(BOOL)disable;
@end
diff -r 2219add65094 -r acd4ea48abd0 Frameworks/Adium Framework/Source/AICorePluginLoader.m
--- a/Frameworks/Adium Framework/Source/AICorePluginLoader.m Wed Mar 20 01:02:22 2013 +0100
+++ b/Frameworks/Adium Framework/Source/AICorePluginLoader.m Wed Mar 20 14:50:47 2013 +0100
@@ -35,13 +35,17 @@
#define CONFIRMED_PLUGINS @"Confirmed Plugins"
#define CONFIRMED_PLUGINS_VERSION @"Confirmed Plugin Version"
+#define IS_JS_PLUGIN @"AIJavaScriptPlugin"
+#define JS_PLUGIN_FILENAME @"AIJavaScriptPluginFileName"
+
//#define PLUGIN_LOAD_TIMING
#ifdef PLUGIN_LOAD_TIMING
NSTimeInterval aggregatePluginLoadingTime = 0.0;
#endif
static NSMutableDictionary *pluginDict = nil;
-static NSMutableSet *pluginBundleIdentifiers = nil;
+static NSMutableSet *pluginBundleIdentifiers = nil;
+static NSMutableDictionary *jsPluginDict = nil;
static NSMutableArray *deferredPluginPaths = nil;
@interface AICorePluginLoader ()
@@ -60,6 +64,7 @@
if (self == [AICorePluginLoader class]) {
pluginDict = [[NSMutableDictionary alloc] init];
pluginBundleIdentifiers = [[NSMutableSet alloc] init];
+ jsPluginDict = [[NSMutableDictionary alloc] init];
}
}
@@ -205,25 +210,33 @@
return;
}
- Class principalClass = [pluginBundle principalClass];
- if (principalClass) {
- plugin = [[principalClass alloc] init];
+ if ([[pluginBundle.infoDictionary valueForKey:IS_JS_PLUGIN] boolValue]) {
+ NSString *identifier = [pluginBundle bundleIdentifier];
+ NSString *fileName = [pluginBundle.infoDictionary valueForKey:JS_PLUGIN_FILENAME];
+ NSString *path = [[pluginBundle resourcePath] stringByAppendingPathComponent:fileName];
+
+ [jsPluginDict setObject:path forKey:identifier];
} else {
- NSLog(@"Failed to obtain principal class from plugin \"%@\" (\"%@\")! infoDictionary: %@",
- [pluginPath lastPathComponent],
- pluginPath,
- [pluginBundle infoDictionary]);
- }
-
- if (plugin) {
- [plugin installPlugin];
- [inPluginArray addObject:plugin];
- [pluginDict setObject:plugin forKey:NSStringFromClass(principalClass)];
- [pluginBundleIdentifiers addObject:[pluginBundle bundleIdentifier]];
-
- [plugin release];
- } else {
- NSLog(@"Failed to initialize Plugin \"%@\" (\"%@\")!",[pluginPath lastPathComponent],pluginPath);
+ Class principalClass = [pluginBundle principalClass];
+ if (principalClass) {
+ plugin = [[principalClass alloc] init];
+ } else {
+ NSLog(@"Failed to obtain principal class from plugin \"%@\" (\"%@\")! infoDictionary: %@",
+ [pluginPath lastPathComponent],
+ pluginPath,
+ [pluginBundle infoDictionary]);
+ }
+
+ if (plugin) {
+ [plugin installPlugin];
+ [inPluginArray addObject:plugin];
+ [pluginDict setObject:plugin forKey:NSStringFromClass(principalClass)];
+ [pluginBundleIdentifiers addObject:[pluginBundle bundleIdentifier]];
+
+ [plugin release];
+ } else {
+ NSLog(@"Failed to initialize Plugin \"%@\" (\"%@\")!",[pluginPath lastPathComponent],pluginPath);
+ }
}
} else {
NSLog(@"Failed to open Plugin \"%@\"!",[pluginPath lastPathComponent]);
@@ -293,7 +306,7 @@
NSBundle *pluginBundle = [NSBundle bundleWithPath:pluginPath];
NSArray *pluginArchs = [pluginBundle executableArchitectures];
- return [pluginArchs containsObject:[NSNumber numberWithInteger:CURRENT_BUNDLE_ARCH]];
+ return [[pluginBundle.infoDictionary valueForKey:IS_JS_PLUGIN] boolValue] || [pluginArchs containsObject:[NSNumber numberWithInteger:CURRENT_BUNDLE_ARCH]];
}
+ (BOOL)confirmMinimumVersionMetForPluginAtPath:(NSString *)pluginPath
@@ -372,4 +385,8 @@
return [pluginDict objectForKey:className];
}
++ (NSArray *)jsPlugins {
+ return [jsPluginDict allValues];
+}
+
@end
diff -r 2219add65094 -r acd4ea48abd0 Plugins/WebKit Message View/AIAdiumURLProtocol.m
--- a/Plugins/WebKit Message View/AIAdiumURLProtocol.m Wed Mar 20 01:02:22 2013 +0100
+++ b/Plugins/WebKit Message View/AIAdiumURLProtocol.m Wed Mar 20 14:50:47 2013 +0100
@@ -27,4 +27,19 @@
return [[[request URL] scheme] isEqualToString:@"adium"];
}
++ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
+{
+ return request;
+}
+
+- (void)startLoading
+{
+ [self.client URLProtocolDidFinishLoading:self];
+}
+
+- (void)stopLoading
+{
+
+}
+
@end
diff -r 2219add65094 -r acd4ea48abd0 Plugins/WebKit Message View/AIWebKitDelegate.m
--- a/Plugins/WebKit Message View/AIWebKitDelegate.m Wed Mar 20 01:02:22 2013 +0100
+++ b/Plugins/WebKit Message View/AIWebKitDelegate.m Wed Mar 20 14:50:47 2013 +0100
@@ -239,11 +239,27 @@
- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
{
NSString *scheme = request.URL.scheme;
+ NSString *host = request.URL.host;
- if (!([scheme isEqualToString:@"adium"] || [scheme isEqualToString:@"file"])) {
- return nil;
+ // Stupid scripts use "//example.com/" as a trick to load either https or http depending on the origin.
+ // This doesn't work for our webview of course, as those live in adium://. So we're going to prepend "https".
+ if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"]
+ && host && !([host isEqualToString:@""] || [host isEqualToString:@"localhost"]) && ![host hasSuffix:@".adiummessagestyle"]) {
+ NSMutableURLRequest *newRequest = [[request mutableCopy] autorelease];
+ NSMutableString *URLString = [[request.URL absoluteString] mutableCopy];
+
+ [URLString replaceCharactersInRange:NSMakeRange(0, scheme.length) withString:@"https"];
+
+ NSURL *newURL = [NSURL URLWithString:URLString];
+
+ scheme = @"https";
+ [newRequest setURL:newURL];
+ request = newRequest;
}
+ // TODO: check whitelist
+
+ AILogWithSignature(@"%@", request);
return request;
}
@end
diff -r 2219add65094 -r acd4ea48abd0 Plugins/WebKit Message View/AIWebKitMessageViewController.m
--- a/Plugins/WebKit Message View/AIWebKitMessageViewController.m Wed Mar 20 01:02:22 2013 +0100
+++ b/Plugins/WebKit Message View/AIWebKitMessageViewController.m Wed Mar 20 14:50:47 2013 +0100
@@ -21,6 +21,7 @@
#import "AIWebKitDelegate.h"
#import "ESFileTransferRequestPromptController.h"
#import "ESWebView.h"
+#import "AICorePluginLoader.h"
#import <Adium/AIContactControllerProtocol.h>
#import <Adium/AIContentControllerProtocol.h>
#import <Adium/AIMenuControllerProtocol.h>
@@ -512,7 +513,7 @@
// We need to pass a local URL to allow LocalStorage from the WebView.
// The hostname-part determines the namespace, which we seperate per style.
// The path-part may not end in a /, as directories don't get local permissions.
- NSURL *baseURL = [NSURL URLWithString:[NSString stringWithFormat:@"adium://%@/adium", [messageStyle.bundle bundleIdentifier]]];
+ NSURL *baseURL = [NSURL URLWithString:[NSString stringWithFormat:@"adium://%@.adiummessagestyle/adium", [messageStyle.bundle bundleIdentifier]]];
[[webView mainFrame] loadHTMLString:[messageStyle baseTemplateForChat:chat] baseURL:baseURL];
if(chat.isGroupChat && ((AIGroupChat *)chat).supportsTopic) {
@@ -818,6 +819,7 @@
- (void)webViewIsReady{
webViewIsReady = YES;
+ [self loadPlugins];
[self setupMarkedScroller];
[self setIsGroupChat:chat.isGroupChat];
[self processQueuedContent];
@@ -1507,6 +1509,23 @@
}
}
+- (void)loadPlugins
+{
+ NSArray *jsPlugins = [AICorePluginLoader jsPlugins];
+
+ for (NSString *jsPluginPath in jsPlugins) {
+ NSURL *jsPluginURL = [NSURL fileURLWithPath:jsPluginPath];
+ DOMDocument *domDocument = [webView mainFrameDocument];
+ DOMElement *scriptElement = [domDocument createElement:@"script"];
+
+ [scriptElement setAttribute:@"type" value:@"text/javascript"];
+ [scriptElement setAttribute:@"src" value:[jsPluginURL absoluteString]];
+
+ DOMElement *headElement = (DOMElement*)[[domDocument getElementsByTagName:@"head"] item:0];
+ [headElement appendChild:scriptElement];
+ }
+}
+
#pragma mark Marked Scroller
- (JVMarkedScroller *)markedScroller
{
More information about the commits
mailing list