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