Redirector is an extension for Firefox that allows you to automatically redirect from
+ one webpage to another. For example, every time you visit http://abc.com you will automatically
+ load http://def.com instead. This can be useful for instance to always redirect articles to printer friendly
+ versions, redirect http:// to https:// for sites that support both, bypass advertising pages that appear before
+ being able to view certain pages and more.
+
+
+
Basic usage
+
To add a new redirect you can go to the Tools menuitem and select Redirector. That will
+ open the Redirector settings window which shows all your redirects. The window can also be opened
+ by right clicking on the R icon in your statusbar.
+ There you can press the Add... button and then you can enter the details for the new redirect. A redirect
+ consists of a few things:
+
+
Example url: This is an example of an url you want to redirect. It is not really used for anything,
+ it's just there to show what types of urls you're targetting. You can leave this out, but then you can't use the Test pattern button.
+
+
Include pattern: This is pattern for the urls you want to redirect. In the simplest case, where you just want
+ to redirect one specific url to another then this will just be the exact url you want to redirect. For instance, if you just want http://aaa.com to
+ redirect to http://bbb.com then Include pattern will just be http://aaa.com. For more complex patterns that match many
+ urls you can use either wildcards or regular expressions.
+
+
Exclude pattern: Urls that match this pattern will never be redirected. This is not necessary to
+ fill out, but can be useful when you want to redirect all urls that contain some text except if they contain some other text.
+ Redirects like that can often be done with a complex regular expression, but using an exclude pattern makes it much simpler. The exclude
+ patterns can use wildcard characters or regular expressions like the include patterns.
+
+
Redirect to: This is the url that you will be redirected to when you open any page where the url matches the
+ include pattern. You can use the special signs $1, $2, $3 etc. in the url, they will be replaced by the results of captures with regular
+ expressions or stars with wildcards. For instance, if you have the include pattern http://google.com/*, redirect to http://froogle.com/$1
+ and you open the page http://google.com/foobar, then you will be redireced to http://froogle.com/foobar, since 'foobar' was what the star replaced. $1 is for the
+ first star in the pattern, $2 for the second and so on. For regular expression $1 is for the first parantheses, $2 for the second etc.
+
+
Pattern type: This specifies how Redirector should interpret the patterns, either as
+ wildcards or regular expressions.
+
+
Unescape matches: A common usage of Redirector is to catch urls like
+ http://foo.com/redirect.php?url=http%3A%2F%2Fbar%2Ecom%2Fpath and try to catch the url parameter and redirect to it. A pattern
+ like http://foo.com/redirect.php?url=* might be used for that purpose. However, if the url parameter is escaped (also known
+ as urlencoded) then that won't work. In the url above we see that it starts with http%3A%2F%2F instead of http://, and Firefox
+ won't accept this as a new url to redirect to. So, in cases like these you can check the Unescape matches option and then all
+ matches will be unescaped (turned from e.g. http%3A%2F%2Fbar%2Ecom to http://bar.com) before being inserted into the target url.
+
+
+
+
+
+
+
Wildcards
+
+
Wildcards are the simplest way to specify include and exclude patterns. When you create a wildcard pattern there
+ is just one special character, the asterisk *. An asterisk in your pattern will match zero or more characters and you can
+ have more than one star in your pattern. Some examples:
+
+
http://example.com/* matches http://example.com/, http://example.com/foo, http://example.com/bar and all other urls that start with http://example.com/.
+
http://*.example.com matches all subdomains of example.com, like http://www.example.com, http://mail.example.com.
+
http*://example.com matches both http://example.com and https://example.com.
+ $1, $2, $3 in the redirect urls will match the text that the stars matched. Examples:
+
+
http://example.com/* matches http://example.com/foobar, $1 is foobar.
+
http://*.example.com/* matches http://www.example.com/foobar, $1 is www, $2 is foobar.
+
+
+
+
+
Regular expressions
+
+
Regular expressions allow for more complicated patterns but they are a lot harder to learn than wildcards. I'm not gonna
+ create a regex tutorial here but normal javascript regex syntax works, look at http://regular-expressions.info for
+ an introduction to regular expressions. $1,$2 etc. can be used in the redirect url and will be replaced with contents of captures in
+ the regular expressions. Captures are specified with parantheses. Example: http://example.com/index.asp\?id=(\d+) will match the url
+ http://example.com/index.asp?id=12345 and $1 will be replaced by 12345. (A common mistake in regex patterns is to forget to escape
+ the ? sign in the querystring of the url. ? is a special character in regular expressions so if you want to match an url with a querystring
+ you should escape it as \?).
+
+
+
Examples
+
+
+
+ Static redirect
+ Redirects from http://example.com/foo to http://example.com/bar
+
+ Include pattern: http://example.com/foo
+ Exclude pattern:
+ Redirect to: http://example.com/bar
+ Pattern type: Wildcard
+
+
+
+
+ Redirect using query string parameter and wildcards
+ Redirects from http://example.com/index.php?id=12345&a=b to http://example.com/printerfriendly.php?id=12345&a=b
+ where 12345 could be any number.
+
+ Include pattern: http://example.com/index.php?id=*&a=b
+ Exclude pattern:
+ Redirect to: http://example.com/printerfriendly.com?id=$1&a=b
+ Pattern type: Wildcard
+
+
+
+ Redirect using query string parameter and regular expressions
+ Redirects from http://example.com/index.php?id=12345&a=b to http://example.com/printerfriendly.php?id=12345&a=b
+ where 12345 could be any number.
+
+ Include pattern: http://example.com/index.php\?id=(\d+)&a=b
+ Exclude pattern:
+ Redirect to: http://example.com/printerfriendly.com?id=$1&a=b
+ Pattern type: Regular Expression
+
+
+
+ Redirect to a different folder using wildcards
+ Redirects from http://example.com/category/fish/index.php to http://example.com/category/cats/index.php
+ where fish could be any word. The exclude pattern makes sure that there is only one
+ folder there, so for instance http://example.com/category/fish/cat/mouse/index.php would not match.
+
+ Include pattern: http://example.com/category/*/index.php
+ Exclude pattern: http://example.com/category/*/*/index.php
+ Redirect to: http://example.com/category/cats/index.php
+ Pattern type: Wildcard
+
+
+
+ Redirect http to https using wildcards
+ Redirects from http://mail.google.com/randomcharacters to https://mail.google.com/randomcharacters
+ where randomcharacters could be anything.
+
+ Include pattern: http://mail.google.com*
+ Exclude pattern:
+ Redirect to: https://mail.google.com$1
+ Pattern type: Wildcard
+
+
+
+
+
\ No newline at end of file
diff --git a/chrome/images/redirector.png b/chrome/images/redirector.png
new file mode 100644
index 0000000..f8de12c
Binary files /dev/null and b/chrome/images/redirector.png differ
diff --git a/chrome/images/statusactive.png b/chrome/images/statusactive.png
new file mode 100644
index 0000000..06ce766
Binary files /dev/null and b/chrome/images/statusactive.png differ
diff --git a/chrome/images/statusinactive.png b/chrome/images/statusinactive.png
new file mode 100644
index 0000000..8b83562
Binary files /dev/null and b/chrome/images/statusinactive.png differ
diff --git a/chrome/js/browserOverlay.js b/chrome/js/browserOverlay.js
new file mode 100644
index 0000000..ed1ab73
--- /dev/null
+++ b/chrome/js/browserOverlay.js
@@ -0,0 +1,95 @@
+Components.utils.import("chrome://redirector/content/js/redirectorprefs.js");
+Components.utils.import("chrome://redirector/content/js/redirector.js");
+
+var RedirectorOverlay = {
+
+ strings : null,
+ prefs : null,
+
+ onLoad : function(event) {
+ try {
+
+ // initialization code
+ document.getElementById('contentAreaContextMenu')
+ .addEventListener("popupshowing", function(e) { RedirectorOverlay.showContextMenu(e); }, false);
+
+ this.strings = document.getElementById("redirector-strings");
+ this.prefs = new RedirectorPrefs();
+ this.changedPrefs(this.prefs);
+ this.prefs.addListener(this);
+ document.addEventListener('keypress', function(event) {
+ if ((event.charCode == 114) && event.altKey) { //alt+r
+ RedirectorOverlay.toggleEnabled();
+ }
+ }, true);
+ } catch(e) {
+ if (this.strings) {
+ alert(this.strings.getString("initError") + "\n\n" + e);
+ } else {
+ alert(e);
+ }
+ }
+ },
+
+ onUnload : function(event) {
+ this.prefs.dispose();
+ Redirector.debug("Finished cleanup");
+ },
+
+ changedPrefs : function(prefs) {
+ var statusImg = document.getElementById('redirector-statusbar-img');
+
+ if (prefs.enabled) {
+ statusImg.src = 'chrome://redirector/content/images/statusactive.png'
+ statusImg.setAttribute('tooltiptext', this.strings.getString('enabledTooltip'));
+ } else {
+ statusImg.src = 'chrome://redirector/content/images/statusinactive.png'
+ statusImg.setAttribute('tooltiptext', this.strings.getString('disabledTooltip'));
+ }
+
+ document.getElementById('redirector-status').hidden = !prefs.showStatusBarIcon;
+ document.getElementById('redirector-context').hidden = !prefs.showContextMenu;
+ },
+
+ showContextMenu : function(event) {
+ if (gContextMenu.onLink) {
+ document.getElementById("redirector-context").label = this.strings.getString('addLinkUrl');
+ } else {
+ document.getElementById("redirector-context").label = this.strings.getString('addCurrentUrl');
+ }
+ },
+
+ onContextMenuCommand: function(event) {
+ var redirect = new Redirect(window.content.location.href, window.content.location.href);
+ if (gContextMenu.onLink) {
+ redirect.redirectUrl = gContextMenu.link.toString();
+ }
+
+ gBrowser.selectedTab = gBrowser.addTab("chrome://redirector/content/redirector.html");
+ },
+
+ onMenuItemCommand: function(event) {
+ this.openSettings();
+ },
+
+ toggleEnabled : function(event) {
+ this.prefs.enabled = !this.prefs.enabled;
+ },
+
+ openSettings : function() {
+ gBrowser.selectedTab = gBrowser.addTab("chrome://redirector/content/redirector.html");
+ },
+
+ statusBarClick : function(event) {
+ var LEFT = 0, RIGHT = 2;
+
+ if (event.button == LEFT) {
+ RedirectorOverlay.toggleEnabled();
+ } else if (event.button == RIGHT) {
+ this.openSettings();
+ }
+ }
+
+};
+window.addEventListener("load", function(event) { RedirectorOverlay.onLoad(event); }, false);
+window.addEventListener("unload", function(event) { RedirectorOverlay.onUnload(event); }, false);
diff --git a/chrome/js/component.js b/chrome/js/component.js
new file mode 100644
index 0000000..7b19109
--- /dev/null
+++ b/chrome/js/component.js
@@ -0,0 +1,21 @@
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Ci = Components.interfaces;
+Cr = Components.results;
+
+Components.utils.import("chrome://redirector/content/js/redirector.js");
+
+function RedirectorComponent() { }
+
+RedirectorComponent.prototype = {
+ classDescription: "My Hello World Javascript XPCOM Component",
+ classID: Components.ID("{b7a7a54f-0581-47ff-b086-d6920cb7a3f7}"),
+ contractID: "@einaregilsson.com/redirector;1",
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIContentPolicy) || iid.equals(Ci.nsIChannelEventSink)) {
+ return Redirector;
+ }
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ }
+};
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([RedirectorComponent]);
diff --git a/chrome/js/proxyserver.js b/chrome/js/proxyserver.js
new file mode 100644
index 0000000..4881f59
--- /dev/null
+++ b/chrome/js/proxyserver.js
@@ -0,0 +1,58 @@
+Components.utils.import("chrome://redirector/content/js/xpcom.js");
+
+var EXPORTED_SYMBOLS = ['RedirectorProxy'];
+
+var RedirectorProxy = {
+
+ start : function(port, getUrl) {
+ dump('Opening Proxy Server Socket on port ' + port);
+ this.getUrl = getUrl;
+ this.serverSocket = new ServerSocket(port, true, -1);
+ this.serverSocket.asyncListen(this);
+ },
+
+ onSocketAccepted: function(serverSocket, clientSocket) {
+ dump("Accepted connection on "+clientSocket.host+":"+clientSocket.port);
+ var requestStream = clientSocket.openInputStream(0, 0, 0).QueryInterface(Ci.nsIAsyncInputStream);
+ var responseStream = clientSocket.openOutputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0);
+ var tm = Cc["@mozilla.org/thread-manager;1"].getService();
+ requestStream.asyncWait({
+ onInputStreamReady : function(inputStream) {
+ RedirectorProxy.processRequest(clientSocket, inputStream, responseStream);
+ }
+ },0,0,tm.mainThread);
+ },
+
+ processRequest : function(clientSocket, inputStream, responseStream) {
+ var requestStream = new ScriptableInputStream(inputStream);
+ requestStream.available();
+ var request = '';
+ while (requestStream.available()) {
+ request = request + requestStream.read(2048);
+ }
+ var parts = request.split(' ');
+ dump('\n\n\n' + request + '\n\n\n');
+ dump("\n" + parts[0] + " request for " + parts[1]);
+ var redirectUrl = 'http://einaregilsson.com';//Redirector.getRedirectUrl(parts[1]);
+ var outp = 'HTTP/1.1 302 Moved Temporarily';
+ outp += '\r\nContent-Length: ';
+ outp += '\r\nLocation: ' + redirectUrl;
+ outp += '\r\nX-Redirected-By: Redirector Firefox Extension'
+ outp += '\r\n\r\n';
+ var cl = outp.length -4;
+ if (cl < 100) {
+ cl+=2;
+ } else if (cl < 1000) {
+ cl += 3;
+ } else if (cl < 10000) {
+ cl += 4;
+ } else if (cl < 100000) {
+ cl += 5;
+ }
+ outp = outp.replace('', cl);
+ dump(outp);
+ responseStream.write(outp, outp.length);
+ responseStream.close();
+ inputStream.close();
+ }
+}
\ No newline at end of file
diff --git a/chrome/js/redirect.js b/chrome/js/redirect.js
new file mode 100644
index 0000000..8b0b1d2
--- /dev/null
+++ b/chrome/js/redirect.js
@@ -0,0 +1,213 @@
+
+var EXPORTED_SYMBOLS = ['Redirect'];
+
+
+function Redirect(exampleUrl, includePattern, redirectUrl, patternType, excludePattern, unescapeMatches, disabled) {
+ this._init(exampleUrl, includePattern, redirectUrl, patternType, excludePattern, unescapeMatches, disabled);
+}
+
+//Static
+Redirect.WILDCARD = 'W';
+Redirect.REGEX = 'R';
+
+Redirect.prototype = {
+
+ //attributes
+ exampleUrl : null,
+
+ get includePattern() { return this._includePattern; },
+ set includePattern(value) {
+ this._includePattern = value;
+ this._rxInclude = this._compile(value);
+ },
+
+ get excludePattern() { return this._excludePattern; },
+ set excludePattern(value) {
+ this._excludePattern = value;
+ this._rxExclude = this._compile(value);
+ },
+
+ redirectUrl : null,
+
+ get patternType() { return this._patternType; },
+ set patternType(value) {
+ this._patternType = value;
+ this.compile();
+ },
+
+ unescapeMatches : false,
+
+ disabled : false,
+
+ //Functions
+ clone : function() {
+ return new Redirect().fromObject(this.toObject());
+ },
+
+ compile : function() {
+ this._rxInclude = this._compile(this._includePattern);
+ this._rxExclude = this._compile(this._excludePattern);
+ },
+
+ toObject : function() {
+ return {
+ exampleUrl : this.exampleUrl,
+ includePattern : this.includePattern,
+ excludePattern : this.excludePattern,
+ redirectUrl : this.redirectUrl,
+ patternType : this.patternType,
+ unescapeMatches : this.unescapeMatches,
+ disabled : !!this.disabled
+ };
+ },
+
+ fromObject : function(o) {
+ for (var prop in o) {
+ this[prop] = o[prop];
+ }
+ return this;
+ },
+
+ copyValues : function(other) {
+ this.exampleUrl = other.exampleUrl;
+ this.includePattern = other.includePattern;
+ this.excludePattern = other.excludePattern;
+ this.redirectUrl = other.redirectUrl;
+ this.patternType = other.patternType;
+ this.unescapeMatches = other.unescapeMatches;
+ this.disabled = other.disabled;
+ },
+
+ equals : function(redirect) {
+ return this.exampleUrl == redirect.exampleUrl
+ && this.includePattern == redirect.includePattern
+ && this.excludePattern == redirect.excludePattern
+ && this.redirectUrl == redirect.redirectUrl
+ && this.patternType == redirect.patternType
+ && this.unescapeMatches == redirect.unescapeMatches
+ ;
+ },
+
+ getMatch: function(url) {
+ var result = {
+ isMatch : false,
+ isExcludeMatch : false,
+ isDisabledMatch : false,
+ redirectTo : '',
+ toString : function() { return "{ isMatch : " + this.isMatch +
+ ", isExcludeMatch : " + this.isExcludeMatch +
+ ", isDisabledMatch : " + this.isDisabledMatch +
+ ", redirectTo : \"" + this.redirectTo + "\"" +
+ "}"; }
+ };
+ var redirectTo = null;
+
+ redirectTo = this._includeMatch(url);
+ if (redirectTo !== null) {
+ if (this.disabled) {
+ result.isDisabledMatch = true;
+ } else if (this._excludeMatch(url)) {
+ result.isExcludeMatch = true;
+ } else {
+ result.isMatch = true;
+ result.redirectTo = redirectTo;
+ }
+ }
+ return result;
+ },
+
+ isRegex: function() {
+ return this.patternType == Redirect.REGEX;
+ },
+
+ isWildcard : function() {
+ return this.patternType == Redirect.WILDCARD;
+ },
+
+ test : function() {
+ return this.getMatch(this.exampleUrl);
+ },
+
+
+ //Private functions below
+
+ _includePattern : null,
+ _excludePattern : null,
+ _patternType : null,
+ _rxInclude : null,
+ _rxExclude : null,
+
+ _preparePattern : function(pattern) {
+ if (this.patternType == Redirect.REGEX) {
+ return pattern;
+ } else { //Convert wildcard to regex pattern
+ var converted = '^';
+ for (var i = 0; i < pattern.length; i++) {
+ var ch = pattern.charAt(i);
+ if ('()[]{}?.^$\\+'.indexOf(ch) != -1) {
+ converted += '\\' + ch;
+ } else if (ch == '*') {
+ converted += '(.*?)';
+ } else {
+ converted += ch;
+ }
+ }
+ converted += '$';
+ return converted;
+ }
+ },
+
+ _compile : function(pattern) {
+ if (!pattern) {
+ return null;
+ }
+ return new RegExp(this._preparePattern(pattern),"gi");
+ },
+
+ _init : function(exampleUrl, includePattern, redirectUrl, patternType, excludePattern, unescapeMatches, disabled) {
+ this.exampleUrl = exampleUrl || '';
+ this.includePattern = includePattern || '';
+ this.excludePattern = excludePattern || '';
+ this.redirectUrl = redirectUrl || '';
+ this.patternType = patternType || Redirect.WILDCARD;
+ this.unescapeMatches = (unescapeMatches === 'true' || unescapeMatches === true);
+ this.disabled = (disabled === 'true' || disabled === true);
+ },
+
+ toString : function() {
+ return 'REDIRECT: {'
+ + '\n\tExample url : ' + this.exampleUrl
+ + '\n\tInclude pattern : ' + this.includePattern
+ + '\n\tExclude pattern : ' + this.excludePattern
+ + '\n\tRedirect url : ' + this.redirectUrl
+ + '\n\tPattern type : ' + this.patternType
+ + '\n\tUnescape matches : ' + this.unescapeMatches
+ + '\n\tDisabled : ' + this.disabled
+ + '\n}\n';
+ },
+
+ _includeMatch : function(url) {
+ if (!this._rxInclude) {
+ return null;
+ }
+ var matches = this._rxInclude.exec(url);
+ if (!matches) {
+ return null;
+ }
+ var resultUrl = this.redirectUrl;
+ for (var i = 1; i < matches.length; i++) {
+ resultUrl = resultUrl.replace(new RegExp('\\$' + i, 'gi'), this.unescapeMatches ? unescape(matches[i]) : matches[i]);
+ }
+ this._rxInclude.lastIndex = 0;
+ return resultUrl;
+ },
+
+ _excludeMatch : function(url) {
+ if (!this._rxExclude) {
+ return false;
+ }
+ var shouldExclude = !!this._rxExclude.exec(url);
+ this._rxExclude.lastIndex = 0;
+ return shouldExclude;
+ }
+};
\ No newline at end of file
diff --git a/chrome/js/redirector-ui.js b/chrome/js/redirector-ui.js
new file mode 100644
index 0000000..e0a5d07
--- /dev/null
+++ b/chrome/js/redirector-ui.js
@@ -0,0 +1,207 @@
+Components.utils.import("chrome://redirector/content/js/redirector.js");
+Components.utils.import("chrome://redirector/content/js/redirectorprefs.js");
+Components.utils.import("chrome://redirector/content/js/xpcom.js");
+
+$(document).ready(function() {
+ var prefs = new RedirectorPrefs();
+ var strings = StringBundleService.createBundle('chrome://redirector/locale/redirector.properties', LocaleService.getApplicationLocale());
+ function tr(name) {
+ return strings.GetStringFromName(name);
+ }
+
+ function trPlural(name, count) {
+ name += count == 1 ? 'Singular' : '';
+ return strings.formatStringFromName(name, [count],1);
+ }
+
+ function getFile(captionKey, mode) {
+ var picker = new FilePicker(window, tr(captionKey), mode);
+ picker.defaultExtension = ".rjson";
+ var dir = prefs.defaultDir;
+ if (dir) {
+ picker.displayDirectory = new LocalFile(dir);
+ }
+ picker.appendFilter(tr('redirectorFiles'), '*.rjson');
+
+ if (picker.show() == picker.returnCancel) {
+ return null;
+ }
+ prefs.defaultDir = picker.displayDirectory.path;
+ return picker.file;
+ }
+
+ function exportRedirects() {
+ var file = getFile('exportCaption', FilePickerMode.save);
+ if (file) {
+ Redirector.exportRedirects(file);
+ }
+ }
+
+ function importRedirects() {
+ var file = getFile('importCaption', FilePickerMode.open);
+ var result;
+ if (!file) {
+ return;
+ }
+ result = Redirector.importRedirects(file);
+ var msg, imported, existed;
+ imported = result & 0xFFFF;
+ existed = result >> 16;
+
+ if (imported > 0) {
+ msg = trPlural('importedMessage', imported);
+ if (existed > 0) {
+ msg += ', ' + trPlural('existedMessage',existed);
+ } else {
+ msg += '.';
+ }
+ } else if (imported == 0 && existed > 0) {
+ msg = trPlural('allExistedMessage', existed);
+ } else { //Both 0
+ msg = tr('importedNone');
+ }
+
+ var title = tr('importResult');
+ PromptService.alert(null, title, msg);
+
+ if (imported > 0) {
+ var newlist = [];
+ for (var i = Redirector.redirectCount-imported; i < Redirector.redirectCount; i++) {
+ newlist.push(Redirector.getRedirectAt(i));
+ }
+ }
+ }
+
+ var template = $('#redirect-list').html().replace(/^\s*|\s$/g, '');
+ function databind() {
+ $('#redirect-list').empty();
+ for (var i = 0; i < Redirector.redirectCount; i++) {
+ var redirect = Redirector.getRedirectAt(i);
+ var node = $(template);
+ node.find('.pattern').html(redirect.includePattern);
+ node.find('.redirectTo').html(redirect.redirectUrl);
+ node.find('.exampleUrl').html(redirect.exampleUrl);
+ node.find('.redirectResult').html(redirect.getMatch(redirect.exampleUrl).redirectTo);
+ node.appendTo('#redirect-list');
+ node.data('redirect', redirect);
+ }
+
+ }
+
+ $('#redirect-list li div a.delete').live('click', function(ev) {
+ var redirect = $(this.parentNode.parentNode).data('redirect');
+ if (PromptService.confirm(null, tr("deleteConfirmationTitle"), tr("deleteConfirmationText"))) {
+ Redirector.deleteRedirect(redirect);
+ $(this.parentNode.parentNode).fadeOut(function() { $(this).remove(); });
+ }
+ ev.preventDefault();
+ });
+
+ $('#redirect-list li div a.edit').live('click', function(ev) {
+ var redirect = $(this.parentNode.parentNode).data('redirect');
+ $('#redirect-form').show();
+ ev.preventDefault();
+ });
+
+ databind();
+ $('#import').click(importRedirects);
+ $('#export').click(exportRedirects);
+
+ function bindConfig() {
+ $('#config input[type="checkbox"]').each(function() {
+ var pref = $(this).attr('data-pref');
+ $(this).attr('checked', prefs[pref]);
+ });
+ }
+
+ bindConfig();
+ prefs.addListener({ changedPrefs:bindConfig});
+
+ var movingElement = null;
+ $('li').mousedown(function(ev) {
+ if (ev.target && ev.target.tagName == 'A') {
+ return;
+ }
+ $(this).css('background', '-moz-linear-gradient(top, #aac, #99b)');
+ $('#redirect-list').css('cursor', 'move');
+ movingElement = this;
+ });
+
+
+ $('li').mouseover(function() {
+ if (movingElement && this !== movingElement) {
+ if ($(movingElement).offset().top > $(this).offset().top) {
+ $(movingElement).detach().insertBefore(this);
+ } else {
+ $(movingElement).detach().insertAfter(this);
+ }
+ }
+ });
+
+ $(document).mouseup(function() {
+ if (movingElement) {
+ $(movingElement).css('background', '');
+ movingElement = null;
+ $('#redirect-list').css('cursor', '');
+ var newOrder = {};
+ $('#redirect-list li').each(function(i) {
+ newOrder[$(this).data('redirect')] = i;
+ });
+
+ Redirector.sortRedirects(function(a,b) {
+ return newOrder[a] - newOrder[b];
+ });
+ }
+ });
+
+ $('#config input[type="checkbox"]').bind('CheckboxStateChange', function() {
+ var pref = $(this).attr('data-pref');
+ prefs[pref] = !!$(this).attr('checked');
+ });
+});
+
+/*
+ testPattern : function() {
+ try {
+ var redirect = new Redirect();
+ this.saveValues(redirect);
+ var extName = this.strings.getString('extensionName');
+ var result = redirect.test();
+ if (result.isMatch) {
+ this.msgBox(extName, this.strings.getFormattedString('testPatternSuccess', [redirect.includePattern, redirect.exampleUrl, result.redirectTo]));
+ } else if (result.isExcludeMatch) {
+ this.msgBox(extName, this.strings.getFormattedString('testPatternExclude', [redirect.exampleUrl, redirect.excludePattern]));
+ } else {
+ this.msgBox(extName, this.strings.getFormattedString('testPatternFailure', [redirect.includePattern, redirect.exampleUrl]));
+ }
+ } catch(e) {alert(e);}
+ }
+
+ if (!/^\s*$/.test(args.redirect.exampleUrl)) {
+ var result = args.redirect.getMatch(args.redirect.exampleUrl);
+ if (!result.isMatch) {
+ title = this.strings.getString('warningExampleUrlDoesntMatchPatternTitle');
+ msg = this.strings.getString('warningExampleUrlDoesntMatchPattern');
+ var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
+ var rv = ps.confirmEx(window, title, msg, ps.STD_YES_NO_BUTTONS, ps.BUTTON_TITLE_YES, ps.BUTTON_TITLE_NO, null, null, {});
+ return rv == 0;
+ } else {
+ var resultUrl = result.redirectTo;
+ if (!resultUrl.match(/https?:/)) {
+ var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
+ var uri = ioService.newURI(args.redirect.exampleUrl, null, null);
+ resultUrl = uri.resolve(resultUrl);
+ }
+
+ var secondResult = args.redirect.getMatch(resultUrl);
+ if (secondResult.isMatch) {
+ title = this.strings.getString('errorExampleUrlMatchesRecursiveTitle');
+ msg = this.strings.getFormattedString('errorExampleUrlMatchesRecursive', [args.redirect.exampleUrl, resultUrl]);
+ this.msgBox(title, msg);
+ return false;
+ }
+ }
+ }
+
+
+*/
\ No newline at end of file
diff --git a/chrome/js/redirector.js b/chrome/js/redirector.js
new file mode 100644
index 0000000..21268e6
--- /dev/null
+++ b/chrome/js/redirector.js
@@ -0,0 +1,366 @@
+Components.utils.import("chrome://redirector/content/js/xpcom.js");
+Components.utils.import("chrome://redirector/content/js/redirect.js");
+Components.utils.import("chrome://redirector/content/js/redirectorprefs.js");
+Components.utils.import("chrome://redirector/content/js/proxyserver.js");
+
+var EXPORTED_SYMBOLS = ['Redirector', 'rdump'];
+
+function rdump(msg) {
+ //dump(msg + '\n');
+}
+
+Redirector = {
+
+ get enabled() {
+ return this._prefs && this._prefs.enabled;
+ },
+
+ set enabled(value) {
+ if (this._prefs) {
+ this._prefs.enabled = value;
+ }
+ },
+
+ get redirectCount() {
+ return this._list.length;
+ },
+
+ toString : function() {
+ return "Redirector";
+ },
+
+ addRedirect : function(redirect) {
+ this._list.push(redirect);
+ this.save();
+ },
+
+ debug : function(msg) {
+ if (this._prefs.debugEnabled) {
+ this._cout.logStringMessage('REDIRECTOR: ' + msg);
+ }
+ },
+
+ deleteRedirect : function(redirect) {
+ this._list.splice(this._list.indexOf(redirect), 1);
+ this.save();
+ },
+
+ exportRedirects : function(file) {
+ var fileStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
+ const PR_WRONLY = 0x02;
+ const PR_CREATE_FILE = 0x08;
+ const PR_TRUNCATE = 0x20;
+
+ fileStream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0644, 0);
+ var stream = Cc["@mozilla.org/intl/converter-output-stream;1"].createInstance(Ci.nsIConverterOutputStream);
+ stream.init(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
+ var rjson = { createdBy : 'Redirector v' + this._prefs.version, createdAt : new Date(), redirects :[]};
+ for each (var re in this._list) {
+ rjson.redirects.push(re.toObject());
+ }
+ stream.writeString(JSON.stringify(rjson, null, 4));
+ stream.close();
+ },
+
+ getRedirectAt : function(index) {
+ return this._list[index];
+ },
+
+ //Get the redirect url for the given url. This will not check if we are enabled, and
+ //not do any verification on the url, just assume that it is a good string url that is for http/s
+ getRedirectUrl : function(url) {
+ this.debug("Checking " + url);
+
+ for each (var redirect in this._list) {
+ var result = redirect.getMatch(url);
+ if (result.isExcludeMatch) {
+ this.debug(url + ' matched exclude pattern ' + redirect.excludePattern + ' so the redirect ' + redirect.includePattern + ' will not be used');
+ } else if (result.isDisabledMatch) {
+ this.debug(url + ' matched pattern ' + redirect.includePattern + ' but the redirect is disabled');
+ } else if (result.isMatch) {
+ redirectUrl = this._makeAbsoluteUrl(url, result.redirectTo);
+
+ //check for loops...
+ result = redirect.getMatch(redirectUrl);
+ if (result.isMatch) {
+ var title = this._getString('invalidRedirectTitle');
+ var msg = this._getFormattedString('invalidRedirectText', [redirect.includePattern, url, redirectUrl]);
+ this.debug(msg);
+ redirect.disabled = true;
+ this.save();
+ this._msgBox(title, msg);
+ } else {
+ this.debug('Redirecting ' + url + ' to ' + redirectUrl);
+ return redirectUrl;
+ }
+ }
+ }
+ return null;
+ },
+
+ QueryInterface: function(iid) {
+ if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIContentPolicy) || iid.equals(Ci.nsIChannelEventSink)) {
+ return this;
+ }
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ },
+
+ _getRedirectsFile : function() {
+ var file = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("ProfD", Ci.nsIFile);
+ file.append('redirector.rjson');
+ return file;
+ },
+
+ handleUpgrades : function(){
+ var currentVersion = '2.6';
+ this._list = [];
+
+ if (this._prefs.version == currentVersion) {
+ return;
+ }
+ //Here update checks are handled
+
+ try {
+ var branch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("extensions.redirector.");
+ var data = branch.getCharPref("redirects");
+ } catch(e) {
+ this._prefs.version = currentVersion;
+ return;
+ }
+ var arr;
+ this._list = [];
+ if (data != '') {
+ for each (redirectString in data.split(':::')) {
+ if (!redirectString || !redirectString.split) {
+ continue;
+ rdump('Invalid old redirect: ' + redirectString);
+ }
+ var parts = redirectString.split(',,,');
+ if (parts.length < 5) {
+ throw Error("Invalid serialized redirect, too few fields: " + redirectString);
+ }
+ var redirect = new Redirect();
+ redirect._init.apply(redirect, parts);
+ this._list.push(redirect);
+ }
+ this.save();
+ this._list = []; //Let the real loading start this properly
+ }
+ branch.deleteBranch('redirects');
+ this._prefs.version = currentVersion;
+ },
+
+ importRedirects : function(file) {
+ var fileStream = new FileInputStream(file, 0x01, 0444, 0);
+ var stream = new ConverterInputStream(fileStream, "UTF-8", 16384, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
+ var str = {};
+ var rjson = '';
+ while (stream.readString(4096, str) != 0) {
+ rjson += str.value;
+ }
+ stream.close();
+ var importCount = 0, existsCount = 0;
+ rjson = JSON.parse(rjson);
+ for each (var rd in rjson.redirects) {
+ var redirect = new Redirect();
+ redirect.fromObject(rd);
+ if (this._containsRedirect(redirect)) {
+ existsCount++;
+ } else {
+ this._list.push(redirect);
+ importCount++;
+ }
+ }
+ this.save();
+ return importCount | (existsCount << 16);
+ },
+
+ save : function() {
+ var file = this._getRedirectsFile();
+ this.exportRedirects(file);
+ },
+
+ sortRedirects : function(sortFunc) {
+ this._list.sort(sortFunc);
+ this.save();
+ },
+
+ // nsIContentPolicy implementation
+ shouldLoad: function(contentType, contentLocation, requestOrigin, aContext, mimeTypeGuess, extra) {
+ if (contentLocation.scheme != "http" && contentLocation.scheme != "https") {
+ return Ci.nsIContentPolicy.ACCEPT;
+ } //Immediately, otherwise we will log all sorts of crap
+
+ rdump('nsIContentPolicy::ShouldLoad ' + contentLocation.spec);
+ try {
+ //This is also done in getRedirectUrl, but we want to exit as quickly as possible for performance
+ if (!this._prefs.enabled) {
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+
+ if (contentType != Ci.nsIContentPolicy.TYPE_DOCUMENT) {
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+
+ if (contentLocation.scheme != "http" && contentLocation.scheme != "https") {
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+
+ if (!aContext || !aContext.loadURI) {
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+
+ var redirectUrl = this.getRedirectUrl(contentLocation.spec);
+
+ if (!redirectUrl) {
+ return Ci.nsIContentPolicy.ACCEPT;
+ }
+
+ aContext.loadURI(redirectUrl, requestOrigin, null);
+ return Ci.nsIContentPolicy.REJECT_REQUEST;
+ } catch(e) {
+ this.debug(e);
+ }
+
+ },
+
+ shouldProcess: function(contentType, contentLocation, requestOrigin, insecNode, mimeType, extra) {
+ return Ci.nsIContentPolicy.ACCEPT;
+ },
+ //end nsIContentPolicy
+
+ //nsIChannelEventSink implementation
+
+ //For FF4.0. Got this from a thread about adblock plus, https://adblockplus.org/forum/viewtopic.php?t=5895
+ asyncOnChannelRedirect: function(oldChannel, newChannel, flags, redirectCallback) {
+ this.onChannelRedirect(oldChannel, newChannel, flags);
+ redirectCallback.onRedirectVerifyCallback(0);
+ },
+
+ onChannelRedirect: function(oldChannel, newChannel, flags)
+ {
+ try {
+ let newLocation = newChannel.URI.spec;
+ rdump('nsIChannelEventSink::onChannelRedirect ' + newLocation);
+
+ if (!(newChannel.loadFlags & Ci.nsIChannel.LOAD_DOCUMENT_URI)) {
+ //We only redirect documents...
+ return;
+ }
+
+ if (!this._prefs.enabled) {
+ return;
+ }
+
+ if (!newLocation) {
+ return;
+ }
+ let callbacks = [];
+ if (newChannel.notificationCallbacks) {
+ callbacks.push(newChannel.notificationCallbacks);
+ }
+ if (newChannel.loadGroup && newChannel.loadGroup.notificationCallbacks) {
+ callbacks.push(newChannel.loadGroup.notificationCallbacks);
+ }
+ var win;
+ var webNav;
+ for each (let callback in callbacks)
+ {
+ try {
+ win = callback.getInterface(Ci.nsILoadContext).associatedWindow;
+ webNav = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation);
+ break;
+ } catch(e) {}
+ }
+ if (!webNav) {
+ return;
+ }
+ var redirectUrl = this.getRedirectUrl(newLocation);
+
+ if (redirectUrl) {
+ webNav.loadURI(redirectUrl,null,null,null,null);
+ throw Cr.NS_BASE_STREAM_WOULD_BLOCK; //Throw this because the real error we should throw shows up in console...
+ }
+
+ } catch (e if (e != Cr.NS_BASE_STREAM_WOULD_BLOCK)) {
+ // We shouldn't throw exceptions here - this will prevent the redirect.
+ rdump("Redirector: Unexpected error in onChannelRedirect: " + e + "\n");
+ }
+ },
+ //end nsIChannelEventSink
+
+ //Private members and methods
+
+ _prefs : null,
+ _list : null,
+ _strings : null,
+ _cout : Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService),
+
+ init : function() {
+ if (this._prefs) {
+ this._prefs.dispose();
+ }
+ this._cout.logStringMessage('REDIRECTOR CREATED');
+ this._prefs = new RedirectorPrefs();
+ //Check if we need to update existing redirects
+ var data = this._prefs.redirects;
+ var version = this._prefs.version;
+ this._loadStrings();
+ this._list = [];
+ this.handleUpgrades();
+ var redirectsFile = this._getRedirectsFile();
+ if (redirectsFile.exists()) {
+ this.importRedirects(redirectsFile);
+ }
+
+ RedirectorProxy.start(this._prefs.proxyServerPort);
+ rdump('Registering as Proxy Filter');
+ //var pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(Ci.nsIProtocolProxyService);
+ //pps.registerFilter(this, 0);
+ },
+
+ _loadStrings : function() {
+ var src = 'chrome://redirector/locale/redirector.properties';
+ var localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService);
+ var appLocale = localeService.getApplicationLocale();
+ var stringBundleService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
+ this._strings = stringBundleService.createBundle(src, appLocale);
+ },
+
+ _containsRedirect : function(redirect) {
+ for each (var existing in this._list) {
+ if (existing.equals(redirect)) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ _getString : function(name) {
+ return this._strings.GetStringFromName(name);
+ },
+
+ _getFormattedString : function(name, params) {
+ return this._strings.formatStringFromName(name, params, params.length);
+ },
+
+ _msgBox : function(title, text) {
+ Cc["@mozilla.org/embedcomp/prompt-service;1"]
+ .getService(Ci.nsIPromptService)
+ .alert(null, title, text);
+ },
+
+ _makeAbsoluteUrl : function(currentUrl, relativeUrl) {
+
+ if (relativeUrl.match(/https?:/)) {
+ return relativeUrl;
+ }
+
+ var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
+ var uri = ioService.newURI(currentUrl, null, null);
+
+ return uri.resolve(relativeUrl);
+ }
+};
+
+Redirector.init();
\ No newline at end of file
diff --git a/chrome/js/redirectorprefs.js b/chrome/js/redirectorprefs.js
new file mode 100644
index 0000000..75ef936
--- /dev/null
+++ b/chrome/js/redirectorprefs.js
@@ -0,0 +1,76 @@
+var EXPORTED_SYMBOLS = ['RedirectorPrefs'];
+
+function RedirectorPrefs() {
+ this.init();
+}
+
+RedirectorPrefs.prototype = {
+
+ _listeners : null,
+ init : function() {
+ this._prefBranch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.redirector.");
+ this.reload();
+ this._listeners = [];
+ this.service.addObserver('extensions.redirector', this, false);
+ },
+
+ dispose : function() {
+ this._listeners = null;
+ this.service.removeObserver('extensions.redirector', this);
+ },
+
+ reload : function(addWatch) {
+ var b = this._prefBranch;
+ for each (var name in b.getChildList('')){
+ this.unwatch(name);
+ var type = b.getPrefType(name);
+ if (type == b.PREF_STRING) {
+ this[name] = b.getCharPref(name);
+ } else if (type == b.PREF_INT) {
+ this[name] = b.getIntPref(name);
+ } else if (type == b.PREF_BOOL) {
+ this[name] = b.getBoolPref(name);
+ }
+
+ this.watch(name, function(id,oldval,newval) {
+ var type = b.getPrefType(id);
+ if (type == b.PREF_STRING) {
+ b.setCharPref(id,newval);
+ } else if (type == b.PREF_INT) {
+ b.setIntPref(id, newval);
+ } else if (type == b.PREF_BOOL) {
+ dump(id+ ' ' + newval)
+ b.setBoolPref(id, newval);
+ }
+ return newval;
+ });
+ }
+ },
+
+ get service() {
+ return Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranchInternal);
+ },
+
+ observe : function(subject, topic, data) {
+ if (topic != 'nsPref:changed') {
+ return;
+ }
+ this.reload(false);
+ for each (var listener in this._listeners) {
+ listener && listener.changedPrefs && listener.changedPrefs(this);
+ }
+ },
+
+ addListener : function(listener) {
+ this._listeners.push(listener);
+ },
+
+ removeListener : function(listener) {
+ for (var i = 0; i < this._listeners.length; i++) {
+ this._listeners.splice(i,1);
+ if (this._listeners[i] == listener) {
+ return;
+ }
+ }
+ },
+}
\ No newline at end of file
diff --git a/chrome/js/settings.js b/chrome/js/settings.js
deleted file mode 100644
index c12562b..0000000
--- a/chrome/js/settings.js
+++ /dev/null
@@ -1,162 +0,0 @@
-Components.utils.import("chrome://redirector/content/code/redirector.js");
-Components.utils.import("chrome://redirector/content/code/redirectorprefs.js");
-Components.utils.import("chrome://redirector/content/code/xpcom.js");
-
-$(document).ready(function() {
- var prefs = new RedirectorPrefs();
- var strings = StringBundleService.createBundle('chrome://redirector/locale/redirector.properties', LocaleService.getApplicationLocale());
- function tr(name) {
- return strings.GetStringFromName(name);
- }
-
- function trPlural(name, count) {
- name += count == 1 ? 'Singular' : '';
- return strings.formatStringFromName(name, [count],1);
- }
-
- function getFile(captionKey, mode) {
- var picker = new FilePicker(window, tr(captionKey), mode);
- picker.defaultExtension = ".rjson";
- var dir = prefs.defaultDir;
- if (dir) {
- picker.displayDirectory = new LocalFile(dir);
- }
- picker.appendFilter(tr('redirectorFiles'), '*.rjson');
-
- if (picker.show() == picker.returnCancel) {
- return null;
- }
- prefs.defaultDir = picker.displayDirectory.path;
- return picker.file;
- }
-
- function exportRedirects() {
- var file = getFile('exportCaption', FilePickerMode.save);
- if (file) {
- Redirector.exportRedirects(file);
- }
- }
-
- function importRedirects() {
- var file = getFile('importCaption', FilePickerMode.open);
- var result;
- if (!file) {
- return;
- }
- result = Redirector.importRedirects(file);
- var msg, imported, existed;
- imported = result & 0xFFFF;
- existed = result >> 16;
-
- if (imported > 0) {
- msg = trPlural('importedMessage', imported);
- if (existed > 0) {
- msg += ', ' + trPlural('existedMessage',existed);
- } else {
- msg += '.';
- }
- } else if (imported == 0 && existed > 0) {
- msg = trPlural('allExistedMessage', existed);
- } else { //Both 0
- msg = tr('importedNone');
- }
-
- var title = tr('importResult');
- PromptService.alert(null, title, msg);
-
- if (imported > 0) {
- var newlist = [];
- for (var i = Redirector.redirectCount-imported; i < Redirector.redirectCount; i++) {
- newlist.push(Redirector.getRedirectAt(i));
- }
- //this.addItemsToListBox(newlist);
- }
- }
-
- var template = $('#redirect-list').html().replace(/^\s*|\s$/g, '');
- function databind() {
- $('#redirect-list').empty();
- for (var i = 0; i < Redirector.redirectCount; i++) {
- var redirect = Redirector.getRedirectAt(i);
- var node = $(template);
- node.find('.pattern').html(redirect.includePattern);
- node.find('.redirectTo').html(redirect.redirectUrl);
- node.find('.exampleUrl').html(redirect.exampleUrl);
- node.find('.redirectResult').html(redirect.getMatch(redirect.exampleUrl).redirectTo);
- node.appendTo('#redirect-list');
- node.data('redirect', redirect);
- }
-
- }
-
- $('#redirect-list li div a.delete').live('click', function(ev) {
- var redirect = $(this.parentNode.parentNode).data('redirect');
- if (PromptService.confirm(null, tr("deleteConfirmationTitle"), tr("deleteConfirmationText"))) {
- Redirector.deleteRedirect(redirect);
- $(this.parentNode.parentNode).fadeOut(function() { $(this).remove(); });
- }
- ev.preventDefault();
- });
-
- $('#redirect-list li div a.edit').live('click', function(ev) {
- var redirect = $(this.parentNode.parentNode).data('redirect');
- $('#redirect-form').show();
- ev.preventDefault();
- });
-
- databind();
- $('#import').click(importRedirects);
- $('#export').click(exportRedirects);
-
- function bindConfig() {
- $('#config input[type="checkbox"]').each(function() {
- var pref = $(this).attr('data-pref');
- $(this).attr('checked', prefs[pref]);
- });
- }
-
- bindConfig();
- prefs.addListener({ changedPrefs:bindConfig});
-
- var movingElement = null;
- $('li').mousedown(function(ev) {
- if (ev.target && ev.target.tagName == 'A') {
- return;
- }
- $(this).css('background', '-moz-linear-gradient(top, #aac, #99b)');
- $('#redirect-list').css('cursor', 'move');
- movingElement = this;
- });
-
-
- $('li').mouseover(function() {
- if (movingElement && this !== movingElement) {
- if ($(movingElement).offset().top > $(this).offset().top) {
- $(movingElement).detach().insertBefore(this);
- } else {
- $(movingElement).detach().insertAfter(this);
- }
- }
- });
-
- $(document).mouseup(function() {
- if (movingElement) {
- $(movingElement).css('background', '');
- movingElement = null;
- $('#redirect-list').css('cursor', '');
- var newOrder = {};
- $('#redirect-list li').each(function(i) {
- newOrder[$(this).data('redirect')] = i;
- });
-
- Redirector.sortRedirects(function(a,b) {
- return newOrder[a] - newOrder[b];
- });
- }
- });
-
- $('#config input[type="checkbox"]').bind('CheckboxStateChange', function() {
- var pref = $(this).attr('data-pref');
- prefs[pref] = !!$(this).attr('checked');
- });
-});
\ No newline at end of file
diff --git a/chrome/js/xpcom.js b/chrome/js/xpcom.js
new file mode 100644
index 0000000..e81f58e
--- /dev/null
+++ b/chrome/js/xpcom.js
@@ -0,0 +1,28 @@
+
+Ci = Components.interfaces;
+Cc = Components.classes;
+Cr = Components.results;
+
+const ServerSocket = Components.Constructor("@mozilla.org/network/server-socket;1", "nsIServerSocket", "init");
+const ScriptableInputStream = Components.Constructor("@mozilla.org/scriptableinputstream;1", "nsIScriptableInputStream", "init");
+const FileInputStream = Components.Constructor("@mozilla.org/network/file-input-stream;1", "nsIFileInputStream", "init");
+const ConverterInputStream = Components.Constructor("@mozilla.org/intl/converter-input-stream;1", "nsIConverterInputStream", "init");
+const LocalFile = Components.Constructor("@mozilla.org/file/local;1", "nsILocalFile", "initWithPath");
+const FilePicker = Components.Constructor("@mozilla.org/filepicker;1", "nsIFilePicker", "init");
+const FilePickerMode = { save : Ci.nsIFilePicker.modeSave, open : Ci.nsIFilePicker.modeOpen };
+
+function Service(className, interfaceName) {
+ return Cc[className].getService(Ci[interfaceName]);
+}
+
+const PromptService = Service("@mozilla.org/embedcomp/prompt-service;1","nsIPromptService");
+const IOService = Service("@mozilla.org/network/io-service;1","nsIIOService");
+const LocaleService = Service("@mozilla.org/intl/nslocaleservice;1", "nsILocaleService");
+const StringBundleService = Service("@mozilla.org/intl/stringbundle;1", "nsIStringBundleService");
+
+var EXPORTED_SYMBOLS = [];
+for (var name in this) {
+ if (name != 'Service' && name != 'QueryInterface' && name != 'name' && name != 'EXPORTED_SYMBOLS') {
+ EXPORTED_SYMBOLS.push(name);
+ }
+}
diff --git a/chrome/redirector.html b/chrome/redirector.html
new file mode 100644
index 0000000..9bb6cc7
--- /dev/null
+++ b/chrome/redirector.html
@@ -0,0 +1,71 @@
+
+
+
+ Redirector Extension Settings
+
+
+
+
+
+
Redirector is an extension for Firefox that allows you to automatically redirect from
- one webpage to another. For example, every time you visit http://abc.com you will automatically
- load http://def.com instead. This can be useful for instance to always redirect articles to printer friendly
- versions, redirect http:// to https:// for sites that support both, bypass advertising pages that appear before
- being able to view certain pages and more.
-
-
-
Basic usage
-
To add a new redirect you can go to the Tools menuitem and select Redirector. That will
- open the Redirector settings window which shows all your redirects. The window can also be opened
- by right clicking on the R icon in your statusbar.
- There you can press the Add... button and then you can enter the details for the new redirect. A redirect
- consists of a few things:
-
-
Example url: This is an example of an url you want to redirect. It is not really used for anything,
- it's just there to show what types of urls you're targetting. You can leave this out, but then you can't use the Test pattern button.
-
-
Include pattern: This is pattern for the urls you want to redirect. In the simplest case, where you just want
- to redirect one specific url to another then this will just be the exact url you want to redirect. For instance, if you just want http://aaa.com to
- redirect to http://bbb.com then Include pattern will just be http://aaa.com. For more complex patterns that match many
- urls you can use either wildcards or regular expressions.
-
-
Exclude pattern: Urls that match this pattern will never be redirected. This is not necessary to
- fill out, but can be useful when you want to redirect all urls that contain some text except if they contain some other text.
- Redirects like that can often be done with a complex regular expression, but using an exclude pattern makes it much simpler. The exclude
- patterns can use wildcard characters or regular expressions like the include patterns.
-
-
Redirect to: This is the url that you will be redirected to when you open any page where the url matches the
- include pattern. You can use the special signs $1, $2, $3 etc. in the url, they will be replaced by the results of captures with regular
- expressions or stars with wildcards. For instance, if you have the include pattern http://google.com/*, redirect to http://froogle.com/$1
- and you open the page http://google.com/foobar, then you will be redireced to http://froogle.com/foobar, since 'foobar' was what the star replaced. $1 is for the
- first star in the pattern, $2 for the second and so on. For regular expression $1 is for the first parantheses, $2 for the second etc.
-
-
Pattern type: This specifies how Redirector should interpret the patterns, either as
- wildcards or regular expressions.
-
-
Unescape matches: A common usage of Redirector is to catch urls like
- http://foo.com/redirect.php?url=http%3A%2F%2Fbar%2Ecom%2Fpath and try to catch the url parameter and redirect to it. A pattern
- like http://foo.com/redirect.php?url=* might be used for that purpose. However, if the url parameter is escaped (also known
- as urlencoded) then that won't work. In the url above we see that it starts with http%3A%2F%2F instead of http://, and Firefox
- won't accept this as a new url to redirect to. So, in cases like these you can check the Unescape matches option and then all
- matches will be unescaped (turned from e.g. http%3A%2F%2Fbar%2Ecom to http://bar.com) before being inserted into the target url.
-
-
-
-
-
-
-
Wildcards
-
-
Wildcards are the simplest way to specify include and exclude patterns. When you create a wildcard pattern there
- is just one special character, the asterisk *. An asterisk in your pattern will match zero or more characters and you can
- have more than one star in your pattern. Some examples:
-
-
http://example.com/* matches http://example.com/, http://example.com/foo, http://example.com/bar and all other urls that start with http://example.com/.
-
http://*.example.com matches all subdomains of example.com, like http://www.example.com, http://mail.example.com.
-
http*://example.com matches both http://example.com and https://example.com.
- $1, $2, $3 in the redirect urls will match the text that the stars matched. Examples:
-
-
http://example.com/* matches http://example.com/foobar, $1 is foobar.
-
http://*.example.com/* matches http://www.example.com/foobar, $1 is www, $2 is foobar.
-
-
-
-
-
Regular expressions
-
-
Regular expressions allow for more complicated patterns but they are a lot harder to learn than wildcards. I'm not gonna
- create a regex tutorial here but normal javascript regex syntax works, look at http://regular-expressions.info for
- an introduction to regular expressions. $1,$2 etc. can be used in the redirect url and will be replaced with contents of captures in
- the regular expressions. Captures are specified with parantheses. Example: http://example.com/index.asp\?id=(\d+) will match the url
- http://example.com/index.asp?id=12345 and $1 will be replaced by 12345. (A common mistake in regex patterns is to forget to escape
- the ? sign in the querystring of the url. ? is a special character in regular expressions so if you want to match an url with a querystring
- you should escape it as \?).
-
-
-
Examples
-
-
-
- Static redirect
- Redirects from http://example.com/foo to http://example.com/bar
-
- Include pattern: http://example.com/foo
- Exclude pattern:
- Redirect to: http://example.com/bar
- Pattern type: Wildcard
-
-
-
-
- Redirect using query string parameter and wildcards
- Redirects from http://example.com/index.php?id=12345&a=b to http://example.com/printerfriendly.php?id=12345&a=b
- where 12345 could be any number.
-
- Include pattern: http://example.com/index.php?id=*&a=b
- Exclude pattern:
- Redirect to: http://example.com/printerfriendly.com?id=$1&a=b
- Pattern type: Wildcard
-
-
-
- Redirect using query string parameter and regular expressions
- Redirects from http://example.com/index.php?id=12345&a=b to http://example.com/printerfriendly.php?id=12345&a=b
- where 12345 could be any number.
-
- Include pattern: http://example.com/index.php\?id=(\d+)&a=b
- Exclude pattern:
- Redirect to: http://example.com/printerfriendly.com?id=$1&a=b
- Pattern type: Regular Expression
-
-
-
- Redirect to a different folder using wildcards
- Redirects from http://example.com/category/fish/index.php to http://example.com/category/cats/index.php
- where fish could be any word. The exclude pattern makes sure that there is only one
- folder there, so for instance http://example.com/category/fish/cat/mouse/index.php would not match.
-
- Include pattern: http://example.com/category/*/index.php
- Exclude pattern: http://example.com/category/*/*/index.php
- Redirect to: http://example.com/category/cats/index.php
- Pattern type: Wildcard
-
-
-
- Redirect http to https using wildcards
- Redirects from http://mail.google.com/randomcharacters to https://mail.google.com/randomcharacters
- where randomcharacters could be anything.
-
- Include pattern: http://mail.google.com*
- Exclude pattern:
- Redirect to: https://mail.google.com$1
- Pattern type: Wildcard
-