PK k> chrome/PK
N[>+~ chrome.manifestcontent xbmciplayersender chrome/content/
overlay chrome://browser/content/browser.xul chrome://xbmciplayersender/content/Overlay.xul
override chrome://xbmciplayersender/content/Options.xul chrome://xbmciplayersender/content/FennecOptions.xul application={a23983c0-fd0e-11dc-95ff-0800200c9a66}
override chrome://xbmciplayersender/content/Overlay.xul chrome://xbmciplayersender/content/FennecOverlay.xul application={a23983c0-fd0e-11dc-95ff-0800200c9a66}
skin xbmciplayersender classic/1.0 chrome/skin/
component {4933fdae-a715-4a05-b81e-ef5bcd13c800} components/xbmciplayerComp.js
contract @awilco.net/xbmciplayersender;1 {4933fdae-a715-4a05-b81e-ef5bcd13c800}
category profile-after-change iplayerUA @awilco.net/xbmciplayersender;1
locale xbmciplayersender en-US chrome/locale/en-US/
PK k> chrome/content/PK
M[><~8 chrome/content/content.jsvar xbmciplayersender_gmCompiler={
log: function(txt)
{
sendAsyncMessage("XBMCSender:Dump", { 'text' : txt });
},
getUrlContents: function(aUrl){
var ioService=Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var scriptableStream=Components
.classes["@mozilla.org/scriptableinputstream;1"]
.getService(Components.interfaces.nsIScriptableInputStream);
var unicodeConverter=Components
.classes["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
unicodeConverter.charset="UTF-8";
var channel=ioService.newChannel(aUrl, null, null);
var input=channel.open();
scriptableStream.init(input);
var str=scriptableStream.read(input.available());
scriptableStream.close();
input.close();
try {
return unicodeConverter.ConvertToUnicode(str);
} catch (e) {
return str;
}
},
isGreasemonkeyable: function(url) {
var scheme=Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.extractScheme(url);
dump(scheme);
return (
(scheme == "http" || scheme == "https" || scheme == "file") &&
!/hiddenWindow\.html$/.test(url)
);
},
contentLoaded: function(e)
{
var unsafeWin=content;
if (unsafeWin.wrappedJSObject) unsafeWin=unsafeWin.wrappedJSObject;
var unsafeLoc=new XPCNativeWrapper(unsafeWin, "location").location;
var href=new XPCNativeWrapper(unsafeLoc, "href").href;
if (
xbmciplayersender_gmCompiler.isGreasemonkeyable(href)
&& true
&& true
/* check for bbc iPLayer website */
) {
var match = /bbc\.co\.uk\/.*iplayer\//.exec(href);
if (match)
{
sendAsyncMessage("XBMCSender:Dump", { text : 'Is iPlayer' });
var script=xbmciplayersender_gmCompiler.getUrlContents(
'chrome://xbmciplayersender/content/xbmciplayersender.js'
);
xbmciplayersender_gmCompiler.injectScript(script, href, unsafeWin);
}
}
},
addStyle:function(doc, css) {
var head, style;
head = doc.getElementsByTagName('head')[0];
if (!head) { return; }
style = doc.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
},
injectScript: function(script, url, unsafeContentWin) {
var sandbox, script, logger, storage, xmlhttpRequester;
var safeWin=new XPCNativeWrapper(unsafeContentWin);
sandbox=new Components.utils.Sandbox(safeWin);
var storage=new xbmciplayersender_ScriptStorage();
xmlhttpRequester=new xbmciplayersender_xmlhttpRequester(
unsafeContentWin, content//appSvc.hiddenDOMWindow
);
sandbox.window=safeWin;
sandbox.document=sandbox.window.document;
sandbox.unsafeWindow=unsafeContentWin;
// patch missing properties on xpcnw
sandbox.XPathResult=Components.interfaces.nsIDOMXPathResult;
// add our own APIs
sandbox.GM_addStyle=function(css) { xbmciplayersender_gmCompiler.addStyle(sandbox.document, css) };
sandbox.GM_setValue=xbmciplayersender_gmCompiler.hitch(storage, "setValue");
sandbox.GM_getValue=xbmciplayersender_gmCompiler.hitch(storage, "getValue");
//sandbox.GM_openInTab=xbmciplayersender_gmCompiler.hitch(this, "openInTab", unsafeContentWin);
sandbox.GM_xmlhttpRequest=xbmciplayersender_gmCompiler.hitch(
xmlhttpRequester, "contentStartRequest"
);
//unsupported
sandbox.GM_registerMenuCommand=function(){};
sandbox.GM_log=xbmciplayersender_gmCompiler.hitch(xbmciplayersender_gmCompiler,"log");
sandbox.GM_getResourceURL=function(){};
sandbox.GM_getResourceText=function(){};
sandbox.GM_openInTab=function(){};
sandbox.__proto__=sandbox.window;
try {
this.evalInSandbox(
"(function(){"+script+"})()",
url,
sandbox);
} catch (e) {
var e2=new Error(typeof e=="string" ? e : e.message);
e2.fileName=script.filename;
e2.lineNumber=0;
//GM_logError(e2);
content.alert(e2);
}
},
evalInSandbox: function(code, codebase, sandbox) {
if (Components.utils && Components.utils.Sandbox) {
// DP beta+
Components.utils.evalInSandbox(code, sandbox);
} else if (Components.utils && Components.utils.evalInSandbox) {
// DP alphas
Components.utils.evalInSandbox(code, codebase, sandbox);
} else if (Sandbox) {
// 1.0.x
evalInSandbox(code, sandbox, codebase);
} else {
throw new Error("Could not create sandbox.");
}
},
apiLeakCheck: function(allowedCaller) {
var stack=Components.stack;
var leaked=false;
do {
if (2==stack.language) {
if ('chrome'!=stack.filename.substr(0, 6) &&
allowedCaller!=stack.filename
) {
leaked=true;
break;
}
}
stack=stack.caller;
} while (stack);
return leaked;
},
hitch: function(obj, meth) {
if (!obj[meth]) {
throw "method '" + meth + "' does not exist on object '" + obj + "'";
}
var hitchCaller=Components.stack.caller.filename;
var staticArgs = Array.prototype.splice.call(arguments, 2, arguments.length);
return function() {
if (xbmciplayersender_gmCompiler.apiLeakCheck(hitchCaller)) {
return;
}
// make a copy of staticArgs (don't modify it because it gets reused for
// every invocation).
var args = staticArgs.concat();
// add all the new arguments
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
// invoke the original function with the correct this obj and the combined
// list of static and dynamic arguments.
return obj[meth].apply(obj, args);
};
},
}//object xbmciplayersender_gmCompiler
function xbmciplayersender_ScriptStorage() {
this.prefMan=new xbmciplayersender_PrefManager();
}
xbmciplayersender_ScriptStorage.prototype.setValue = function(name, val) {
this.prefMan.setValue(name, val);
}
xbmciplayersender_ScriptStorage.prototype.getValue = function(name, defVal) {
return this.prefMan.getValue(name, defVal);
}
sendAsyncMessage("XBMCSender:Dump", { text : 'In Content Process' });
addEventListener("DOMContentLoaded", xbmciplayersender_gmCompiler.contentLoaded, false);
PK
M[> chrome/content/contents.rdf
chrome://uacontrol/content/uacontrolOverlay.xul
chrome://uacontrol/content/uacontrolOverlay.xul
PK
M[>! chrome/content/FennecOptions.xul
Enable XBMC iPlayer sender
The name or IP of your xbmc computer
The name or IP of your xbmc computer
The username for logging into XBMC
The password fpr logging into XBMC
PK
M[>ż chrome/content/FennecOverlay.xul
PK
M[>dm m chrome/content/Options.cssdialog { width: 45em; padding-top: 0px; padding-right: 0px; padding-left: 0px; }
label
{
width: 100px;
}PK
l>wE
chrome/content/Options.xul
PK
M[>9 chrome/content/Overlay.xul
PK
M[>^#2~
~
chrome/content/prefman.ff.jsfunction xbmciplayersender_PrefManager() {
var startPoint="extensions.xbmciplayersender.";
var pref=Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).
getBranch(startPoint);
var observers={};
// whether a preference exists
this.exists=function(prefName) {
return pref.getPrefType(prefName) != 0;
}
// returns the named preference, or defaultValue if it does not exist
this.getValue=function(prefName, defaultValue) {
var prefType=pref.getPrefType(prefName);
// underlying preferences object throws an exception if pref doesn't exist
if (prefType==pref.PREF_INVALID) {
return defaultValue;
}
switch (prefType) {
case pref.PREF_STRING: return pref.getCharPref(prefName);
case pref.PREF_BOOL: return pref.getBoolPref(prefName);
case pref.PREF_INT: return pref.getIntPref(prefName);
}
}
// sets the named preference to the specified value. values must be strings,
// booleans, or integers.
this.setValue=function(prefName, value) {
var prefType=typeof(value);
switch (prefType) {
case "string":
case "boolean":
break;
case "number":
if (value % 1 != 0) {
throw new Error("Cannot set preference to non integral number");
}
break;
default:
throw new Error("Cannot set preference with datatype: " + prefType);
}
// underlying preferences object throws an exception if new pref has a
// different type than old one. i think we should not do this, so delete
// old pref first if this is the case.
if (this.exists(prefName) && prefType != typeof(this.getValue(prefName))) {
this.remove(prefName);
}
// set new value using correct method
switch (prefType) {
case "string": pref.setCharPref(prefName, value); break;
case "boolean": pref.setBoolPref(prefName, value); break;
case "number": pref.setIntPref(prefName, Math.floor(value)); break;
}
}
// deletes the named preference or subtree
this.remove=function(prefName) {
pref.deleteBranch(prefName);
}
// call a function whenever the named preference subtree changes
this.watch=function(prefName, watcher) {
// construct an observer
var observer={
observe:function(subject, topic, prefName) {
watcher(prefName);
}
};
// store the observer in case we need to remove it later
observers[watcher]=observer;
pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal).
addObserver(prefName, observer, false);
}
// stop watching
this.unwatch=function(prefName, watcher) {
if (observers[watcher]) {
pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal)
.removeObserver(prefName, observers[watcher]);
}
}
}PK
M[>(8 chrome/content/prefman.jsfunction xbmciplayersender_PrefManager() {
var startPoint="extensions.xbmciplayersender.";
var pref=Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).
getBranch(startPoint);
var observers={};
// whether a preference exists
this.exists=function(prefName) {
return pref.getPrefType(prefName) != 0;
}
// returns the named preference, or defaultValue if it does not exist
this.getValue=function(prefName, defaultValue) {
var prefType=pref.getPrefType(prefName);
// underlying preferences object throws an exception if pref doesn't exist
if (prefType==pref.PREF_INVALID) {
return defaultValue;
}
switch (prefType) {
case pref.PREF_STRING: return pref.getCharPref(prefName);
case pref.PREF_BOOL: return pref.getBoolPref(prefName);
case pref.PREF_INT: return pref.getIntPref(prefName);
}
}
// sets the named preference to the specified value. values must be strings,
// booleans, or integers.
this.setValue=function(prefName, value) {
var prefType=typeof(value);
switch (prefType) {
case "string":
case "boolean":
break;
case "number":
if (value % 1 != 0) {
throw new Error("Cannot set preference to non integral number");
}
break;
default:
throw new Error("Cannot set preference with datatype: " + prefType);
}
// underlying preferences object throws an exception if new pref has a
// different type than old one. i think we should not do this, so delete
// old pref first if this is the case.
if (this.exists(prefName) && prefType != typeof(this.getValue(prefName))) {
this.remove(prefName);
}
// set new value using correct method
switch (prefType) {
case "string": pref.setCharPref(prefName, value); break;
case "boolean": pref.setBoolPref(prefName, value); break;
case "number": pref.setIntPref(prefName, Math.floor(value)); break;
}
}
// deletes the named preference or subtree
this.remove=function(prefName) {
pref.deleteBranch(prefName);
}
// call a function whenever the named preference subtree changes
this.watch=function(prefName, watcher) {
// construct an observer
var observer={
observe:function(subject, topic, prefName) {
watcher(prefName);
}
};
// store the observer in case we need to remove it later
observers[watcher]=observer;
pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal).
addObserver(prefName, observer, false);
}
// stop watching
this.unwatch=function(prefName, watcher) {
if (observers[watcher]) {
pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal)
.removeObserver(prefName, observers[watcher]);
}
}
}PK
M[>Ua * chrome/content/script-compiler-overlay.xulPK
M[>Zm¡% % % chrome/content/script-compiler.bck.jsvar xbmciplayersender_gmCompiler={
// getUrlContents adapted from Greasemonkey Compiler
// http://www.letitblog.com/code/python/greasemonkey.py.txt
// used under GPL permission
//
// most everything else below based heavily off of Greasemonkey
// http://greasemonkey.devjavu.com/
// used under GPL permission
getUrlContents: function(aUrl){
var ioService=Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var scriptableStream=Components
.classes["@mozilla.org/scriptableinputstream;1"]
.getService(Components.interfaces.nsIScriptableInputStream);
var unicodeConverter=Components
.classes["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
unicodeConverter.charset="UTF-8";
var channel=ioService.newChannel(aUrl, null, null);
var input=channel.open();
scriptableStream.init(input);
var str=scriptableStream.read(input.available());
scriptableStream.close();
input.close();
try {
return unicodeConverter.ConvertToUnicode(str);
} catch (e) {
return str;
}
},
isGreasemonkeyable: function(url) {
var scheme=Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.extractScheme(url);
dump(scheme);
return (
(scheme == "http" || scheme == "https" || scheme == "file") &&
!/hiddenWindow\.html$/.test(url)
);
},
contentLoad: function(e) {
dump('In contentLoaded');
// dump(Browser.selectedBrowser.contentDocument.title);
// var unsafeWin=e.target.defaultView;
// if (unsafeWin.wrappedJSObject) unsafeWin=unsafeWin.wrappedJSObject;
// var unsafeLoc=new XPCNativeWrapper(unsafeWin, "location").location;
// var href=new XPCNativeWrapper(unsafeLoc, "href").href;
// if (
// xbmciplayersender_gmCompiler.isGreasemonkeyable(href)
// && true
// && true
// ) {
// dump('Is greasmonkeyable');
// var script=xbmciplayersender_gmCompiler.getUrlContents(
// 'chrome://xbmciplayersender/content/xbmciplayersender.js'
// );
// xbmciplayersender_gmCompiler.injectScript(script, href, unsafeWin);
// }
// dump('end ContentLoaded');
},
injectScript: function(script, url, unsafeContentWin) {
dump('In injectScript');
var sandbox, script, logger, storage, xmlhttpRequester;
var safeWin=new XPCNativeWrapper(unsafeContentWin);
sandbox=new Components.utils.Sandbox(safeWin);
var storage=new xbmciplayersender_ScriptStorage();
xmlhttpRequester=new xbmciplayersender_xmlhttpRequester(
unsafeContentWin, window//appSvc.hiddenDOMWindow
);
sandbox.window=safeWin;
sandbox.document=sandbox.window.document;
sandbox.unsafeWindow=unsafeContentWin;
// patch missing properties on xpcnw
sandbox.XPathResult=Components.interfaces.nsIDOMXPathResult;
// add our own APIs
sandbox.GM_addStyle=function(css) { xbmciplayersender_gmCompiler.addStyle(sandbox.document, css) };
sandbox.GM_setValue=xbmciplayersender_gmCompiler.hitch(storage, "setValue");
sandbox.GM_getValue=xbmciplayersender_gmCompiler.hitch(storage, "getValue");
sandbox.GM_openInTab=xbmciplayersender_gmCompiler.hitch(this, "openInTab", unsafeContentWin);
sandbox.GM_xmlhttpRequest=xbmciplayersender_gmCompiler.hitch(
xmlhttpRequester, "contentStartRequest"
);
//unsupported
sandbox.GM_registerMenuCommand=function(){};
sandbox.GM_log=function(){};
sandbox.GM_getResourceURL=function(){};
sandbox.GM_getResourceText=function(){};
sandbox.__proto__=sandbox.window;
try {
dump('Evaluating script');
this.evalInSandbox(
"(function(){"+script+"})()",
url,
sandbox);
} catch (e) {
var e2=new Error(typeof e=="string" ? e : e.message);
e2.fileName=script.filename;
e2.lineNumber=0;
//GM_logError(e2);
alert(e2);
}
},
evalInSandbox: function(code, codebase, sandbox) {
if (Components.utils && Components.utils.Sandbox) {
// DP beta+
Components.utils.evalInSandbox(code, sandbox);
} else if (Components.utils && Components.utils.evalInSandbox) {
// DP alphas
Components.utils.evalInSandbox(code, codebase, sandbox);
} else if (Sandbox) {
// 1.0.x
evalInSandbox(code, sandbox, codebase);
} else {
throw new Error("Could not create sandbox.");
}
},
openInTab: function(unsafeContentWin, url) {
var tabBrowser = getBrowser(), browser, isMyWindow = false;
for (var i = 0; browser = tabBrowser.browsers[i]; i++)
if (browser.contentWindow == unsafeContentWin) {
isMyWindow = true;
break;
}
if (!isMyWindow) return;
var loadInBackground, sendReferrer, referrer = null;
loadInBackground = tabBrowser.mPrefs.getBoolPref("browser.tabs.loadInBackground");
sendReferrer = tabBrowser.mPrefs.getIntPref("network.http.sendRefererHeader");
if (sendReferrer) {
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
referrer = ios.newURI(content.document.location.href, null, null);
}
tabBrowser.loadOneTab(url, referrer, null, null, loadInBackground);
},
hitch: function(obj, meth) {
var unsafeTop = new XPCNativeWrapper(unsafeContentWin, "top").top;
for (var i = 0; i < this.browserWindows.length; i++) {
this.browserWindows[i].openInTab(unsafeTop, url);
}
},
apiLeakCheck: function(allowedCaller) {
var stack=Components.stack;
var leaked=false;
do {
if (2==stack.language) {
if ('chrome'!=stack.filename.substr(0, 6) &&
allowedCaller!=stack.filename
) {
leaked=true;
break;
}
}
stack=stack.caller;
} while (stack);
return leaked;
},
hitch: function(obj, meth) {
if (!obj[meth]) {
throw "method '" + meth + "' does not exist on object '" + obj + "'";
}
var hitchCaller=Components.stack.caller.filename;
var staticArgs = Array.prototype.splice.call(arguments, 2, arguments.length);
return function() {
if (xbmciplayersender_gmCompiler.apiLeakCheck(hitchCaller)) {
return;
}
// make a copy of staticArgs (don't modify it because it gets reused for
// every invocation).
var args = staticArgs.concat();
// add all the new arguments
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
// invoke the original function with the correct this obj and the combined
// list of static and dynamic arguments.
return obj[meth].apply(obj, args);
};
},
addStyle:function(doc, css) {
var head, style;
head = doc.getElementsByTagName('head')[0];
if (!head) { return; }
style = doc.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
},
onMessage: function(message) {
dump(message.json.text);
},
onLoad: function() {
dump('In onLoad');
var appcontent=window.document.getElementById("browsers");
//if (appcontent && !appcontent.greased_xbmciplayersender_gmCompiler) {
// appcontent.greased_xbmciplayersender_gmCompiler=true;
appcontent.addEventListener("DOMContentLoaded", xbmciplayersender_gmCompiler.contentLoad, false);
//appcontent.addEventListener("load", xbmciplayersender_gmCompiler.contentLoad, false);
//appcontent.tabContainer.addEventListener("TabSelect", xbmciplayersender_gmCompiler.contentLoad, false);
//}
messageManager.addMessageListener("MyCode:Loaded", xbmciplayersender_gmCompiler.onMessage);
messageManager.loadFrameScript("chrome://xbmciplayersender/content/content.js", true);
dump('End onLoad');
},
onUnLoad: function() {
dump('Remove Listeners');
//remove now unnecessary listeners
//window.removeEventListener('load', xbmciplayersender_gmCompiler.onLoad, false);
//window.removeEventListener('unload', xbmciplayersender_gmCompiler.onUnLoad, false);
//window.document.getElementById("browsers")
// .removeEventListener("DOMContentLoaded", xbmciplayersender_gmCompiler.contentLoad, false);
},
}; //object xbmciplayersender_gmCompiler
function dump(aMessage){
var consoleService =
Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage("XBMC iPlayer: " + aMessage);
}
function xbmciplayersender_ScriptStorage() {
this.prefMan=new xbmciplayersender_PrefManager();
}
xbmciplayersender_ScriptStorage.prototype.setValue = function(name, val) {
this.prefMan.setValue(name, val);
}
xbmciplayersender_ScriptStorage.prototype.getValue = function(name, defVal) {
return this.prefMan.getValue(name, defVal);
}
window.addEventListener('load', xbmciplayersender_gmCompiler.onLoad, false);
window.addEventListener('unload', xbmciplayersender_gmCompiler.onUnLoad, false);PK
M[>=d d $ chrome/content/script-compiler.ff.jsvar xbmciplayersender_gmCompiler={
// getUrlContents adapted from Greasemonkey Compiler
// http://www.letitblog.com/code/python/greasemonkey.py.txt
// used under GPL permission
//
// most everything else below based heavily off of Greasemonkey
// http://greasemonkey.devjavu.com/
// used under GPL permission
getUrlContents: function(aUrl){
var ioService=Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var scriptableStream=Components
.classes["@mozilla.org/scriptableinputstream;1"]
.getService(Components.interfaces.nsIScriptableInputStream);
var unicodeConverter=Components
.classes["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
unicodeConverter.charset="UTF-8";
var channel=ioService.newChannel(aUrl, "UTF-8", null);
var input=channel.open();
scriptableStream.init(input);
var str=scriptableStream.read(input.available());
scriptableStream.close();
input.close();
try {
return unicodeConverter.ConvertToUnicode(str);
} catch (e) {
return str;
}
},
isGreasemonkeyable: function(url) {
var scheme=Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.extractScheme(url);
return (
(scheme == "http" || scheme == "https" || scheme == "file") &&
!/hiddenWindow\.html$/.test(url)
);
},
contentLoad: function(e) {
var unsafeWin=e.target.defaultView;
if (unsafeWin.wrappedJSObject) unsafeWin=unsafeWin.wrappedJSObject;
var unsafeLoc=new XPCNativeWrapper(unsafeWin, "location").location;
var href=new XPCNativeWrapper(unsafeLoc, "href").href;
if (
xbmciplayersender_gmCompiler.isGreasemonkeyable(href)
&& true
&& true
) {
var script=xbmciplayersender_gmCompiler.getUrlContents(
'chrome://xbmciplayersender/content/xbmciplayersender.js'
);
xbmciplayersender_gmCompiler.injectScript(script, href, unsafeWin);
}
},
injectScript: function(script, url, unsafeContentWin) {
var sandbox, script, logger, storage, xmlhttpRequester;
var safeWin=new XPCNativeWrapper(unsafeContentWin);
sandbox=new Components.utils.Sandbox(safeWin);
var storage=new xbmciplayersender_ScriptStorage();
xmlhttpRequester=new xbmciplayersender_xmlhttpRequester(
unsafeContentWin, window//appSvc.hiddenDOMWindow
);
sandbox.window=safeWin;
sandbox.document=sandbox.window.document;
sandbox.unsafeWindow=unsafeContentWin;
// patch missing properties on xpcnw
sandbox.XPathResult=Components.interfaces.nsIDOMXPathResult;
// add our own APIs
sandbox.GM_addStyle=function(css) { xbmciplayersender_gmCompiler.addStyle(sandbox.document, css) };
sandbox.GM_setValue=xbmciplayersender_gmCompiler.hitch(storage, "setValue");
sandbox.GM_getValue=xbmciplayersender_gmCompiler.hitch(storage, "getValue");
sandbox.GM_openInTab=xbmciplayersender_gmCompiler.hitch(this, "openInTab", unsafeContentWin);
sandbox.GM_xmlhttpRequest=xbmciplayersender_gmCompiler.hitch(
xmlhttpRequester, "contentStartRequest"
);
//unsupported
sandbox.GM_registerMenuCommand=function(){};
sandbox.GM_log=xbmciplayersender_gmCompiler.hitch(this, "log");
sandbox.GM_getResourceURL=function(){};
sandbox.GM_getResourceText=function(){};
sandbox.__proto__=sandbox.window;
try {
this.evalInSandbox(
"(function(){"+script+"})()",
url,
sandbox);
} catch (e) {
var e2=new Error(typeof e=="string" ? e : e.message);
e2.fileName=script.filename;
e2.lineNumber=0;
//GM_logError(e2);
alert(e2);
}
},
log : function(text)
{
dump(text);
},
evalInSandbox: function(code, codebase, sandbox) {
if (Components.utils && Components.utils.Sandbox) {
// DP beta+
Components.utils.evalInSandbox(code, sandbox);
} else if (Components.utils && Components.utils.evalInSandbox) {
// DP alphas
Components.utils.evalInSandbox(code, codebase, sandbox);
} else if (Sandbox) {
// 1.0.x
evalInSandbox(code, sandbox, codebase);
} else {
throw new Error("Could not create sandbox.");
}
},
openInTab: function(unsafeContentWin, url) {
var tabBrowser = getBrowser(), browser, isMyWindow = false;
for (var i = 0; browser = tabBrowser.browsers[i]; i++)
if (browser.contentWindow == unsafeContentWin) {
isMyWindow = true;
break;
}
if (!isMyWindow) return;
var loadInBackground, sendReferrer, referrer = null;
loadInBackground = tabBrowser.mPrefs.getBoolPref("browser.tabs.loadInBackground");
sendReferrer = tabBrowser.mPrefs.getIntPref("network.http.sendRefererHeader");
if (sendReferrer) {
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
referrer = ios.newURI(content.document.location.href, null, null);
}
tabBrowser.loadOneTab(url, referrer, null, null, loadInBackground);
},
hitch: function(obj, meth) {
var unsafeTop = new XPCNativeWrapper(unsafeContentWin, "top").top;
for (var i = 0; i < this.browserWindows.length; i++) {
this.browserWindows[i].openInTab(unsafeTop, url);
}
},
apiLeakCheck: function(allowedCaller) {
var stack=Components.stack;
var leaked=false;
do {
if (2==stack.language) {
if ('chrome'!=stack.filename.substr(0, 6) &&
allowedCaller!=stack.filename
) {
leaked=true;
break;
}
}
stack=stack.caller;
} while (stack);
return leaked;
},
hitch: function(obj, meth) {
if (!obj[meth]) {
throw "method '" + meth + "' does not exist on object '" + obj + "'";
}
var hitchCaller=Components.stack.caller.filename;
var staticArgs = Array.prototype.splice.call(arguments, 2, arguments.length);
return function() {
if (xbmciplayersender_gmCompiler.apiLeakCheck(hitchCaller)) {
return;
}
// make a copy of staticArgs (don't modify it because it gets reused for
// every invocation).
var args = staticArgs.concat();
// add all the new arguments
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
// invoke the original function with the correct this obj and the combined
// list of static and dynamic arguments.
return obj[meth].apply(obj, args);
};
},
addStyle:function(doc, css) {
var head, style;
head = doc.getElementsByTagName('head')[0];
if (!head) { return; }
style = doc.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
},
onLoad: function() {;
var appcontent=window.document.getElementById("appcontent");
if (appcontent && !appcontent.greased_xbmciplayersender_gmCompiler) {
appcontent.greased_xbmciplayersender_gmCompiler=true;
appcontent.addEventListener("DOMContentLoaded", xbmciplayersender_gmCompiler.contentLoad, false);
}
},
onUnLoad: function() {
//remove now unnecessary listeners
window.removeEventListener('load', xbmciplayersender_gmCompiler.onLoad, false);
window.removeEventListener('unload', xbmciplayersender_gmCompiler.onUnLoad, false);
window.document.getElementById("appcontent")
.removeEventListener("DOMContentLoaded", xbmciplayersender_gmCompiler.contentLoad, false);
},
}; //object xbmciplayersender_gmCompiler
function xbmciplayersender_ScriptStorage() {
this.prefMan=new xbmciplayersender_PrefManager();
}
xbmciplayersender_ScriptStorage.prototype.setValue = function(name, val) {
this.prefMan.setValue(name, val);
}
xbmciplayersender_ScriptStorage.prototype.getValue = function(name, defVal) {
return this.prefMan.getValue(name, defVal);
}
function dump(aMessage){
var consoleService =
Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage("XBMC iPlayer: " + aMessage);
}
window.addEventListener('load', xbmciplayersender_gmCompiler.onLoad, false);
window.addEventListener('unload', xbmciplayersender_gmCompiler.onUnLoad, false);PK
M[>&< < ! chrome/content/script-compiler.jsvar xbmciplayersender_gmCompiler={
// getUrlContents adapted from Greasemonkey Compiler
// http://www.letitblog.com/code/python/greasemonkey.py.txt
// used under GPL permission
//
// most everything else below based heavily off of Greasemonkey
// http://greasemonkey.devjavu.com/
// used under GPL permission
onLoad: function() {
window.messageManager.addMessageListener("XBMCSender:Dump", xbmciplayersender_gmCompiler.onMessage);
window.messageManager.loadFrameScript("chrome://xbmciplayersender/content/prefman.js", true);
window.messageManager.loadFrameScript("chrome://xbmciplayersender/content/xmlhttprequester.js", true);
window.messageManager.loadFrameScript("chrome://xbmciplayersender/content/content.js", true);
},
onUnLoad: function() {
},
}; //object xbmciplayersender_gmCompiler
function dump(aMessage){
var consoleService =
Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage("XBMC iPlayer: " + aMessage);
}
function xbmciplayersender_ScriptStorage() {
this.prefMan=new xbmciplayersender_PrefManager();
}
xbmciplayersender_ScriptStorage.prototype.setValue = function(name, val) {
this.prefMan.setValue(name, val);
}
xbmciplayersender_ScriptStorage.prototype.getValue = function(name, defVal) {
return this.prefMan.getValue(name, defVal);
}
window.addEventListener('load', xbmciplayersender_gmCompiler.onLoad, false);
window.addEventListener('unload', xbmciplayersender_gmCompiler.onUnLoad, false);PK
M[> v chrome/content/uacontrolEdit.js
var uaEditManager = {
getString: function(sStringName)
{
return document.getElementById('uacontrol-strings').getString(sStringName);
},
onLoad: function()
{
try {
var fldSite = document.getElementById("fldSite");
var fldActionGroup = document.getElementById("fldActionGroup");
var fldActionNormal = document.getElementById("fldActionNormal");
var fldActionBlock = document.getElementById("fldActionBlock");
var fldActionCustom = document.getElementById("fldActionCustom");
var fldAction = document.getElementById("fldAction");
var site = window.arguments[0].site;
var action = window.arguments[0].action;
if (site == '@DEFAULT') {
fldSite.value = this.getString("SiteDefault");
fldSite.style.fontWeight = "bold";
fldSite.disabled = true;
} else {
fldSite.value = site;
}
switch (action.str)
{
case '@NORMAL':
fldActionGroup.selectedItem = fldActionNormal;
fldAction.value = "";
fldAction.disabled = true;
break;
case '':
fldActionGroup.selectedItem = fldActionBlock;
fldAction.value = "";
fldAction.disabled = true;
break;
default:
fldActionGroup.selectedItem = fldActionCustom;
fldAction.value = action.str;
fldAction.disabled = false;
break;
}
} catch (ex) {
uacontrolMisc.dump("onLoad: " + ex);
}
},
onOK: function()
{
try {
var fldSite = document.getElementById("fldSite");
var fldActionGroup = document.getElementById("fldActionGroup");
var fldActionNormal = document.getElementById("fldActionNormal");
var fldActionBlock = document.getElementById("fldActionBlock");
var fldActionCustom = document.getElementById("fldActionCustom");
var fldAction = document.getElementById("fldAction");
var site;
var action = {};
if (fldSite.disabled){
site = '@DEFAULT';
}else {
if (fldSite.value == "") {
window.alert(this.getString("SiteNotFilledInAlert"));
return false;
}
try {
var svcIO = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
site = svcIO.newURI(fldSite.value, null, null).host;
} catch (ex) {
site = fldSite.value;
}
if (site.search(/[ =]/) != -1) {
window.alert(this.getString("SiteInvalidCharactersAlert"));
return false;
}
}
switch (fldActionGroup.selectedItem)
{
case fldActionNormal:
action.str = '@NORMAL';
break;
case fldActionBlock:
action.str = '';
break;
case fldActionCustom:
action.str = fldAction.value;
break;
default:
window.alert("Unable to determine selected action.");
return false;
}
window.arguments[0].site = site;
window.arguments[0].action = action;
window.arguments[0].ret = true;
return true;
} catch (ex) {
uacontrolMisc.dump("onOK: " + ex);
}
return false;
},
onActionChange: function(aEvent)
{
var fldAction = document.getElementById("fldAction");
fldAction.disabled = !(aEvent.target.id == "fldActionCustom");
}
};
PK
M[>au chrome/content/uacontrolEdit.xul
PK
M[>`' chrome/content/uacontrolMisc.js
function uacontrolMisc(){}
uacontrolMisc.dump = function(aMessage){
var consoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage("UAControl: " + aMessage);
};
PK
M[>-^5 5 " chrome/content/uacontrolOptions.js
var uaOptionsManager = {
getString: function(sStringName)
{
return document.getElementById('uacontrol-strings').getString(sStringName);
},
_aUAActions: null,
aSortKeys: null,
// everything except '@DEFAULT' sorted lexicographically
sortKeys: function(arr)
{
var ret = [];
for (var sKey in arr) {
if (sKey != '@DEFAULT')
ret.push(sKey);
}
return ret.sort();
},
get aUAActions() { return this._aUAActions; },
set aUAActions(val) {
this._aUAActions = val;
this.aSortKeys = this.sortKeys(this._aUAActions);
},
get tree() {
return document.getElementById("actionsTree");
},
view: {
mgr: null, // points back to uaOptionsManager
atomBold: null,
init: function(mgr)
{
this.mgr = mgr;
var svcAtom = Components.classes["@mozilla.org/atom-service;1"].getService(Components.interfaces.nsIAtomService);
this.atomBold = svcAtom.getAtom("bold");
},
// Implement TreeView interface
get rowCount()
{
return this.mgr.aSortKeys.length;
},
getCellText: function (aRow, aColumn)
{
try {
var sColumn = (aColumn.id != undefined) ? aColumn.id : aColumn;
if (sColumn == "siteCol") {
return this.mgr.formatSite(this.mgr.aSortKeys[aRow]);
} else if (sColumn == "actionCol") {
return this.mgr.formatAction(this.mgr.aUAActions[this.mgr.aSortKeys[aRow]]);
}
} catch (ex) {
uacontrolMisc.dump("getCellText: " + ex);
}
return "";
},
isSeparator: function(aIndex) { return false; },
isSorted: function() { return false; },
isContainer: function(aIndex) { return false; },
setTree: function(aTree){},
getImageSrc: function(aRow, aColumn) {},
getProgressMode: function(aRow, aColumn) {},
getCellValue: function(aRow, aColumn) {},
cycleHeader: function(aColId, aElt) {},
getRowProperties: function(aRow, aProperty) {},
getColumnProperties: function(aColumn, aColumnElement, aProperty) {},
getCellProperties: function(aRow, aColumn, aProperty)
{
try {
var bBold = false;
var sColumn = (aColumn.id != undefined) ? aColumn.id : aColumn;
var sValue;
if (sColumn == "siteCol") {
sValue = this.mgr.aSortKeys[aRow];
bBold = (sValue.charAt(0) == '@');
} else if (sColumn == "actionCol") {
sValue = this.mgr.aUAActions[this.mgr.aSortKeys[aRow]].str;
bBold = (sValue.charAt(0) == '@' || sValue == '');
}
if (bBold)
aProperty.AppendElement(this.atomBold);
} catch (ex) {
uacontrolMisc.dump("getCellProperties: " + ex);
}
},
get selection() {
return (
this._selection != undefined ? this._selection :
this.mgr.tree.selection != undefined ? this.mgr.tree.selection : undefined);
},
set selection(val) { return this._selection = val; }
// end Implement TreeView interface
},
getActionsToExport: function()
{
function myEncodeURI(sURI)
{
if (sURI.charAt(0) == '@')
return sURI;
else
return encodeURI(sURI);
}
var aKVs = [];
var myKeys = ['@DEFAULT'].concat(this.aSortKeys);
for (var i = 0; i < myKeys.length; i++) {
aKVs.push(myKeys[i] + "=" + myEncodeURI(this.aUAActions[myKeys[i]].str));
}
return aKVs;
},
getActionsFromImport: function(aActions, oldActions)
{
function myDecodeURI(sEncodedURI)
{
if (sEncodedURI.charAt(0) == '@')
return sEncodedURI;
try {
return decodeURI(sEncodedURI);
} catch (ex) {
return sEncodedURI;
}
}
var newActions = oldActions ? oldActions : [];
for (var i in aActions) {
var aKV = aActions[i].match(/(.*?)=(.*)/);
if (aKV != null) {
newActions[aKV[1]] = { str: myDecodeURI(aKV[2]) };
}
}
return newActions;
},
getActionsFromBranch: function(oPrefBranch)
{
var sActions = oPrefBranch.getCharPref('actions');
var oldActions = [];
oldActions['@DEFAULT'] = { str: '@NORMAL' }; // in case it is not in the pref
return this.getActionsFromImport(sActions.split(' '), oldActions);
},
getActions: function()
{
return this.getActionsFromBranch(uaPrefs.getPrefBranch());
},
onLoad: function()
{
try {
this.aUAActions = this.getActions();
this.view.init(this);
this.tree.treeBoxObject.view = this.view;
this.onActionsSelected();
this.onDefaultChanged();
if (window.arguments != undefined &&
window.arguments[0] != undefined &&
window.arguments[0].contextSite != undefined)
{
// opened from context menu
setTimeout(function(myThis, sSite) { myThis.contextEdit(sSite); },
0,
this, window.arguments[0].contextSite);
// this.contextEdit(window.arguments[0].contextSite);
}
} catch (ex) {
uacontrolMisc.dump("onLoad: " + ex);
}
},
onOK: function()
{
try {
var sActions = this.getActionsToExport().join(" ");
var prefBranch = uaPrefs.getPrefBranch();
prefBranch.setCharPref("actions", sActions);
return true;
} catch (ex) {
uacontrolMisc.dump("onOK: " + ex);
}
return false;
},
findRDFID: function(extDB, sID)
{
var prefixes = [
"urn:mozilla:extension:", // Firefox 1.0.x
"urn:mozilla:item:" // Firefox 1.5
];
var rdfs = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
for (var i in prefixes) {
var sRDFID = prefixes[i] + sID;
if (extDB.GetTarget(rdfs.GetResource(sRDFID),
rdfs.GetResource("http://www.mozilla.org/2004/em-rdf#name"),
true) !== null)
return sRDFID;
}
return null;
},
getLineBreak: function()
{
var p = navigator.platform;
return (
(new RegExp("win", "i").test(p) || new RegExp("os/2", "i").test(p)) ?
"\r\n" : "\n"
);
},
onImport: function()
{
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
fp.init(window, this.getString("ImportTitle"), fp.modeOpen);
fp.appendFilters(fp.filterText);
fp.appendFilters(fp.filterAll);
if (fp.show() == fp.returnCancel)
return;
try {
var fis = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
fis.QueryInterface(Components.interfaces.nsILineInputStream);
fis.init(fp.file,
0x01, /* PR_RDONLY */
0444, /* r--r--r-- (unused?) */
0);
var lines = []
var line = {};
var eof;
eof = !fis.readLine(line);
if (line.value != '[UAControl]') {
alert(this.getString("ImportInvalidFileAlert"));
return;
}
while (!eof) {
eof = !fis.readLine(line);
if (line.value.charAt(0) == '[')
break;
if (line.value.charAt(0) == ';')
continue;
lines.push(line.value);
}
fis.close();
this.aUAActions = this.getActionsFromImport(lines, this.aUAActions);
if (this.view.selection) {
this.view.selection.clearSelection();
this.view.selection.currentIndex = -1;
}
this.tree.treeBoxObject.view = this.view; /* refresh tree view */
this.onDefaultChanged(); /* refresh default box, just in case */
} catch(ex) {
alert(this.getString("ImportErrorAlert") + ": " + ex);
}
},
onExport: function()
{
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
fp.init(window, this.getString("ExportTitle"), fp.modeSave);
fp.defaultExtension = "txt";
fp.appendFilters(fp.filterText);
fp.appendFilters(fp.filterAll);
if (fp.show() == fp.returnCancel)
return;
try {
var fos = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
fos.init(fp.file,
0x02 | /* PR_WRONLY */
0x08 | /* PR_CREATE_FILE */
0x20, /* PR_TRUNCATE */
0644, /* rw-r--r-- */
0);
/* remove first entry (@DEFAULT) and add '[UAControl]' at front */
var arrLines = ['[UAControl]'].concat(this.getActionsToExport().slice(1));
var sLines = arrLines.join(this.getLineBreak()) + this.getLineBreak();
fos.write(sLines, sLines.length);
fos.close();
} catch(ex) {
alert(this.getString("ExportErrorAlert") + ": " + ex);
}
},
onActionsDblClick: function(aEvent)
{
try {
if (aEvent.target._lastSelectedRow != -1)
this.onEdit();
else
this.onAdd();
} catch (ex) {
uacontrolMisc.dump("onActionsDblClick: " + ex);
}
},
onActionsKeyPress: function(aEvent)
{
if (aEvent.keyCode == 46) {
/* Delete */
var btnRemove = document.getElementById("btnRemove");
if (!btnRemove.disabled)
this.onRemove();
}
},
onActionsSelected: function()
{
try {
var selection = this.view.selection;
var btnEdit = document.getElementById("btnEdit");
var btnRemove = document.getElementById("btnRemove");
btnEdit.disabled = !(selection && (selection.count == 1));
btnRemove.disabled = !(selection && (selection.count >= 1));
} catch (ex) {
uacontrolMisc.dump("onActionsSelected: " + ex);
}
},
doEdit: function(oldSite, oldIndex)
{
if (oldIndex != -1) {
if (this.view.selection)
this.view.selection.select(oldIndex);
this.tree.treeBoxObject.ensureRowIsVisible(oldIndex);
}
var oldAction = (this.aUAActions[oldSite] != undefined) ?
this.aUAActions[oldSite] :
{ str: '@NORMAL' };
var arg = { site: oldSite, action: oldAction };
openDialog("chrome://uacontrol/content/uacontrolEdit.xul",
"", "centerscreen,chrome,modal,resizable=no", arg);
if (!arg.ret)
return;
if (arg.site != oldSite)
delete this.aUAActions[oldSite];
this.aUAActions[arg.site] = arg.action;
if (oldIndex == -1 || arg.site != oldSite) {
this.aUAActions = this.aUAActions; // yea for hidden side-effects
if (this.view.selection) {
this.view.selection.clearSelection();
// don't know why, but we need this next line if called via
// the setTimeout for the contextEdit
this.view.selection.currentIndex = -1;
}
this.tree.treeBoxObject.view = this.view; // force total refresh
} else {
this.tree.treeBoxObject.invalidateRow(oldIndex);
}
if (arg.site == '@DEFAULT')
this.onDefaultChanged();
},
onAdd: function()
{
try {
this.doEdit("", -1);
} catch (ex) {
uacontrolMisc.dump("onAdd: " + ex);
}
},
onEdit: function()
{
try {
var selection = this.view.selection;
var oldSite = this.aSortKeys[selection.currentIndex];
this.doEdit(oldSite, selection.currentIndex);
} catch (ex) {
uacontrolMisc.dump("onEdit: " + ex);
}
},
contextEdit: function(sSite)
{
try {
this.doEdit(sSite, this.binarySearch(this.aSortKeys, sSite));
} catch (ex) {
uacontrolMisc.dump("contextEdit: " + ex);
}
},
binarySearch: function(arr, searchElement, lft, rgt)
{
if (lft == undefined || lft < 0) lft = 0;
if (rgt == undefined || rgt > arr.length - 1) rgt = arr.length - 1;
while (lft <= rgt) {
var mid = Math.floor((rgt + lft) / 2);
if (arr[mid] < searchElement)
lft = mid + 1;
else if (arr[mid] > searchElement)
rgt = mid - 1;
else if (arr[mid] == searchElement)
return mid;
else
throw "Array contains invalid elements for binary search";
}
return -1;
},
onRemove: function()
{
try {
var selection = this.view.selection;
var oldIndex = selection.currentIndex;
selection.selectEventsSuppressed = true;
// remove selected items from aUAActions
var rangeCount = selection.getRangeCount();
for (var range = 0; range < rangeCount; range++) {
var min = new Object(), max = new Object();
selection.getRangeAt(range, min, max);
for (var i = min.value; i <= max.value; i++) {
delete this.aUAActions[this.aSortKeys[i]];
}
}
// remove references from aSortKeys and refresh tree display
for (i = 0; i < this.aSortKeys.length; i++) {
if (this.aUAActions[this.aSortKeys[i]] == undefined) {
var r = i;
while (
r < this.aSortKeys.length &&
this.aUAActions[this.aSortKeys[r]] == undefined
)
r++;
this.aSortKeys.splice(i, r - i);
this.tree.treeBoxObject.rowCountChanged(i, i - r);
}
}
selection.selectEventsSuppressed = false;
// fix selection
if (oldIndex > this.view.rowCount - 1)
oldIndex = this.view.rowCount - 1;
this.view.selection.select(oldIndex);
this.tree.treeBoxObject.ensureRowIsVisible(oldIndex);
} catch (ex) {
uacontrolMisc.dump("onRemove: " + ex);
}
},
onRemoveAll: function()
{
try {
if (!window.confirm(this.getString("ConfirmRemoveAll")))
return;
var newUAActions = {};
var oldRowCount = this.view.rowCount;
newUAActions['@DEFAULT'] = this.aUAActions['@DEFAULT'];
this.aUAActions = newUAActions;
this.tree.treeBoxObject.rowCountChanged(0, -oldRowCount);
var selection = this.view.selection;
if (selection)
selection.clearSelection();
} catch (ex) {
uacontrolMisc.dump("onRemoveAll: " + ex);
}
},
onDefaultChanged: function()
{
try {
var txtDefault = document.getElementById("txtDefault");
var act = this.aUAActions['@DEFAULT'];
var bBold = (act.str.charAt(0) == '@' || act.str == '');
txtDefault.value = this.formatAction(act);
txtDefault.style.color = "#000000";
txtDefault.style.fontWeight = bBold ? 'bold' : 'normal';
} catch (ex) {
uacontrolMisc.dump("onDefaultChanged: " + ex);
}
},
onEditDefault: function()
{
try {
this.doEdit('@DEFAULT', -1);
} catch (ex) {
uacontrolMisc.dump("onEditDefault: " + ex);
}
},
formatSite: function(sSite)
{
return (
(sSite == '@DEFAULT') ?
this.getString("SiteDefault") :
sSite
);
},
formatAction: function(act)
{
return (
(act.str == '@NORMAL') ?
this.getString("ActionNormal") :
(act.str == '') ?
this.getString("ActionBlock") :
act.str
);
}
};
PK
M[>&0< < " chrome/content/uacontrolOverlay.js
var uaOverlayManager = {
getString: function(sStringName)
{
return document.getElementById('uacontrol-strings').getString(sStringName);
},
isOurURL: function(sURL)
{
var svcIO = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
try {
var uri = svcIO.newURI(sURL, null, null);
} catch (ex) {
return false;
}
return (uri.schemeIs('http') || uri.schemeIs('https'));
},
getLinkURL: function(contextMenu)
{
return(
typeof(contextMenu.linkURL) == 'function' ?
contextMenu.linkURL() : contextMenu.linkURL
);
},
openOptions: function(sSite)
{
var winOptions = openDialog('chrome://uacontrol/content/uacontrolOptions.xul',
'UAControlOptions',
'centerscreen,chrome,resizable,dialog=no',
(sSite !== undefined) ? { contextSite: sSite } : undefined);
try {
winOptions.focus();
} catch (ex) { }
},
openOptionsURL: function(sURL)
{
var svcIO = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
this.openOptions(svcIO.newURI(sURL, null, null).host);
},
toolsOptions: function()
{
this.openOptions();
},
contextOptions: function()
{
var sSite;
try {
sSite = window._content.document.location.hostname;
} catch (ex) { }
this.openOptions(sSite);
},
contextOptionsLink: function()
{
this.openOptionsURL(this.getLinkURL(gContextMenu));
},
contextOptionsImage: function()
{
this.openOptionsURL(gContextMenu.imageURL);
},
onLoad: function()
{
window.getBrowser().addProgressListener(this,
Components.interfaces.nsIWebProgress.NOTIFY_LOCATION |
Components.interfaces.nsIWebProgress.NOTIFY_STATUS);
document.getElementById("contentAreaContextMenu").addEventListener("popupshowing", this, false);
this.prefBranch = uaPrefs.getPrefBranch();
this.prefBranch.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
for (var sPref in
{
enabled: 0,
statusbar: 0,
contextMenu: 0
}
)
{
this.prefBranch.addObserver(sPref, this, true);
this.observe(this.prefBranch, 'nsPref:changed', sPref);
}
},
onPopupShowing: function(e)
{
var bShow = this.bShowContextMenu &&
!gContextMenu.isTextSelected && !gContextMenu.onLink && !gContextMenu.onImage && !gContextMenu.onTextInput &&
this.isOurURL(gContextMenu.target.ownerDocument.location.href); // gContextMenu.docURL
var bShowLink = this.bShowContextMenu &&
gContextMenu.onLink &&
this.isOurURL(this.getLinkURL(gContextMenu));
var bShowImage = this.bShowContextMenu &&
gContextMenu.onImage &&
this.isOurURL(gContextMenu.imageURL);
gContextMenu.showItem('uacontrol_sep', bShow || bShowLink || bShowImage);
gContextMenu.showItem('uacontrol_options', bShow);
gContextMenu.showItem('uacontrol_options_link', bShowLink);
gContextMenu.showItem('uacontrol_options_image', bShowImage);
},
// Implement nsIEventListener
handleEvent: function(evt)
{
try {
switch (evt.type)
{
case 'load':
// workaround https://bugzilla.mozilla.org/show_bug.cgi?id=174320
setTimeout(function(myThis) {
window.removeEventListener("load", myThis, false);
}, 0, this);
// window.removeEvenetListener("load", this, false);
return this.onLoad(evt);
case 'popupshowing':
return this.onPopupShowing(evt);
default:
uacontrolMisc.dump("handleEvent: unknown event: " + evt.type);
}
} catch (ex) {
uacontrolMisc.dump("handleEvent: " + ex);
}
return undefined;
},
onChangeEnabled: function(oPrefBranch)
{
try {
this.bEnabled = oPrefBranch.getBoolPref('enabled');
this.updateStatusbar();
} catch (ex) {
uacontrolMisc.dump("onChangeEnabled: " + ex);
}
},
onChangeStatusbar: function(oPrefBranch)
{
try {
this.showStatusbar = oPrefBranch.getBoolPref("statusbar");
this.updateStatusbar();
} catch (ex) {
uacontrolMisc.dump("onChangeStatusbar: " + ex);
}
},
onChangeContextMenu: function(oPrefBranch)
{
try {
this.bShowContextMenu = oPrefBranch.getBoolPref('contextMenu');
} catch (ex) {
uacontrolMisc.dump("onChangeContextMenu: " + ex);
}
},
// Implement nsIObserver
observe: function(aSubject, aTopic, aData)
{
try {
switch (aTopic)
{
case 'nsPref:changed':
aSubject.QueryInterface(Components.interfaces.nsIPrefBranch);
switch (aData)
{
case 'enabled':
this.onChangeEnabled(aSubject);
break;
case 'statusbar':
this.onChangeStatusbar(aSubject);
break;
case 'contextMenu':
this.onChangeContextMenu(aSubject);
break;
default:
uacontrolMisc.dump("observe: unknown pref changing: " + aData);
break;
}
break;
default:
uacontrolMisc.dump("observe: unknown topic: " + aTopic);
break;
}
} catch (ex) {
uacontrolMisc.dump("observe: " + ex);
}
},
updateStatusbar: function()
{
try {
var sb = document.getElementById("uacontrol-status");
if (!this.showStatusbar) {
sb.setAttribute("collapsed", true);
return;
}
var sbIcon = document.getElementById("uacontrol-status-icon");
sbIcon.src = this.bEnabled ?
"chrome://uacontrol/skin/icon_enabled.png" :
"chrome://uacontrol/skin/icon_disabled.png";
sb.removeAttribute("collapsed");
} catch (ex) {
uacontrolMisc.dump("updateStatusbar: " + ex);
}
},
updateOnNextStatusChange: false,
// Implement nsIWebProgressListener
onLocationChange: function(aWebProgress, aRequest, aLocation)
{
this.updateStatusbar();
this.updateOnNextStatusChange = true;
},
onProgressChange: function(webProgress, request, curSelfProgress, maxSelfProgress, curTotalProgress, maxTotalProgress) {},
onSecurityChange: function(webProgress, request, state) {},
onStateChange: function(webProgress, request, stateFlags, status) {},
onStatusChange: function(webProgress, request, status, message)
{
if (this.updateOnNextStatusChange)
{
this.updateStatusbar();
this.updateOnNextStatusChange = false;
}
},
// end Implement nsIWebProgressListener
// see http://forums.mozillazine.org/viewtopic.php?t=49716
onLinkIconAvailable: function(a) {},
// Implement nsISupports
QueryInterface: function(aIID)
{
if (aIID.equals(Components.interfaces.nsIObserver) ||
aIID.equals(Components.interfaces.nsIWebProgressListener) ||
// aIID.equals(Components.interfaces.nsIEventListener) ||
aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
aIID.equals(Components.interfaces.nsISupports))
{
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
window.addEventListener("load", uaOverlayManager, false);
PK
N[>
c c chrome/content/uacontrolPrefs.js
var uaPrefs =
{
getPrefBranch: function()
{
var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
return prefService.getBranch("uacontrol.");
},
onPopupShowing: function(aEvent)
{
// onpopupshowing is inherited by child elements.
// avoid processing on these
if (aEvent.target.id != "uacontrol-popupOptions")
return true;
var prefBranch = this.getPrefBranch();
var bChecked;
var arrMenuItems = aEvent.target.getElementsByTagName("menuitem");
for (var i in arrMenuItems) {
var type;
if(arrMenuItems[i].getAttribute)
type = arrMenuItems[i].getAttribute('type');
else continue;
switch (type)
{
case 'checkbox':
case 'radio':
try {
if (type == 'checkbox')
bChecked = prefBranch.getBoolPref(arrMenuItems[i].value);
else if (type == 'radio')
bChecked = (prefBranch.getIntPref(arrMenuItems[i].getAttribute('name')) == arrMenuItems[i].value);
} catch (e) {
bChecked = false;
}
if (bChecked)
arrMenuItems[i].setAttribute("checked", true);
else
arrMenuItems[i].removeAttribute("checked");
break;
}
}
return true;
},
onChangeCheckboxPref: function(aEvent)
{
if(aEvent.target.getAttribute("checked") == "false"){
aEvent.target.setAttribute("checked", "");
}
try {
this.getPrefBranch().setBoolPref(
aEvent.target.value,
!!aEvent.target.getAttribute('checked'));
} catch (ex) {
uacontrolMisc.dump("onChangeCheckboxPref: " + ex);
}
}
};
PK
[>ϖ # chrome/content/xbmciplayersender.js// ==UserScript==
// @name XBMC iPlayer sender
// @namespace xbmciPlayer
// @description Provides an option on iPlayer to send to XBMC requires the URL of your XBMC box from the computer you install the script on
// @version January 2011. Initial version
// @match bbc.co.uk/iplayer/*
// ==/UserScript==
var match = /iplayer\/episode\/([^\/#?]+)/.exec(window.location.href)
var enabled = GM_getValue('enabled');
if (enabled)
{
if (match)
{
//With thanks to webtoolkit
// http://www.webtoolkit.info/javascript-base64.html
var Base64 = {
// private property
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// public method for encoding
encode : function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = Base64._utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
}
return output;
},
// private method for UTF-8 encoding
_utf8_encode : function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
}
function sendRequest()
{
var host = GM_getValue('hostname');
var port = GM_getValue('port');
var username = GM_getValue('username');
var password = GM_getValue('password');
url = 'http://';
url = url + host + ':' + port.toString() + '/jsonrpc';
GM_log(url);
if (username != "")
{
//Create authorization header
var tok = username + ':' + password;
var hash = Base64.encode(tok);
var authHeader = "Basic " + hash;
}
var postData = '{"jsonrpc":"2.0","method":"XBMC.Play","params":"plugin://plugin.video.iplayer/?resolveURL=True&pid=' + match[1] + '","id":1}';
try
{
GM_xmlhttpRequest({
method: 'POST',
url: url,
data: postData,
headers: { Authorization: authHeader },
onerror: function(r) {
GM_log('XBMC: Request Sent');
if (r.status != 200)
{
alert('Error Contacting XBMC ' + r.Status);
}
}
});
}
catch(err)
{
alert('Error Contacting XBMC ' + err);
}
}
//add button
var epTools = document.getElementById('episodeTools');
//insert before epTools
if (epTools)
{
GM_log('Adding desktop button');
var div = document.createElement('div');
var link = document.createElement('a');
var img = document.createElement('img');
img.src = "http://www.awilco.net/xbmc/main_btn.png";
link.href="#";
link.addEventListener('click',sendRequest,false);
link.appendChild(img);
div.appendChild(link);
epTools.parentNode.insertBefore(div,epTools);
}
//Try mobile
var mobileButton = document.getElementById('clicktoplay');
if (mobileButton)
{
var btnImg = mobileButton.childNodes[1];
GM_log(btnImg.nodeName);
btnImg.src = "http://www.awilco.net/xbmc/send_to_xbmc.png";
GM_log('Adding mobile button');
mobileButton.addEventListener('click',sendRequest,false);
}
}
}PK
N[>rp
p
% chrome/content/xmlhttprequester.ff.jsfunction xbmciplayersender_xmlhttpRequester(unsafeContentWin, chromeWindow) {
this.unsafeContentWin = unsafeContentWin;
this.chromeWindow = chromeWindow;
}
// this function gets called by user scripts in content security scope to
// start a cross-domain xmlhttp request.
//
// details should look like:
// {method,url,onload,onerror,onreadystatechange,headers,data}
// headers should be in the form {name:value,name:value,etc}
// can't support mimetype because i think it's only used for forcing
// text/xml and we can't support that
xbmciplayersender_xmlhttpRequester.prototype.contentStartRequest = function(details) {
// important to store this locally so that content cannot trick us up with
// a fancy getter that checks the number of times it has been accessed,
// returning a dangerous URL the time that we actually use it.
var url = details.url;
// make sure that we have an actual string so that we can't be fooled with
// tricky toString() implementations.
if (typeof url != "string") {
throw new Error("Invalid url: url must be of type string");
}
var ioService=Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var scheme = ioService.extractScheme(url);
// This is important - without it, GM_xmlhttpRequest can be used to get
// access to things like files and chrome. Careful.
switch (scheme) {
case "http":
case "https":
case "ftp":
this.chromeWindow.setTimeout(
xbmciplayersender_gmCompiler.hitch(this, "chromeStartRequest", url, details), 0);
break;
default:
throw new Error("Invalid url: " + url);
}
}
// this function is intended to be called in chrome's security context, so
// that it can access other domains without security warning
xbmciplayersender_xmlhttpRequester.prototype.chromeStartRequest=function(safeUrl, details) {
var req = new this.chromeWindow.XMLHttpRequest();
this.setupRequestEvent(this.unsafeContentWin, req, "onload", details);
this.setupRequestEvent(this.unsafeContentWin, req, "onerror", details);
this.setupRequestEvent(this.unsafeContentWin, req, "onreadystatechange", details);
req.open(details.method, safeUrl);
dump('URL:' +safeUrl);
if (details.headers) {
for (var prop in details.headers) {
req.setRequestHeader(prop, details.headers[prop]);
}
}
req.send(details.data);
}
// arranges for the specified 'event' on xmlhttprequest 'req' to call the
// method by the same name which is a property of 'details' in the content
// window's security context.
xbmciplayersender_xmlhttpRequester.prototype.setupRequestEvent =
function(unsafeContentWin, req, event, details) {
if (details[event]) {
req[event] = function() {
var responseState = {
// can't support responseXML because security won't
// let the browser call properties on it
responseText:req.responseText,
readyState:req.readyState,
responseHeaders:(req.readyState==4?req.getAllResponseHeaders():''),
status:(req.readyState==4?req.status:0),
statusText:(req.readyState==4?req.statusText:'')
}
// Pop back onto browser thread and call event handler.
// Have to use nested function here instead of GM_hitch because
// otherwise details[event].apply can point to window.setTimeout, which
// can be abused to get increased priveledges.
new XPCNativeWrapper(unsafeContentWin, "setTimeout()")
.setTimeout(function(){details[event](responseState);}, 0);
}
}
}PK
N[>L
" chrome/content/xmlhttprequester.js
function xbmciplayersender_xmlhttpRequester(unsafeContentWin, chromeWindow) {
this.unsafeContentWin = unsafeContentWin;
this.chromeWindow = chromeWindow;
}
// this function gets called by user scripts in content security scope to
// start a cross-domain xmlhttp request.
//
// details should look like:
// {method,url,onload,onerror,onreadystatechange,headers,data}
// headers should be in the form {name:value,name:value,etc}
// can't support mimetype because i think it's only used for forcing
// text/xml and we can't support that
xbmciplayersender_xmlhttpRequester.prototype.contentStartRequest = function(details) {
// important to store this locally so that content cannot trick us up with
// a fancy getter that checks the number of times it has been accessed,
// returning a dangerous URL the time that we actually use it.
var url = details.url;
// make sure that we have an actual string so that we can't be fooled with
// tricky toString() implementations.
if (typeof url != "string") {
throw new Error("Invalid url: url must be of type string");
}
var ioService=Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var scheme = ioService.extractScheme(url);
// This is important - without it, GM_xmlhttpRequest can be used to get
// access to things like files and chrome. Careful.
switch (scheme) {
case "http":
case "https":
case "ftp":
this.chromeWindow.setTimeout(
xbmciplayersender_gmCompiler.hitch(this, "chromeStartRequest", url, details), 0);
break;
default:
throw new Error("Invalid url: " + url);
}
}
// this function is intended to be called in chrome's security context, so
// that it can access other domains without security warning
xbmciplayersender_xmlhttpRequester.prototype.chromeStartRequest=function(safeUrl, details) {
var req = new this.chromeWindow.XMLHttpRequest();
this.setupRequestEvent(this.unsafeContentWin, req, "onload", details);
this.setupRequestEvent(this.unsafeContentWin, req, "onerror", details);
this.setupRequestEvent(this.unsafeContentWin, req, "onreadystatechange", details);
req.open(details.method, safeUrl);
if (details.headers) {
for (var prop in details.headers) {
req.setRequestHeader(prop, details.headers[prop]);
}
}
req.send(details.data);
}
// arranges for the specified 'event' on xmlhttprequest 'req' to call the
// method by the same name which is a property of 'details' in the content
// window's security context.
xbmciplayersender_xmlhttpRequester.prototype.setupRequestEvent =
function(unsafeContentWin, req, event, details) {
if (details[event]) {
req[event] = function() {
var responseState = {
// can't support responseXML because security won't
// let the browser call properties on it
responseText:req.responseText,
readyState:req.readyState,
responseHeaders:(req.readyState==4?req.getAllResponseHeaders():''),
status:(req.readyState==4?req.status:0),
statusText:(req.readyState==4?req.statusText:'')
}
// Pop back onto browser thread and call event handler.
// Have to use nested function here instead of GM_hitch because
// otherwise details[event].apply can point to window.setTimeout, which
// can be abused to get increased priveledges.
new XPCNativeWrapper(unsafeContentWin, "setTimeout()")
.setTimeout(function(){details[event](responseState);}, 0);
}
}
}PK k> chrome/locale/PK k> chrome/locale/en-US/PK
N[>D#K K chrome/locale/en-US/contents.rdf
PK
N[>?L L ) chrome/locale/en-US/xbmciplayersender.dtd
PK
N[>>0+ + 0 chrome/locale/en-US/xbmciplayersender.propertiesextensions.uacontrol@qz.tsugumi.org.description=Control what gets sent as the User-Agent on a per-site basis.
StatusbarNoReferer=
ImportTitle=Import
ImportInvalidFileAlert=This is not a valid UAControl file.
ImportErrorAlert=Error importing from file
ExportTitle=Export
ExportErrorAlert=Error exporting to file
ConfirmRemoveAll=Are you sure you want to remove all sites?
SiteDefault=
ActionNormal=
ActionBlock=
SiteNotFilledInAlert=Site must be filled in.
SiteInvalidCharactersAlert=Invalid characters in site.
PK k> chrome/skin/PK
N[>H chrome/skin/contents.rdf
PK
N[>U{_) _) chrome/skin/icon.pngPNG
IHDR @ @ nAH iCCPICC Profile xTkA6n"Zkx"IYhE6bkEd3In6&*Ezd/JZE(ޫ(b-nL~7}ov
r4
Ril|Bj A4%UN$As{z[V{wwҶ@G*q
Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>infObN~N>!?F?aĆ=5`5_M'Tq.
VJp8dasZHOLn}&wVQygE0
HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K`m)m$``/]?[xFQT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs od IDATx{Uյwwzf^Q@@4|5&*֨DMy&h,Q#j<[@#%bTH 8s`$=}^}m۱pzu⚻WkgS
E~{sm%_lY*V[iݱ-bCwkC0vZ3C)aoν0+l6hi߰idߔicP5:[E!5+h?7t\M3BXy}%Go/Z8Ϝ)%8?()#^9Ԕ՜o/U~C~' <T<__w/>{x)P{3lMyS~