commit 22b9128e5f9acd5a62cb87d075cd12f92895ae8a
Author: j <0x006A@0x2620.org>
Date: Tue Aug 3 22:49:30 2010 +0200
OxFF pan.do/ra Firefox Extension
diff --git a/.bzrignore b/.bzrignore
new file mode 100644
index 0000000..e35a4bc
--- /dev/null
+++ b/.bzrignore
@@ -0,0 +1 @@
+OxFF/settings.sqlite
diff --git a/OxFF/chrome.manifest b/OxFF/chrome.manifest
new file mode 100644
index 0000000..e2dc961
--- /dev/null
+++ b/OxFF/chrome.manifest
@@ -0,0 +1,9 @@
+content OxFF chrome/content/
+overlay chrome://browser/content/browser.xul chrome://OxFF/content/browser.xul
+
+resource ox modules/
+
+interfaces components/nsIOxFF.xpt
+component {32e2138b-2026-4cac-87c7-4f97ac4cf1c5} components/OxFF.js
+contract @pan.do/ra_extension;1 {32e2138b-2026-4cac-87c7-4f97ac4cf1c5}
+category JavaScript-global-constructor OxFF @pan.do/ra_extension;1
diff --git a/OxFF/chrome/content/browser.xul b/OxFF/chrome/content/browser.xul
new file mode 100644
index 0000000..1b51c72
--- /dev/null
+++ b/OxFF/chrome/content/browser.xul
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
diff --git a/OxFF/chrome/content/icon.png b/OxFF/chrome/content/icon.png
new file mode 100644
index 0000000..8e305db
Binary files /dev/null and b/OxFF/chrome/content/icon.png differ
diff --git a/OxFF/chrome/content/options.js b/OxFF/chrome/content/options.js
new file mode 100644
index 0000000..69d1c6c
--- /dev/null
+++ b/OxFF/chrome/content/options.js
@@ -0,0 +1,193 @@
+// -*- coding: utf-8 -*-
+// vi:si:et:sw=2:sts=4:ts=2
+
+Components.utils.import("resource://ox/utils.jsm");
+
+function Site(site, access) {
+ this.site = site;
+ this.access = access;
+ this.status = access==1?"Allowed":"Denied";
+}
+
+Site.prototype = {
+ delete: function() {
+ var conn = ox.getDB();
+ var q = conn.createStatement("DELETE FROM site WHERE site = :site");
+ q.params.site = this.site;
+ q.executeStep();
+ },
+ toggle: function() {
+ var conn = ox.getDB();
+ if(this.access==1) this.access=0;
+ else this.access = 1;
+ var q = conn.createStatement("UPDATE site SET access = :access WHERE site = :site");
+ q.params.site = this.site;
+ q.params.access = this.access;
+ q.executeStep();
+ this.status = this.access==1?"Allowed":"Denied";
+ }
+}
+
+var OxFFManager = {
+ _sites : [],
+ _tree : null,
+ _view: {
+ _rowCount: 0,
+ get rowCount() {
+ return this._rowCount;
+ },
+ getCellText: function (aRow, aColumn) {
+ if (aColumn.id == "siteCol")
+ return OxFFManager._sites[aRow].site;
+ else if (aColumn.id == "statusCol")
+ return OxFFManager._sites[aRow].status;
+ 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(column) {},
+ getRowProperties: function(row,prop){},
+ getColumnProperties: function(column,prop){},
+ getCellProperties: function(row,column,prop){}
+ },
+ onLoad: function () {
+ this._tree = document.getElementById("sitesTree");
+ this._sites = [];
+
+ // load permissions into a table
+ var conn = ox.getDB();
+ var q = conn.createStatement("SELECT site, access FROM site");
+ while(q.executeStep()) {
+ var p = new Site(q.row.site, q.row.access);
+ this._sites.push(p);
+ }
+
+ this._view._rowCount = this._sites.length;
+
+ // sort and display the table
+ this._tree.treeBoxObject.view = this._view;
+ this.onSiteSort("site", false);
+
+ // disable "remove all" button if there are none
+ document.getElementById("removeAllSites").disabled = this._sites.length == 0;
+ },
+ onSiteDoubleclick: function (aEvent) {
+ var selection = this._tree.view.selection;
+ var rc = selection.getRangeCount();
+ for (var i = 0; i < rc; ++i) {
+ var min = { }; var max = { };
+ selection.getRangeAt(i, min, max);
+ for (var j = min.value; j <= max.value; ++j) {
+ this._sites[j].toggle();
+ }
+ }
+ },
+ onSiteSelected: function () {
+ var hasSelection = this._tree.view.selection.count > 0;
+ var hasRows = this._tree.view.rowCount > 0;
+ document.getElementById("removeSite").disabled = !hasRows || !hasSelection;
+ document.getElementById("removeAllSites").disabled = !hasRows;
+ },
+ onSiteDeleted: function () {
+ if (!this._view.rowCount)
+ return;
+ var removedSites = [];
+ gTreeUtils.deleteSelectedItems(this._tree, this._view, this._sites, removedSites);
+ for (var i = 0; i < removedSites.length; ++i) {
+ var p = removedSites[i];
+ p.delete();
+ }
+ document.getElementById("removeSite").disabled = !this._sites.length;
+ document.getElementById("removeAllSites").disabled = !this._sites.length;
+ },
+ onAllSitesDeleted: function () {
+ if (!this._view.rowCount)
+ return;
+ var removedSites = [];
+ gTreeUtils.deleteAll(this._tree, this._view, this._sites, removedSites);
+ for (var i = 0; i < removedSites.length; ++i) {
+ var p = removedSites[i];
+ p.delete();
+ }
+ document.getElementById("removeSite").disabled = true;
+ document.getElementById("removeAllSites").disabled = true;
+ },
+ _lastSiteSortColumn: "",
+ _lastSiteSortAscending: false,
+
+ onSiteSort: function (aColumn) {
+ this._lastSiteSortAscending = gTreeUtils.sort(this._tree,
+ this._view,
+ this._sites,
+ aColumn,
+ this._lastSiteSortColumn,
+ this._lastSiteSortAscending);
+ this._lastSiteSortColumn = aColumn;
+ },
+};
+
+var gTreeUtils = {
+ deleteAll: function (aTree, aView, aItems, aDeletedItems) {
+ for (var i = 0; i < aItems.length; ++i)
+ aDeletedItems.push(aItems[i]);
+ aItems.splice(0);
+ var oldCount = aView.rowCount;
+ aView._rowCount = 0;
+ aTree.treeBoxObject.rowCountChanged(0, -oldCount);
+ },
+
+ deleteSelectedItems: function (aTree, aView, aItems, aDeletedItems) {
+ var selection = aTree.view.selection;
+ selection.selectEventsSuppressed = true;
+
+ var rc = selection.getRangeCount();
+ for (var i = 0; i < rc; ++i) {
+ var min = { }; var max = { };
+ selection.getRangeAt(i, min, max);
+ for (var j = min.value; j <= max.value; ++j) {
+ aDeletedItems.push(aItems[j]);
+ aItems[j] = null;
+ }
+ }
+
+ var nextSelection = 0;
+ for (i = 0; i < aItems.length; ++i) {
+ if (!aItems[i]) {
+ var j = i;
+ while (j < aItems.length && !aItems[j])
+ ++j;
+ aItems.splice(i, j - i);
+ nextSelection = j < aView.rowCount ? j - 1 : j - 2;
+ aView._rowCount -= j - i;
+ aTree.treeBoxObject.rowCountChanged(i, i - j);
+ }
+ }
+
+ if (aItems.length) {
+ selection.select(nextSelection);
+ aTree.treeBoxObject.ensureRowIsVisible(nextSelection);
+ aTree.focus();
+ }
+ selection.selectEventsSuppressed = false;
+ },
+
+ sort: function (aTree, aView, aDataSet, aColumn,
+ aLastSortColumn, aLastSortAscending) {
+ var ascending = (aColumn == aLastSortColumn) ? !aLastSortAscending : true;
+ aDataSet.sort(function (a, b) { return a[aColumn].toLowerCase().localeCompare(b[aColumn].toLowerCase()); });
+ if (!ascending)
+ aDataSet.reverse();
+
+ aTree.view.selection.select(-1);
+ aTree.view.selection.select(0);
+ aTree.treeBoxObject.invalidate();
+ aTree.treeBoxObject.ensureRowIsVisible(0);
+
+ return ascending;
+ }
+};
diff --git a/OxFF/chrome/content/options.xul b/OxFF/chrome/content/options.xul
new file mode 100644
index 0000000..7d8e09c
--- /dev/null
+++ b/OxFF/chrome/content/options.xul
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The following sites have permission to use OxFF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OxFF/chrome/content/overlay.js b/OxFF/chrome/content/overlay.js
new file mode 100644
index 0000000..e69de29
diff --git a/OxFF/components/OxFF.js b/OxFF/components/OxFF.js
new file mode 100644
index 0000000..d83716b
--- /dev/null
+++ b/OxFF/components/OxFF.js
@@ -0,0 +1,359 @@
+// -*- coding: utf-8 -*-
+// vi:si:et:sw=2:sts=4:ts=2
+/*
+ OxFF - local extension for pan.do/ra
+ http://pan.do/ra
+ 2009-2010 - GPL 3.0
+ */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://ox/utils.jsm");
+
+var OxFFFactory =
+{
+ createInstance: function (outer, iid)
+ {
+ if (outer != null)
+ throw NS_ERROR_NO_AGGREGATION;
+
+ return (new OxFF()).QueryInterface(iid);
+ }
+};
+
+function OxFF() {
+ var _this = this;
+ var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+ var nsWindow = windowMediator.getMostRecentWindow("navigator:browser");
+ this._window = nsWindow.content;
+ this.app = Cc["@mozilla.org/fuel/application;1"].getService(Ci.fuelIApplication);
+
+ this._site = this._window.document.location.hostname;
+ if(!this._site) {
+ this._site = 'localhost';
+ }
+ this.access();
+}
+
+OxFF.prototype = {
+ classDescription: "OxFF pan.do/ra Firefox extension",
+ classID: Components.ID("{32e2138b-2026-4cac-87c7-4f97ac4cf1c5}"),
+ contractID: "@pan.do/ra_extension;1",
+ extensionID: "OxFF@pan.do",
+
+ _xpcom_factory : OxFFFactory,
+
+ _xpcom_categories : [{
+ category: "JavaScript global constructor",
+ entry: "OxFF"
+ }],
+
+ _prefs : Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch),
+ _window : null,
+ _icon : null,
+ _protocolCallbacks : {},
+
+ QueryInterface: XPCOMUtils.generateQI(
+ [Ci.nsIOxFF,
+ Ci.nsISecurityCheckedComponent,
+ Ci.nsISupportsWeakReference,
+ Ci.nsIClassInfo]),
+
+ // nsIClassInfo
+ implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
+ flags: Ci.nsIClassInfo.DOM_OBJECT,
+
+ getInterfaces: function getInterfaces(aCount) {
+ var interfaces = [Ci.nsIOxFF,
+ Ci.nsISecurityCheckedComponent,
+ Ci.nsISupportsWeakReference,
+ Ci.nsIClassInfo];
+ aCount.value = interfaces.length;
+ return interfaces;
+ },
+
+ getHelperForLanguage: function getHelperForLanguage(aLanguage) {
+ return null;
+ },
+
+ //nsISecurityCheckedComponent
+ canCallMethod: function canCallMethod(iid, methodName) {
+ Components.utils.reportError(methodName);
+ return "AllAccess";
+ },
+
+ canCreateWrapper: function canCreateWrapper(iid) {
+ return "AllAccess";
+ },
+
+ canGetProperty: function canGetProperty(iid, propertyName) {
+ Components.utils.reportError(propertyName);
+ return "AllAccess";
+ },
+
+ canSetProperty: function canSetProperty(iid, propertyName) {
+ Components.utils.reportError(propertyName);
+ return "NoAccess";
+ },
+ debug: function() {
+ var msg = "OxFF: ";
+ for(var i=0;i
+
+
+ OxFF@pan.do
+ bzr
+ 2
+
+
+
+
+ {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+ 3.5
+ 4.0b9
+
+
+
+
+ pan.do/ra Firefox extension
+ integrate local files with pan.do/ra databases
+ pan.do/ra
+ https://pan.do/ra_extension
+ chrome://OxFF/content/icon.png
+ https://pan.do/ra_extension/update.rdf
+ chrome://OxFF/content/options.xul
+
+
+
diff --git a/OxFF/modules/utils.jsm b/OxFF/modules/utils.jsm
new file mode 100644
index 0000000..6565ea6
--- /dev/null
+++ b/OxFF/modules/utils.jsm
@@ -0,0 +1,80 @@
+// -*- coding: utf-8 -*-
+// vi:si:et:sw=4:sts=4:ts=4
+
+let EXPORTED_SYMBOLS = [ "ox" ];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+let ox = {
+ getDB: function() {
+ var file = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties)
+ .get("ProfD", Ci.nsIFile);
+ file.append("OxFF.sqlite");
+ var storageService = Cc["@mozilla.org/storage/service;1"].getService(Ci.mozIStorageService);
+ var conn = storageService.openDatabase(file);
+ conn.executeSimpleSQL("CREATE TABLE IF NOT EXISTS site (site varchar(1024) unique, access INT)");
+ return conn;
+ },
+ setTimeout: function(callback, timeout) {
+ var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ timer.initWithCallback(callback, timeout, Ci.nsITimer.TYPE_ONE_SHOT);
+ },
+ glob: function (path) {
+ /*
+ return array of all files(in all subdirectories) for given directory
+ */
+ var directory = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+ directory.initWithPath(path);
+ var entries = directory.directoryEntries;
+ var array = [];
+ while(entries.hasMoreElements()) {
+ var entry = entries.getNext();
+ entry.QueryInterface(Components.interfaces.nsIFile);
+ if(entry.isDirectory()) {
+ var sub = this.glob(entry.path);
+ for(i in sub) {
+ array.push(sub[i]);
+ }
+ } else {
+ array.push(entry.path);
+ }
+ }
+ return array;
+ },
+ subprocess: function(command, options, callback) {
+ if(!this.ipcService) {
+ this.ipcService = Cc["@mozilla.org/process/ipc-service;1"]
+ .getService().QueryInterface(Ci.nsIIPCService);
+ }
+ var cmd = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+ cmd.initWithPath(command);
+
+ if(command.indexOf(".exe")==-1 &&
+ command.substr(0, 15) != "/usr/local/bin/" &&
+ command.substr(0, 9) != "/usr/bin/") {
+ cmd.permissions = 0755;
+ }
+
+ if (typeof(callback) == 'function') {
+ var thread = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager)
+ .newThread(0);
+ var backgroundTask = {
+ run: function() {
+ var result = that.ipcService.run(cmd, options, options.length);
+ callback(result);
+ }
+ }
+ thread.dispatch(backgroundTask, thread.DISPATCH_NORMAL);
+ } else { //no callback, call subprocess blocking, will only return once done
+ /*
+ dump('\ncmd: ');
+ dump(cmd.path)
+ dump('\n');
+ dump(options)
+ */
+ return this.ipcService.run(cmd, options, options.length);
+ }
+ },
+
+};
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..51b2a5d
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+cd `dirname $0`
+
+release=`bzr tags | grep ".0 " | tail -1 | awk '{print $1}' | cut -d- -f2| tr "." " " |awk '{print $1"."$2}'`
+release_rev=`bzr tags | grep ".0 " | tail -1 | awk '{print $2}'`
+current_rev=`bzr revno`
+version=$release.`printf %02d $(( $current_rev-$release_rev ))`
+
+#update idl file
+./src/make.sh
+mkdir -p dist
+
+sed -i "s/version: \".*\"/version: \"$version\"/g" OxFF/components/OxFF.js
+sed -i "s/em:version>.*<\/em:version/em:version>$version<\/em:version/g" OxFF/install.rdf
+
+rm -f dist/OxFF-$version.xpi
+zip -9 -r dist/OxFF-$version.xpi * \
+ -x \*.~1~ -x \*.orig
+
+#cleanup
+sed -i "s/version: \".*\"/version: \"bzr\"/g" OxFF/components/OxFF.js
+sed -i "s/em:version>.*<\/em:version/em:version>bzr<\/em:version/g" OxFF/install.rdf
+
diff --git a/src/make.sh b/src/make.sh
new file mode 100755
index 0000000..b211da1
--- /dev/null
+++ b/src/make.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+cd `dirname $0`
+XULRUNNER=xulrunner-1.9.2.8
+IDL_PREFIX=/usr/share/idl/$XULRUNNER
+XPIDL=/usr/lib/$XULRUNNER/xpidl
+XPT=../OxFF/components/nsIOxFF.xpt
+IDL=nsIOxFF.idl
+$XPIDL -m typelib -w -v -I $IDL_PREFIX -e $XPT $IDL
diff --git a/src/nsIOxFF.idl b/src/nsIOxFF.idl
new file mode 100644
index 0000000..59933dd
--- /dev/null
+++ b/src/nsIOxFF.idl
@@ -0,0 +1,30 @@
+#include "nsISupports.idl"
+
+[function, scriptable, uuid(70015be1-2620-4682-ba3c-8023e7cb42ac)]
+interface oxICallback : nsISupports
+{
+ /**
+ * @param result string
+ */
+ void callback(in AString result);
+};
+
+
+[scriptable, uuid(333280ed-2620-46ed-916d-b9c29e84d9ba)]
+interface nsIOxFF : nsISupports
+{
+ readonly attribute string version;
+
+ boolean login(in AString user);
+ boolean addVolume();
+ string import();
+ float progress(in AString oshash);
+ boolean access([optional] in boolean request);
+ boolean update();
+ string volumes();
+ boolean files(in oxICallback callback);
+ boolean get(in AString oshash, in AString media, in oxICallback callback);
+ boolean extract(in AString oshash, in AString media, in oxICallback callback);
+ boolean logout();
+};
+
diff --git a/test/import.html b/test/import.html
new file mode 100644
index 0000000..133962a
--- /dev/null
+++ b/test/import.html
@@ -0,0 +1,10 @@
+