diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..46eed58
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+cd src; zip -r ../../nextcloud-filelink-$1.xpi .
diff --git a/screenshots/addon-about.png b/screenshots/addon-about.png
deleted file mode 100644
index 4efa825..0000000
Binary files a/screenshots/addon-about.png and /dev/null differ
diff --git a/screenshots/config.png b/screenshots/config.png
new file mode 100644
index 0000000..42b139f
Binary files /dev/null and b/screenshots/config.png differ
diff --git a/screenshots/configured.png b/screenshots/configured.png
deleted file mode 100644
index b98b07e..0000000
Binary files a/screenshots/configured.png and /dev/null differ
diff --git a/screenshots/setup.png b/screenshots/setup.png
deleted file mode 100644
index 74afdcd..0000000
Binary files a/screenshots/setup.png and /dev/null differ
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
new file mode 100644
index 0000000..309a393
--- /dev/null
+++ b/src/_locales/en/messages.json
@@ -0,0 +1,38 @@
+{
+ "extensionName": {
+ "message": "Nextcloud for Filelink",
+ "description": "Name of the extension"
+ },
+ "extensionDescription": {
+ "message": "Nextcloud provider for Thunderbird Filelink",
+ "description": "Description of the extension"
+ },
+ "serviceName": {
+ "message": "Nextcloud",
+ "description": "Name of the service"
+ },
+ "serverURLLabel": {
+ "message": "WebDAV URL"
+ },
+ "serverURLDesc": {
+ "message": "Your Personal WebDAV file path can be found under Settings in the lower left of the Files screen."
+ },
+ "usernameLabel": {
+ "message": "Username"
+ },
+ "usernameDesc": {
+ "message": "Your NextCloud username"
+ },
+ "tokenLabel": {
+ "message": "App Token / Password"
+ },
+ "tokenDesc": {
+ "message": "An app token (preferrable) or password. Generate an app token via User -> Settings -> Security -> App Token. WARNING: this token is stored insecurely. NOTE: this may require the OAuth2 plugin on the server."
+ },
+ "pathLabel": {
+ "message": "Storage Path"
+ },
+ "pathDesc": {
+ "message": "The path where the files are stored in OwnCloud (it must already exist on the server)"
+ }
+}
diff --git a/src/background.js b/src/background.js
new file mode 100644
index 0000000..ca64ca8
--- /dev/null
+++ b/src/background.js
@@ -0,0 +1,184 @@
+/**
+ * @copyright Copyright (c) 2020, Thomas Spellman (thos37@gmail.com)
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+var uploads = new Map();
+
+// browser.cloudFile.onAccountAdded.addListener(async (account) => {
+// //console.log("Account Added", account.id)
+// })
+
+async function getAccountInfo(accountId) {
+ let accountInfo = await browser.storage.local.get([accountId]);
+ if (!accountInfo[accountId] || !("webdavUrl" in accountInfo[accountId])) {
+ throw new Error("No Accounts found.");
+ }
+ return accountInfo[accountId];
+}
+
+browser.cloudFile.onFileUpload.addListener(async (account, params) => {
+
+ let { id, name, data } = params;
+
+ name = "" + Date.now() + "_" + name;
+
+ console.log("onFileUpload", id, account, name);
+
+ let accountInfo = await getAccountInfo(account.id);
+
+ //console.log("accountInfo", accountInfo);
+
+ let uploadInfo = {
+ id,
+ name,
+ abortController: new AbortController(),
+ };
+
+ uploads.set(id, uploadInfo);
+
+ let {webdavUrl, username, token, path} = accountInfo;
+
+ const authHeader = "Basic " + btoa(username + ":" + token);
+
+ let url = webdavUrl + path + encodeURIComponent(name);
+
+ let headers = {
+ "Content-Type": "application/octet-stream",
+ Authorization: authHeader
+ };
+ let fetchInfo = {
+ method: "PUT",
+ headers,
+ body: data,
+ signal: uploadInfo.abortController.signal,
+ };
+
+ //console.log("uploading to ", url, fetchInfo);
+
+ let response = await fetch(url, fetchInfo);
+
+ //console.log("file upload response", response);
+
+ delete uploadInfo.abortController;
+ if (response.status > 299) {
+ throw new Error("response was not ok: server status code: " + response.status + ", response message: " + response.statusText);
+ }
+
+ const serverUrl = webdavUrl.substr(0, webdavUrl.indexOf("remote.php"));
+ const shareUrl = serverUrl + "ocs/v1.php/apps/files_sharing/api/v1/shares?format=json";
+
+ uploadInfo.abortController = new AbortController();
+ uploads.set(id, uploadInfo);
+
+ headers = {
+ "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
+ Authorization: authHeader,
+ "OCS-APIRequest": true
+ };
+
+ fetchInfo = {
+ method: "POST",
+ headers,
+ body: "shareType=3&path=" + encodeURIComponent(path + name),
+ signal: uploadInfo.abortController.signal,
+ };
+
+ console.log("requesting public link", shareUrl, fetchInfo);
+
+ response = await fetch(shareUrl, fetchInfo);
+
+ //console.log("public link response", response);
+
+ if(response.ok)
+ {
+ let respJson = await response.json();
+
+ uploadInfo.shareID = respJson.ocs.data.id;
+ uploads.set(id, uploadInfo);
+
+ return {url: respJson.ocs.data.url + "/download"};
+ }
+ else
+ return {aborted: true}
+
+});
+
+browser.cloudFile.onFileUploadAbort.addListener((account, id) => {
+ //console.log("aborting upload", id);
+ let uploadInfo = uploads.get(id);
+ if (uploadInfo && uploadInfo.abortController) {
+ uploadInfo.abortController.abort();
+ }
+});
+
+browser.cloudFile.onFileDeleted.addListener(async (account, id) => {
+ //console.log("delete upload", id);
+ let uploadInfo = uploads.get(id);
+ if (!uploadInfo) {
+ return;
+ }
+
+ // FIXME how do we get a confirmation popup in TB MailExtensions?
+ // let wishDelete = confirm("Do you wish to delete the file on the server?");
+ // if(!wishDelete){
+ // return;
+ // }
+
+ let accountInfo = await getAccountInfo(account.id);
+
+ let {shareID} = uploadInfo;
+ let {webdavUrl, username, token} = accountInfo;
+
+ const authHeader = "Basic " + btoa(username + ":" + token);
+
+ const serverUrl = webdavUrl.substr(0, webdavUrl.indexOf("remote.php"));
+ const shareUrl = serverUrl + "ocs/v1.php/apps/files_sharing/api/v1/shares/" + shareID;
+
+ let headers = {
+ Authorization: authHeader,
+ "OCS-APIRequest": true
+ };
+
+ let fetchInfo = {
+ headers,
+ method: "DELETE",
+ };
+
+ //console.log("sending delete", url, fetchInfo);
+
+ let response = await fetch(shareUrl, fetchInfo);
+
+ //console.log("delete response", response);
+
+ uploads.delete(id);
+
+ if (response.status > 299) {
+ throw new Error("response was not ok: server status code: " + response.status + ", response message: " + response.statusText);
+ }
+
+});
+
+browser.cloudFile.getAllAccounts().then(async (accounts) => {
+ let allAccountsInfo = await browser.storage.local.get();
+ for (let account of accounts) {
+ await browser.cloudFile.updateAccount(account.id, {
+ configured: account.id in allAccountsInfo,
+ });
+ }
+});
diff --git a/src/chrome.manifest b/src/chrome.manifest
deleted file mode 100644
index c53401f..0000000
--- a/src/chrome.manifest
+++ /dev/null
@@ -1,10 +0,0 @@
-content nextcloud chrome/content/
-locale nextcloud en chrome/locale/en/
-locale nextcloud fr chrome/locale/fr/
-locale nextcloud pl chrome/locale/pl/
-locale nextcloud de chrome/locale/de/
-locale nextcloud nl chrome/locale/nl/
-locale nextcloud es chrome/locale/es/
-component {ad8c3b77-7dc8-41d1-8985-5be88b254ff3} components/nsNextcloud.js
-contract @mozilla.org/mail/nextcloud;1 {ad8c3b77-7dc8-41d1-8985-5be88b254ff3}
-category cloud-files Nextcloud @mozilla.org/mail/nextcloud;1
diff --git a/src/chrome/content/about.xul b/src/chrome/content/about.xul
deleted file mode 100644
index 1e1a7c1..0000000
--- a/src/chrome/content/about.xul
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/chrome/content/aboutLogo.png b/src/chrome/content/aboutLogo.png
deleted file mode 100644
index ff5de22..0000000
Binary files a/src/chrome/content/aboutLogo.png and /dev/null differ
diff --git a/src/chrome/content/logo.png b/src/chrome/content/logo.png
deleted file mode 100644
index 3550c51..0000000
Binary files a/src/chrome/content/logo.png and /dev/null differ
diff --git a/src/chrome/content/management.js b/src/chrome/content/management.js
deleted file mode 100644
index f3b6c6c..0000000
--- a/src/chrome/content/management.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/* global Components, pv */
-/**
- * @copyright Copyright (c) 2017, Olivier Paroz (github@oparoz.com)
- * @copyright Copyright (c) 2017, Philipp Kewisch
- * @copyright Copyright (c) 2017, Mark James
- * @copyright Copyright (c) 2017, Guillaume Viguier-Just (@guillaumev)
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- *
- */
-
-function onLoadProvider (provider) {
- let messenger = Components.classes["@mozilla.org/messenger;1"]
- .createInstance(Components.interfaces.nsIMessenger);
-
- let fileSpaceUsed = document.getElementById("file-space-used");
- let fileSpaceUsedSwatch = document.getElementById("file-space-used-swatch");
- let remainingFileSpace = document.getElementById("remaining-file-space");
- let remainingFileSpaceSwatch = document.getElementById("remaining-file-space-swatch");
- let totalSpace = provider.fileSpaceUsed + provider.remainingFileSpace;
- let pieScale = 2 * Math.PI / totalSpace;
- let spaceDiv = document.getElementById("provider-space-visuals");
- let service = document.getElementById("service");
-
- fileSpaceUsed.textContent = messenger.formatFileSize(provider.fileSpaceUsed);
- fileSpaceUsedSwatch.style.backgroundColor = pv.Colors.category20.values[0];
- remainingFileSpace.textContent = messenger.formatFileSize(provider.remainingFileSpace);
- remainingFileSpaceSwatch.style.backgroundColor = pv.Colors.category20.values[1];
- service.setAttribute("href", provider.serviceURL);
- service.appendChild(document.createTextNode(provider.displayName));
-
- let vis = new pv.Panel()
- .canvas(spaceDiv)
- .width(150)
- .height(150);
-
- vis.add(pv.Wedge)
- .data([provider.fileSpaceUsed, provider.remainingFileSpace])
- .left(75)
- .top(75)
- .innerRadius(30)
- .outerRadius(65)
- .angle(function (d) {
- return d * pieScale;
- });
-
- vis.add(pv.Label)
- .left(75)
- .top(75)
- .font("14px Sans-Serif")
- .textAlign("center")
- .textBaseline("middle")
- .text(messenger.formatFileSize(totalSpace));
-
- vis.render();
-}
diff --git a/src/chrome/content/management.xhtml b/src/chrome/content/management.xhtml
deleted file mode 100644
index 4373044..0000000
--- a/src/chrome/content/management.xhtml
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
-
- %htmlDTD;
- %managementDTD;
- %nextcloudDTD;
- ]>
-
-
-
-
-
-
-
-
-
-
-
- &nextcloudMgmt.provider;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/chrome/content/nextcloud.png b/src/chrome/content/nextcloud.png
deleted file mode 100644
index 12f765c..0000000
Binary files a/src/chrome/content/nextcloud.png and /dev/null differ
diff --git a/src/chrome/content/settings.js b/src/chrome/content/settings.js
deleted file mode 100644
index d354f6b..0000000
--- a/src/chrome/content/settings.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * @copyright Copyright (c) 2017, Olivier Paroz (github@oparoz.com)
- * @copyright Copyright (c) 2017, Philipp Kewisch
- * @copyright Copyright (c) 2017, Mark James
- * @copyright Copyright (c) 2017, Guillaume Viguier-Just (@guillaumev)
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- *
- */
-
-/**
- * Captures the settings provided by the user
- *
- * @returns {{displayName: {type: string, value: (string|string|string|Number)}, server: {type:
- * string, value: *}, port: {type: string, value: (string|string|string|Number)},
- * storageFolder: {type: string, value: (string|string|string|Number)}, username: {type:
- * string, value: (string|string|string|Number)}, protectUploads: {type: string, value:
- * (string|string|string|Number)}}}
- */
-function extraArgs () {
- let displayName = document.getElementById("displayName").value;
- let serverValue = document.getElementById("server").value.trim().replace(/\/+$/, "");
- let portValue = document.getElementById("port").value;
- let storageFolderValue = document.getElementById("storageFolder").value;
- let userValue = document.getElementById("username").value;
- let protectUploadsValue = document.getElementById("protectUploads").value;
-
- return {
- "displayName": {
- type: "char",
- value: displayName
- },
- "server": {
- type: "char",
- value: serverValue
- },
- "port": {
- type: "int",
- value: portValue
- },
- "storageFolder": {
- type: "char",
- value: storageFolderValue
- },
- "username": {
- type: "char",
- value: userValue
- },
- "protectUploads": {
- type: "char",
- value: protectUploadsValue
- }
- };
-}
diff --git a/src/chrome/content/settings.xhtml b/src/chrome/content/settings.xhtml
deleted file mode 100644
index 9cf0926..0000000
--- a/src/chrome/content/settings.xhtml
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
- %htmlDTD;
- %ncDTD;
- ]>
-
-
-
-
-
-
-
-