OxFF pan.do/ra Firefox Extension
This commit is contained in:
commit
22b9128e5f
15 changed files with 803 additions and 0 deletions
1
.bzrignore
Normal file
1
.bzrignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
OxFF/settings.sqlite
|
9
OxFF/chrome.manifest
Normal file
9
OxFF/chrome.manifest
Normal file
|
@ -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
|
9
OxFF/chrome/content/browser.xul
Normal file
9
OxFF/chrome/content/browser.xul
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<?xml-stylesheet href="chrome://oxff/skin/overlay.css" type="text/css"?>
|
||||||
|
<!DOCTYPE overlay SYSTEM "chrome://oxff/locale/oxff.dtd">
|
||||||
|
<overlay id="oxff-overlay"
|
||||||
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||||
|
|
||||||
|
<script type="application/javascript" src="chrome://OxFF/content/overlay.js"/>
|
||||||
|
|
||||||
|
</overlay>
|
BIN
OxFF/chrome/content/icon.png
Normal file
BIN
OxFF/chrome/content/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
193
OxFF/chrome/content/options.js
Normal file
193
OxFF/chrome/content/options.js
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
};
|
53
OxFF/chrome/content/options.xul
Normal file
53
OxFF/chrome/content/options.xul
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||||
|
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>
|
||||||
|
|
||||||
|
<!DOCTYPE dialog SYSTEM "chrome://browser/locale/preferences/permissions.dtd" >
|
||||||
|
|
||||||
|
<window id="OxFFPreferences" class="windowDialog"
|
||||||
|
windowtype="Browser:Sites"
|
||||||
|
title="OxFF Sites"
|
||||||
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
style="width: &window.width;;"
|
||||||
|
onload="OxFFManager.onLoad();"
|
||||||
|
persist="screenX screenY width height">
|
||||||
|
|
||||||
|
<script src="chrome://OxFF/content/options.js"/>
|
||||||
|
|
||||||
|
<keyset>
|
||||||
|
<key key="&windowClose.key;" modifiers="accel" oncommand="window.close();"/>
|
||||||
|
</keyset>
|
||||||
|
|
||||||
|
<vbox class="contentPane" flex="1">
|
||||||
|
<description id="permissionsText" control="url">The following sites have permission to use OxFF</description>
|
||||||
|
<separator class="thin"/>
|
||||||
|
<tree id="sitesTree" flex="1" style="height: 18em;"
|
||||||
|
hidecolumnpicker="true"
|
||||||
|
|
||||||
|
onselect="OxFFManager.onSiteSelected();">
|
||||||
|
<treecols>
|
||||||
|
<treecol id="siteCol" label="&treehead.sitename.label;" flex="3"
|
||||||
|
onclick="OxFFManager.onSiteSort('site');" persist="width"/>
|
||||||
|
<splitter class="tree-splitter"/>
|
||||||
|
<treecol id="statusCol" label="&treehead.status.label;" flex="1"
|
||||||
|
onclick="OxFFManager.onSiteSort('status');" persist="width"/>
|
||||||
|
</treecols>
|
||||||
|
<treechildren ondblclick="OxFFManager.onSiteDoubleclick(event)" />
|
||||||
|
</tree>
|
||||||
|
</vbox>
|
||||||
|
<hbox align="end">
|
||||||
|
<hbox class="actionButtons" flex="1">
|
||||||
|
<button id="removeSite" disabled="true"
|
||||||
|
accesskey="&removepermission.accesskey;"
|
||||||
|
icon="remove" label="&removepermission.label;"
|
||||||
|
oncommand="OxFFManager.onSiteDeleted();"/>
|
||||||
|
<button id="removeAllSites"
|
||||||
|
icon="clear" label="&removeallpermissions.label;"
|
||||||
|
accesskey="&removeallpermissions.accesskey;"
|
||||||
|
oncommand="OxFFManager.onAllSitesDeleted();"/>
|
||||||
|
<spacer flex="1"/>
|
||||||
|
</hbox>
|
||||||
|
<resizer type="window" dir="bottomend"/>
|
||||||
|
</hbox>
|
||||||
|
</window>
|
0
OxFF/chrome/content/overlay.js
Normal file
0
OxFF/chrome/content/overlay.js
Normal file
359
OxFF/components/OxFF.js
Normal file
359
OxFF/components/OxFF.js
Normal file
|
@ -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<arguments.length;i++) {
|
||||||
|
msg += arguments[i];
|
||||||
|
if(i+1<arguments.length)
|
||||||
|
msg += ', ';
|
||||||
|
}
|
||||||
|
this.app.console.log(msg);
|
||||||
|
},
|
||||||
|
base: 'http://127.0.0.1:2620/',
|
||||||
|
username: 'fix',
|
||||||
|
password: 'me',
|
||||||
|
_user: null,
|
||||||
|
|
||||||
|
//nsIOxFF
|
||||||
|
version: "bzr",
|
||||||
|
login: function(user) {
|
||||||
|
if(this._user==null) {
|
||||||
|
this._user = user;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
logout: function(user) {
|
||||||
|
var _this = this;
|
||||||
|
this.api('shutdown', function() {
|
||||||
|
_this._user = null;
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
update: function() {
|
||||||
|
this.api('update', function() {});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
access: function(request) {
|
||||||
|
if (typeof(request) == 'undefined') request = false;
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
var conn = ox.getDB();
|
||||||
|
var q = conn.createStatement("SELECT access FROM site WHERE site = :site");
|
||||||
|
q.params.site = this._site;
|
||||||
|
this._access = false;
|
||||||
|
while(q.executeStep()) {
|
||||||
|
if(q.row.access == 1) {
|
||||||
|
this._access = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(request && !this._access) {
|
||||||
|
var windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
|
||||||
|
var nsWindow = windowMediator.getMostRecentWindow("navigator:browser");
|
||||||
|
var box = nsWindow.gBrowser.getNotificationBox();
|
||||||
|
var buttons = [{
|
||||||
|
label : "Allow",
|
||||||
|
accessKey : "A",
|
||||||
|
callback : function() { _this.permitAccess(); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label : "Deny",
|
||||||
|
accessKey : "D",
|
||||||
|
callback : function() { _this.denyAccess(); }
|
||||||
|
}];
|
||||||
|
box.appendNotification("Do you wnat to allow "+_this._site+" to manage archvies on your computer",
|
||||||
|
'oxff_permission' , null , box.PRIORITY_INFO_MEDIUM , buttons);
|
||||||
|
}
|
||||||
|
return this._access;
|
||||||
|
},
|
||||||
|
volumes: function(callback) {
|
||||||
|
return this.api('volumes', callback);
|
||||||
|
return JSON.stringify(['Test', 'Another']);
|
||||||
|
},
|
||||||
|
api: function(action, data, callback) {
|
||||||
|
if (typeof(data) == 'function') {
|
||||||
|
callback = data;
|
||||||
|
data = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this._access) {
|
||||||
|
this.debug('permission deinied', action, data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!this._user) {
|
||||||
|
this.debug('login first', action, data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data["site"] = this._site;
|
||||||
|
data["user"] = this._user;
|
||||||
|
|
||||||
|
var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||||
|
.createInstance(Ci.nsIXMLHttpRequest);
|
||||||
|
|
||||||
|
req.addEventListener("error", function(e) {
|
||||||
|
//should check that it was infact not able to connect to server
|
||||||
|
_this.startDaemon();
|
||||||
|
//does this need a timeout?
|
||||||
|
ox.setTimeout(function() { _this.api(action, data, callback); }, 500);
|
||||||
|
}, false);
|
||||||
|
req.addEventListener("load", function(e) {
|
||||||
|
//links should have base prefixed or whatever proxy is used to access them, i.e. some api call
|
||||||
|
//var data = JSON.parse(e.target.responseText);
|
||||||
|
//callback(data);
|
||||||
|
callback(e.target.responseText);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
var base = this.base; //later base can not be a public property
|
||||||
|
var url = base + action;
|
||||||
|
|
||||||
|
var formData = Cc["@mozilla.org/files/formdata;1"]
|
||||||
|
.createInstance(Ci.nsIDOMFormData);
|
||||||
|
if (data) {
|
||||||
|
for(key in data) {
|
||||||
|
formData.append(key, data[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req.open("POST", url, true, this.username, this.password);
|
||||||
|
req.send(formData);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
files: function(callback) {
|
||||||
|
return this.api('files', callback.callback);
|
||||||
|
},
|
||||||
|
get: function(oshash, media, callback) {
|
||||||
|
return this.api('get', {'oshash': oshash, 'media': media}, callback.callback);
|
||||||
|
},
|
||||||
|
extract: function(oshash, media, callback) {
|
||||||
|
return this.api('extract', {'oshash': oshash, 'media': media}, callback);
|
||||||
|
},
|
||||||
|
addVolume: function(archive) {
|
||||||
|
if(!this._access) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//var volumes = this.getVolumes(domain);
|
||||||
|
const nsIFilePicker = Ci.nsIFilePicker;
|
||||||
|
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
|
||||||
|
fp.init(this._window, "Choose location of " + archive, nsIFilePicker.modeGetFolder);
|
||||||
|
fp.appendFilters(nsIFilePicker.filterAll);
|
||||||
|
var rv = fp.show();
|
||||||
|
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
|
||||||
|
var new_location = fp.file.path;
|
||||||
|
this.api('add_volume', {'path': new_location}, function(result) {});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
_internal_update: function() {
|
||||||
|
var new_files = [];
|
||||||
|
var volumes = this.getVolumes(this._site);
|
||||||
|
|
||||||
|
for (i in volumes) {
|
||||||
|
var volume = volumes[i];
|
||||||
|
var files = ox.glob(volume);
|
||||||
|
//filter files, only include folders and files with the right extensions,
|
||||||
|
//where to store or get the list of valid extensions? would be nice if set by domain...
|
||||||
|
|
||||||
|
for (f in files) {
|
||||||
|
var file = files[f];
|
||||||
|
//check if file is in known files
|
||||||
|
var info = this.getFormatInfo(file, false);
|
||||||
|
//strip volume path from info,
|
||||||
|
//+1 since volume paths are wihtout trailing folder seperator
|
||||||
|
info.path = file.substr(volume.length+1, file.length)
|
||||||
|
new_files.push(info);
|
||||||
|
//add to Files table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JSON.stringify(new_files);
|
||||||
|
},
|
||||||
|
//private functions
|
||||||
|
permitAccess: function() {
|
||||||
|
this._access = true;
|
||||||
|
var conn = ox.getDB();
|
||||||
|
var q = conn.createStatement("INSERT OR REPLACE INTO site values (:site, 1)");
|
||||||
|
q.params.site = this._site;
|
||||||
|
q.executeStep();
|
||||||
|
},
|
||||||
|
denyAccess: function() {
|
||||||
|
this._access = false;
|
||||||
|
var conn = ox.getDB();
|
||||||
|
var q = conn.createStatement("INSERT OR REPLACE INTO site values (:site, 0)");
|
||||||
|
q.params.site = this._site;
|
||||||
|
q.executeStep();
|
||||||
|
},
|
||||||
|
startDaemon: function() {
|
||||||
|
var osString = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
|
||||||
|
var daemon = "";
|
||||||
|
if (osString == "WINNT")
|
||||||
|
daemon = 'oxd.exe';
|
||||||
|
else
|
||||||
|
daemon = 'oxd.py';
|
||||||
|
|
||||||
|
function runDaemon(file) {
|
||||||
|
try {
|
||||||
|
file.permissions = 0755;
|
||||||
|
} catch (e) {}
|
||||||
|
var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
|
||||||
|
process.init(file);
|
||||||
|
var args = [];
|
||||||
|
process.run(false, args, args.length);
|
||||||
|
}
|
||||||
|
Components.utils.import("resource://gre/modules/AddonManager.jsm");
|
||||||
|
AddonManager.getAddonByID(this.extensionID, function(addon) {
|
||||||
|
if (addon.hasResource(daemon)) {
|
||||||
|
var resource = addon.getResourceURI(daemon);
|
||||||
|
var file = resource.QueryInterface(Ci.nsIFileURL).file.QueryInterface(Ci.nsILocalFile);
|
||||||
|
runDaemon(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getVolumes: function(site) {
|
||||||
|
var conn = ox.getDB();
|
||||||
|
var q = conn.createStatement("SELECT path FROM volume WHERE domain = :domain");
|
||||||
|
q.params.domain = site;
|
||||||
|
var volumes = [];
|
||||||
|
try {
|
||||||
|
while (q.executeStep()) {
|
||||||
|
var path = q.row.path;
|
||||||
|
volumes.push(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
q.reset();
|
||||||
|
}
|
||||||
|
return volumes;
|
||||||
|
},
|
||||||
|
getFormatInfo: function(filename, callback) {
|
||||||
|
var that = this;
|
||||||
|
var get_json = function(data) {
|
||||||
|
var json = {"format": "unknown"};
|
||||||
|
try {
|
||||||
|
json = JSON.parse(data);
|
||||||
|
} catch(e) {
|
||||||
|
json = {"format": "unknown"};
|
||||||
|
}
|
||||||
|
|
||||||
|
var source_file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
|
||||||
|
source_file.initWithPath(filename);
|
||||||
|
// Try to determine the MIME type of the file
|
||||||
|
//json.contentType = that.getMimeType(source_file);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
var info_callback = function(data) {
|
||||||
|
callback(get_json(data));
|
||||||
|
}
|
||||||
|
var options = [filename, '--info'];
|
||||||
|
if (callback) {
|
||||||
|
ox.subprocess(this.bin('ffmpeg2theora'), options, callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data = ox.subprocess(this.bin('ffmpeg2theora'), options, false);
|
||||||
|
return get_json(data);
|
||||||
|
},
|
||||||
|
bin: function(cmd) {
|
||||||
|
this._cmd_name = '/usr/local/bin/_cmd_';
|
||||||
|
return this._cmd_name.replace('_cmd_', cmd);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
//4.0 only
|
||||||
|
var NSGetFactory = XPCOMUtils.generateNSGetFactory([OxFF]);
|
||||||
|
|
BIN
OxFF/components/nsIOxFF.xpt
Normal file
BIN
OxFF/components/nsIOxFF.xpt
Normal file
Binary file not shown.
28
OxFF/install.rdf
Normal file
28
OxFF/install.rdf
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||||
|
<Description about="urn:mozilla:install-manifest">
|
||||||
|
<em:id>OxFF@pan.do</em:id>
|
||||||
|
<em:version>bzr</em:version>
|
||||||
|
<em:type>2</em:type>
|
||||||
|
|
||||||
|
<!-- Firefox -->
|
||||||
|
<em:targetApplication>
|
||||||
|
<Description>
|
||||||
|
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||||
|
<em:minVersion>3.5</em:minVersion>
|
||||||
|
<em:maxVersion>4.0b9</em:maxVersion>
|
||||||
|
</Description>
|
||||||
|
</em:targetApplication>
|
||||||
|
|
||||||
|
<!-- Front End MetaData -->
|
||||||
|
<em:name>pan.do/ra Firefox extension</em:name>
|
||||||
|
<em:description>integrate local files with pan.do/ra databases</em:description>
|
||||||
|
<em:creator>pan.do/ra</em:creator>
|
||||||
|
<em:homepageURL>https://pan.do/ra_extension</em:homepageURL>
|
||||||
|
<em:iconURL>chrome://OxFF/content/icon.png</em:iconURL>
|
||||||
|
<em:updateURL>https://pan.do/ra_extension/update.rdf</em:updateURL>
|
||||||
|
<em:optionsURL>chrome://OxFF/content/options.xul</em:optionsURL>
|
||||||
|
</Description>
|
||||||
|
</RDF>
|
||||||
|
|
80
OxFF/modules/utils.jsm
Normal file
80
OxFF/modules/utils.jsm
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
23
build.sh
Executable file
23
build.sh
Executable file
|
@ -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
|
||||||
|
|
8
src/make.sh
Executable file
8
src/make.sh
Executable file
|
@ -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
|
30
src/nsIOxFF.idl
Normal file
30
src/nsIOxFF.idl
Normal file
|
@ -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();
|
||||||
|
};
|
||||||
|
|
10
test/import.html
Normal file
10
test/import.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<script>
|
||||||
|
var ox = new OxFF();
|
||||||
|
ox.access(true);
|
||||||
|
ox.get('b2c8f0aa3a447d09', 'stills', function(result) { console.log(result);});
|
||||||
|
ox.login('j');
|
||||||
|
|
||||||
|
//ox.files(function(result) { console.log(result);});
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
Loading…
Reference in a new issue