diff --git a/client/thunderbird-filelink-dl/.eslintrc b/client/thunderbird-filelink-dl/.eslintrc new file mode 100644 index 0000000..67ed648 --- /dev/null +++ b/client/thunderbird-filelink-dl/.eslintrc @@ -0,0 +1,474 @@ +{ + "env": { + "es6": true, + "webextensions": true + }, + "parserOptions": { + "ecmaVersion": 11 + }, + "globals": { + "self": true, + "messenger": true + }, + "rules": { + // Enforce one true brace style (opening brace on the same line) + // Allow single line (for now) because of the vast number of changes needed + "brace-style": [2, "1tbs", {"allowSingleLine": true}], + + // Enforce newline at the end of file, with no multiple empty lines. + "eol-last": 2, + + // Disallow using variables outside the blocks they are defined + "block-scoped-var": 2, + + // Allow trailing commas for easy list extension. Having them does not + // impair readability, but also not required either. + "comma-dangle": 0, + + // Enforce spacing before and after comma + "comma-spacing": [2, {"before": false, "after": true}], + + // Enforce one true comma style. + "comma-style": [2, "last"], + + // Enforce curly brace conventions for all control statements. + "curly": 2, + + // Enforce the spacing around the * in generator functions. + "generator-star-spacing": [2, "after"], + + // Require space before/after arrow function's arrow + "arrow-spacing": [2, { "before": true, "after": true }], + + // Enforces spacing between keys and values in object literal properties. + "key-spacing": [2, {"beforeColon": false, "afterColon": true, "mode": "minimum"}], + + // Disallow the omission of parentheses when invoking a constructor with no + // arguments. + "new-parens": 2, + + // Disallow use of the Array constructor. + "no-array-constructor": 2, + + // disallow use of the Object constructor + "no-new-object": 2, + + // Disallow Primitive Wrapper Instances + "no-new-wrappers": 2, + + // Disallow the catch clause parameter name being the same as a variable in + // the outer scope, to avoid confusion. + "no-catch-shadow": 2, + + // Disallow assignment in conditional expressions. + "no-cond-assign": 2, + + // Disallow use of debugger. + "no-debugger": 2, + + // Disallow deletion of variables (deleting properties is fine). + "no-delete-var": 2, + + // Disallow duplicate arguments in functions. + "no-dupe-args": 2, + + // Disallow duplicate keys when creating object literals. + "no-dupe-keys": 2, + + // Disallow a duplicate case label. + "no-duplicate-case": 2, + + // Disallow the use of empty character classes in regular expressions. + "no-empty-character-class": 2, + + // Disallow assigning to the exception in a catch block. + "no-ex-assign": 2, + + // Disallow adding to native types + "no-extend-native": 2, + + // Disallow double-negation boolean casts in a boolean context. + "no-extra-boolean-cast": 2, + + // Disallow unnecessary semicolons. + "no-extra-semi": 2, + + // Disallow mixed spaces and tabs for indentation. + "no-mixed-spaces-and-tabs": 2, + + // Disallow reassignments of native objects. + "no-native-reassign": 2, + + // Disallow use of octal literals. + "no-octal": 2, + + // Disallow comparisons where both sides are exactly the same. + "no-self-compare": 2, + + // Disallow sparse arrays, eg. let arr = [,,2]. + // Array destructuring is fine though: + // for (let [, breakpointPromise] of aPromises) + "no-sparse-arrays": 2, + + // Disallow trailing whitespace at the end of lines. + "no-trailing-spaces": 2, + + // Disallow use of the with statement. + "no-with": 2, + + // Disallow comparisons with the value NaN. + "use-isnan": 2, + + // Ensure that the results of typeof are compared against a valid string. + "valid-typeof": 2, + + // disallow the use of object properties of the global object (Math and + // JSON) as functions + "no-obj-calls": 2, + + // disallow use of octal escape sequences in string literals, such as + // var foo = "Copyright \251"; + "no-octal-escape": 2, + + // disallow use of void operator + "no-void": 2, + + // Disallow Yoda conditions (where literal value comes first). + "yoda": 2, + + // Require a space immediately following the // in a line comment. + "spaced-comment": [2, "always"], + + // Require use of the second argument for parseInt(). + "radix": 2, + + // Require spaces before/after unary operators (words on by default, + // nonwords off by default). + "space-unary-ops": [2, { "words": true, "nonwords": false }], + + // Enforce spacing after semicolons. + "semi-spacing": [2, {"before": false, "after": true}], + + // Disallow the use of Boolean literals in conditional expressions. + "no-unneeded-ternary": 2, + + // Disallow use of multiple spaces (sometimes used to align const values, + // array or object items, etc.). It's hard to maintain and doesn't add that + // much benefit. + "no-multi-spaces": 2, + + // Require spaces around operators, except for a|0. + // Disabled for now given eslint doesn't support default args yet + // "space-infix-ops": [2, {"int32Hint": true}], + + // Require a space around all keywords. + "keyword-spacing": 2, + + // Disallow space between function identifier and application. + "no-spaced-func": 2, + + // Disallow shadowing of names such as arguments. + "no-shadow-restricted-names": 2, + + // Disallow use of comma operator. + "no-sequences": 2, + + // Disallow use of assignment in return statement. It is preferable for a + // single line of code to have only one easily predictable effect. + "no-return-assign": 2, + + // Require return statements to either always or never specify values + "consistent-return": 2, + + // Disallow padding within blocks. + "padded-blocks": [2, "never"], + + // Disallow spaces inside parentheses. + "space-in-parens": [2, "never"], + + // Require space after keyword for anonymous functions, but disallow space + // after name of named functions. + "space-before-function-paren": [2, {"anonymous": "never", "named": "never"}], + + // Disallow unreachable statements after a return, throw, continue, or break + // statement. + "no-unreachable": 2, + + // Always require use of semicolons wherever they are valid. + "semi": [2, "always"], + + // Disallow empty statements. This will report an error for: + // try { something(); } catch (e) {} + // but will not report it for: + // try { something(); } catch (e) { /* Silencing the error because ...*/ } + // which is a valid use case. + "no-empty": 2, + + // Disallow declaring the same variable more than once (we use let anyway). + "no-redeclare": 2, + + // Warn about declaration of variables already declared in the outer scope. + // This isn't an error because it sometimes is useful to use the same name + // in a small helper function rather than having to come up with another + // random name. Still, making this a warning can help people avoid being + // confused. + "no-shadow": 2, + + // We use var-only-at-top-level instead of no-var as we allow top level + // vars. + "no-var": 0, + + // Disallow global and local variables that aren't used, but allow unused function arguments. + "no-unused-vars": [2, {"vars": "all", "args": "none", "varsIgnorePattern": "EXPORTED_SYMBOLS|rest"}], + + // Require padding inside curly braces + "object-curly-spacing": [2, "always"], + + // Disallow spaces inside of brackets + "array-bracket-spacing": [2, "never"], + + // Disallow control characters in regular expressions + "no-control-regex": 2, + + // Disallow invalid regular expression strings in RegExp constructors + "no-invalid-regexp": 2, + + // Disallow multiple spaces in regular expression literals + "no-regex-spaces": 2, + + // Disallow irregular whitespace + "no-irregular-whitespace": 2, + + // Disallow negating the left operand in `in` expressions + "no-negated-in-lhs": 2, + + // Allow constant expressions in conditions + // With 2.11.0 we can enable this with checkLoops: false + "no-constant-condition": [2, {"checkLoops": false}], + + // Disallow Regexs That Look Like Division + "no-div-regex": 2, + + // Disallow Iterator (using __iterator__) + "no-iterator": 2, + + // Enforce consistent linebreak style + "linebreak-style": [2, "unix"], + + // Enforces return statements in callbacks of array's methods + "array-callback-return": 2, + + // Verify super() calls in constructors + "constructor-super": 2, + + // Disallow modifying variables of class declarations + "no-class-assign": 2, + + // Disallow modifying variables that are declared using const + "no-const-assign": 2, + + // Disallow duplicate name in class members + "no-dupe-class-members": 2, + + // Disallow use of this/super before calling super() in constructors + "no-this-before-super": 2, + + // Disallow duplicate imports + "no-duplicate-imports": 2, + + // Disallow empty destructuring patterns + "no-empty-pattern": 2, + + // Disallow Labeled Statements + "no-labels": 2, + + // Disallow Multiline Strings + "no-multi-str": 2, + + // Disallow Symbol Constructor + "no-new-symbol": 2, + + // Disallow Initializing to undefined + "no-undef-init": 2, + + // Disallow control flow statements in finally blocks + "no-unsafe-finally": 2, + + // Disallow Unused Labels + "no-unused-labels": 2, + + // Disallow unnecessary computed property keys on objects + "no-useless-computed-key": 2, + + // Disallow unnecessary constructor + "no-useless-constructor": 2, + + // Disallow renaming import, export, and destructured assignments to the + // same name + "no-useless-rename": 2, + + // Enforce spacing between rest and spread operators and their expressions + "rest-spread-spacing": [2, "never"], + + // Disallow usage of spacing in template string expressions + "template-curly-spacing": [2, "never"], + + // Disallow the Unicode Byte Order Mark + "unicode-bom": [2, "never"], + + // Enforce spacing around the * in yield* expressions + "yield-star-spacing": [2, "after"], + + // Disallow Implied eval + "no-implied-eval": 2, + + // Disallow unnecessary function binding + "no-extra-bind": 2, + + // Disallow new For Side Effects + "no-new": 2, + + // Disallow Self Assignment + "no-self-assign": 2, + + // Disallow confusing multiline expressions + "no-unexpected-multiline": 2, + + // Require IIFEs to be Wrapped + "wrap-iife": [2, "inside"], + + // Disallow Unused Expressions + "no-unused-expressions": 2, + + // Disallow function or var declarations in nested blocks + "no-inner-declarations": 2, + + // Enforce newline before and after dot + "dot-location": [2, "property"], + + // Disallow Use of caller/callee + "no-caller": 2, + + // Disallow Case Statement Fallthrough + "no-fallthrough": 2, + + // Disallow Floating Decimals + "no-floating-decimal": 2, + + // Require Space Before Blocks + "space-before-blocks": 2, + + // Operators always before the line break + "operator-linebreak": [2, "after", { "overrides": { ":": "before", "?": "ignore"}}], + + // Restricts the use of parentheses to only where they are necessary + // Disabled for now since this also removes parens around assignments, e.g. let foo = bar == baz + // "no-extra-parens": [2, "all", { "conditionalAssign": false, "returnAssign": false, "nestedBinaryExpressions": false }], + + // Double quotes should be used. + "quotes": [2, "double", { "avoidEscape": true }], + + // Disallow if as the only statement in an else block. + "no-lonely-if": 2, + + // Not more than two empty lines with in the file, and no extra lines at + // beginning or end of file. + "no-multiple-empty-lines": [2, { "max": 2, "maxEOF": 0, "maxBOF": 0 }], + + // Make sure all setters have a corresponding getter + "accessor-pairs": 2, + + // Enforce spaces inside of single line blocks + "block-spacing": [2, "always"], + + // Disallow spaces inside of computed properties + "computed-property-spacing": [2, "never"], + + // Require consistent this (using |self|) + "consistent-this": [2, "self"], + + // Disallow unnecessary .call() and .apply() + "no-useless-call": 2, + + // Disallow named function expressions + "func-names": [2, "never"], + + // Enforce placing object properties on separate lines + "object-property-newline": [2, { "allowMultiplePropertiesPerLine": true }], + + // Enforce consistent line breaks inside braces + "object-curly-newline": [2, { "multiline": true }], + + // Disallow whitespace before properties + "no-whitespace-before-property": 2, + + // Disallow unnecessary escape usage + "no-useless-escape": 2, + + // Disallow mixes of different operators, but allow simple math operations. + "no-mixed-operators": [2, { + "groups": [ + /* ["+", "-", "*", "/", "%", "**"], */ + ["&", "|", "^", "~", "<<", ">>", ">>>"], + ["==", "!=", "===", "!==", ">", ">=", "<", "<="], + ["&&", "||"], + ["in", "instanceof"] + ] + }], + + // Disallow unnecessary concatenation of strings + "no-useless-concat": 2, + + // Disallow unmodified conditions of loops + "no-unmodified-loop-condition": 2, + + // Suggest using arrow functions as callbacks + "prefer-arrow-callback": [2, { "allowNamedFunctions": true }], + + // Suggest using the spread operator instead of .apply() + "prefer-spread": 2, + + // Quoting style for property names + "quote-props": ["error", "consistent-as-needed", { "keywords": true }], + + // Disallow negated conditions + "no-negated-condition": 2, + + // Enforce a maximum number of statements allowed per line + "max-statements-per-line": [2, { "max": 2 }], + + // Disallow arrow functions where they could be confused with comparisons + "no-confusing-arrow": 2, + + // Disallow Unnecessary Nested Blocks + "no-lone-blocks": 2, + + // Enforce minimum identifier length + "id-length": [2, { + "min": 3, + "exceptions": [ + /* dl */ "dl", + /* jQuery */ "$", + /* sorting */ "a", "b", + /* exceptions */ "e", "ex", + /* loop indices */ "i", "j", "k", "n", + /* coordinates */ "x", "y", + /* regexes */ "re", + /* known words */ "rc", "rv", "id", "OS", "os", "db", "op", + /* known html elements */ "tr", "td", "th", + /* mail/calendar words */ "to", "cc", + /* Components */ "Ci", "Cc", "Cu", "Cr", + ] + }], + + // Disallow lexical declarations in case/default clauses + "no-case-declarations": 2, + + // Enforce consistent indentation (4-space) + "indent": [2, 2, { "SwitchCase": 1 }], + + // The following rules will not be enabled currently, but are kept here for + // easier updates in the future. + "no-else-return": 0, + } +} diff --git a/client/thunderbird-filelink-dl/.gitignore b/client/thunderbird-filelink-dl/.gitignore index 94cf0f7..15af1aa 100644 --- a/client/thunderbird-filelink-dl/.gitignore +++ b/client/thunderbird-filelink-dl/.gitignore @@ -1,2 +1 @@ *.xpi -*.xpt diff --git a/client/thunderbird-filelink-dl/_locales/en/messages.json b/client/thunderbird-filelink-dl/_locales/en/messages.json new file mode 100644 index 0000000..73ed5f2 --- /dev/null +++ b/client/thunderbird-filelink-dl/_locales/en/messages.json @@ -0,0 +1,23 @@ +{ + "extensionDescription": { + "message": "Convert large attachments to links automatically, directly within the Composer window, using your own “DL” server/service instead of relying on 3rd-party providers" + }, + "extensionName": { + "message": "DL FileLink Provider for Thunderbird" + }, + "serviceName": { + "message": "DL" + }, + "insertUploadGrant": { + "message": "Insert Upload Grant" + }, + "serviceURL": { + "message": "Service URL" + }, + "username": { + "message": "Username" + }, + "password": { + "message": "Password" + } +} diff --git a/client/thunderbird-filelink-dl/api/api.js b/client/thunderbird-filelink-dl/api/api.js new file mode 100644 index 0000000..4c05dd5 --- /dev/null +++ b/client/thunderbird-filelink-dl/api/api.js @@ -0,0 +1,49 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * Portions Copyright (C) Philipp Kewisch, 2019 */ + +function ensureComposeWindow(window) { + if (window.document.documentElement.getAttribute("windowtype") != "msgcompose") { + throw new ExtensionError("Passed window is not a compose window"); + } +} + +this.dl = class extends ExtensionAPI { + getAPI(context) { + let { tabManager } = context.extension; + let windowTracker = Cu.getGlobalForObject(tabManager).windowTracker; + + return { + dl: { + async composeCurrentIdentity(windowId) { + // Something like this will likely exist with bug 1590121 fixed. + let composeWindow = windowTracker.getWindow(windowId, context); + ensureComposeWindow(composeWindow); + + let identity = composeWindow.gCurrentIdentity; + + return { + name: identity.fullName, + email: identity.email, + replyTo: identity.replyTo, + }; + }, + + async composeInsertHTML(windowId, html) { + // This API won't survive well. When this stops working, check out bug 1590121. + // Note it is also super unsafe, you need to make sure things are properly escaped in the + // caller. + + let composeWindow = windowTracker.getWindow(windowId, context); + ensureComposeWindow(composeWindow); + + let editor = composeWindow.GetCurrentEditor(); + editor.beginTransaction(); + editor.insertHTML(html); + editor.endTransaction(); + } + } + }; + } +}; diff --git a/client/thunderbird-filelink-dl/api/schema.json b/client/thunderbird-filelink-dl/api/schema.json new file mode 100644 index 0000000..e277194 --- /dev/null +++ b/client/thunderbird-filelink-dl/api/schema.json @@ -0,0 +1,26 @@ +[ + { + "namespace": "dl", + "functions": [ + { + "name": "composeInsertHTML", + "type": "function", + "async": true, + "description": "Insert HTML into a compose window.", + "parameters": [ + { "name": "windowId", "type": "integer", "minimum": 0 }, + { "name": "html", "type": "string" } + ] + }, + { + "name": "composeCurrentIdentity", + "type": "function", + "async": true, + "description": "Get currently selected compose window identity", + "parameters": [ + { "name": "windowId", "type": "integer", "minimum": 0 } + ] + } + ] + } +] diff --git a/client/thunderbird-filelink-dl/background/background.js b/client/thunderbird-filelink-dl/background/background.js new file mode 100644 index 0000000..7c246c9 --- /dev/null +++ b/client/thunderbird-filelink-dl/background/background.js @@ -0,0 +1,150 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * Portions Copyright (C) Philipp Kewisch, 2019 */ + +var abortControllers = new Map(); +var tickets = new Map(); + +async function accountPrefs(accountId) { + let { + [`accounts.${accountId}.restURL`]: restURL, + [`accounts.${accountId}.username`]: username, + [`accounts.${accountId}.password`]: password + } = await messenger.storage.local.get([ + `accounts.${accountId}.restURL`, + `accounts.${accountId}.username`, + `accounts.${accountId}.password`, + ]); + + return { restURL, username, password }; +} + +async function updateAccount(account) { + let resp = await request({ + account: account, + method: "GET", + url: "info", + }); + + let prefs = await accountPrefs(account.id); + + let { maxsize } = await resp.json(); + + await messenger.cloudFile.updateAccount(account.id, { + uploadSizeLimit: maxsize, + configured: !!(prefs.restURL && prefs.username && prefs.password) + }); +} + +async function request({ account, url, formData, signal, method="POST" }) { + let prefs = await accountPrefs(account.id); + let auth = "Basic " + btoa(prefs.username + ":" + prefs.password); + + if (!formData && method == "POST") { + formData = new FormData(); + } + + if (formData && !formData.has("msg")) { + formData.append("msg", "{}"); + } + + let headers = { + "Authorization": auth, + "X-Authorization": auth, + }; + + let resp = await fetch(new URL(url, prefs.restURL).href, { + method: method, + headers: headers, + body: formData, + signal: signal + }); + + if (!resp.ok) { + let json = await resp.json(); + throw new Error(json.error); + } + + return resp; +} + + +messenger.cloudFile.onFileUpload.addListener( + async (account, { id, name, data }) => { + let controller = new AbortController(); + abortControllers.set(id, controller); + + let formData = new FormData(); + console.log(data); + formData.append("file", new Blob([data]), name); + + try { + let resp = await request({ + account: account, + url: "newticket", + formData: formData, + signal: controller.signal + }); + let json = await resp.json(); + + tickets.set(id, json.id); + + return { url: json.url }; + } finally { + abortControllers.delete(id); + } + } +); + +messenger.cloudFile.onFileUploadAbort.addListener((account, id) => { + let controller = abortControllers.get(id); + if (controller) { + controller.abort(); + abortControllers.delete(id); + } +}); + +messenger.cloudFile.onFileDeleted.addListener(async (account, id) => { + let ticketId = tickets.get(id); + if (ticketId) { + await request({ + account: account, + url: "purgeticket/" + ticketId + }); + tickets.delete(id); + } +}); + + +messenger.cloudFile.getAllAccounts().then(async accounts => { + await Promise.all(accounts.map(updateAccount)); +}); + +messenger.cloudFile.onAccountAdded.addListener(account => updateAccount(account)); + +messenger.composeAction.onClicked.addListener(async (...args) => { + // getLastFocused doesn't return compose windows for some reson + let windows = await messenger.windows.getAll({ windowTypes: ["messageCompose"] }); + let focusedWindow = windows.find(window => window.focused); + + // TODO you might want to add a popup to select which account to create the grant for. Right now + // Thunderbird just supports one account, so this is fine (tm). + let accounts = await messenger.cloudFile.getAllAccounts(); + + let identity = await messenger.dl.composeCurrentIdentity(focusedWindow.id); + + let formData = new FormData(); + formData.append("msg", JSON.stringify({ notify: identity.email })); + + let response = await request({ + account: accounts[0], + url: "newgrant", + formData: formData + }); + + let json = await response.json(); + + let url = encodeURI(json.url); + messenger.dl.composeInsertHTML(focusedWindow.id, `${url}`); +}); diff --git a/client/thunderbird-filelink-dl/build.sh b/client/thunderbird-filelink-dl/build.sh deleted file mode 100755 index 07af23c..0000000 --- a/client/thunderbird-filelink-dl/build.sh +++ /dev/null @@ -1,128 +0,0 @@ -#!/bin/bash -# build.sh -- builds JAR and XPI files for mozilla extensions -# by Nickolay Ponomarev -# (original version based on Nathan Yergler's build script) -# Most recent version is at - -# This script assumes the following directory structure: -# ./ -# chrome.manifest (optional - for newer extensions) -# install.rdf -# (other files listed in $ROOT_FILES) -# -# content/ | -# locale/ |} these can be named arbitrary and listed in $CHROME_PROVIDERS -# skin/ | -# -# defaults/ | -# components/ |} these must be listed in $ROOT_DIRS in order to be packaged -# ... | -# -# It uses a temporary directory ./build when building; don't use that! -# Script's output is: -# ./$APP_NAME.xpi -# ./$APP_NAME.jar (only if $KEEP_JAR=1) -# ./files -- the list of packaged files -# -# Note: It modifies chrome.manifest when packaging so that it points to -# chrome/$APP_NAME.jar!/* - -# -# default configuration file is ./config_build.sh, unless another file is -# specified in command-line. Available config variables: -APP_NAME= # short-name, jar and xpi files name. Must be lowercase with no spaces -CHROME_PROVIDERS= # which chrome providers we have (space-separated list) -CLEAN_UP= # delete the jar / "files" when done? (1/0) -ROOT_FILES= # put these files in root of xpi (space separated list of leaf filenames) -ROOT_DIRS= # ...and these directories (space separated list) -BEFORE_BUILD= # run this before building (bash command) -AFTER_BUILD= # ...and this after the build (bash command) - -if [ -z $1 ]; then - . ./config_build.sh -else - . $1 -fi - -if [ -z $APP_NAME ]; then - echo "You need to create build config file first!" - echo "Read comments at the beginning of this script for more info." - exit; -fi - -ROOT_DIR=`pwd` -TMP_DIR=build - -#uncomment to debug -#set -x - -# remove any left-over files from previous build -rm -f $APP_NAME.jar $APP_NAME.xpi files -rm -rf $TMP_DIR - -$BEFORE_BUILD - -mkdir --parents --verbose $TMP_DIR/chrome - -# generate the JAR file, excluding CVS, SVN, and temporary files -JAR_FILE=$TMP_DIR/chrome/$APP_NAME.jar -echo "Generating $JAR_FILE..." -for CHROME_SUBDIR in $CHROME_PROVIDERS; do - find $CHROME_SUBDIR \( -path '*CVS*' -o -path '*.svn*' \) -prune -o -type f -print | grep -v \~ >> files -done - -zip -0 -r $JAR_FILE -@ < files -# The following statement should be used instead if you don't wish to use the JAR file -#cp --verbose --parents `cat files` $TMP_DIR/chrome - -# prepare components and defaults -echo "Copying various files to $TMP_DIR folder..." -for DIR in $ROOT_DIRS; do - mkdir $TMP_DIR/$DIR - FILES="`find $DIR \( -path '*CVS*' -o -path '*.svn*' \) -prune -o -type f -print | grep -v \~`" - echo $FILES >> files - cp --verbose --parents $FILES $TMP_DIR -done - -# Copy other files to the root of future XPI. -for ROOT_FILE in $ROOT_FILES install.rdf chrome.manifest; do - cp --verbose $ROOT_FILE $TMP_DIR - if [ -f $ROOT_FILE ]; then - echo $ROOT_FILE >> files - fi -done - -cd $TMP_DIR - -if [ -f "chrome.manifest" ]; then - echo "Preprocessing chrome.manifest..." - # You think this is scary? - #s/^(content\s+\S*\s+)(\S*\/)(.*)$/\1jar:chrome\/$APP_NAME\.jar!\/\2\3/ - #s/^(skin|locale)(\s+\S*\s+\S*\s+)(.*\/)$/\1\2jar:chrome\/$APP_NAME\.jar!\/\3/ - # - # Then try this! (Same, but with characters escaped for bash :) - sed -i -r s/^\(content\\s+\\S*\\s+\)\(\\S*\\/\)\(.*\)$/\\1jar:chrome\\/$APP_NAME\\.jar!\\/\\2\\3/ chrome.manifest - sed -i -r s/^\(skin\|locale\)\(\\s+\\S*\\s+\\S*\\s+\)\(.*\\/\)$/\\1\\2jar:chrome\\/$APP_NAME\\.jar!\\/\\3/ chrome.manifest - - # (it simply adds jar:chrome/whatever.jar!/ at appropriate positions of chrome.manifest) -fi - -# generate the XPI file -echo "Generating $APP_NAME.xpi..." -zip -r ../$APP_NAME.xpi * - -cd "$ROOT_DIR" - -echo "Cleanup..." -if [ $CLEAN_UP = 0 ]; then - # save the jar file - mv $TMP_DIR/chrome/$APP_NAME.jar . -else - rm ./files -fi - -# remove the working files -rm -rf $TMP_DIR -echo "Done!" - -$AFTER_BUILD diff --git a/client/thunderbird-filelink-dl/chrome.manifest b/client/thunderbird-filelink-dl/chrome.manifest deleted file mode 100644 index 3669e95..0000000 --- a/client/thunderbird-filelink-dl/chrome.manifest +++ /dev/null @@ -1,12 +0,0 @@ -content thunderbird-filelink-dl chrome/content/ -skin thunderbird-filelink-dl default chrome/skin/ -locale thunderbird-filelink-dl en-US chrome/locale/en-US/ -locale thunderbird-filelink-dl en-US chrome/locale/hu/ - -component {c0bee36d-3c0d-460b-bb9a-f0e9c873a833} components/nsDL.js -contract @thregr.org/thunderbird-filelink-dl;1 {c0bee36d-3c0d-460b-bb9a-f0e9c873a833} -category cloud-files DL @thregr.org/thunderbird-filelink-dl;1 - -interfaces components/nsDL.xpt - -overlay chrome://messenger/content/messengercompose/messengercompose.xul chrome://thunderbird-filelink-dl/content/compose.xul diff --git a/client/thunderbird-filelink-dl/chrome/content/compose.js b/client/thunderbird-filelink-dl/chrome/content/compose.js deleted file mode 100644 index 5be8a4d..0000000 --- a/client/thunderbird-filelink-dl/chrome/content/compose.js +++ /dev/null @@ -1,85 +0,0 @@ -const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; - -Cu.import("resource:///modules/Services.jsm"); -Cu.import("resource:///modules/cloudFileAccounts.js"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -var composeBundle = Services.strings.createBundle( - "chrome://thunderbird-filelink-dl/locale/compose.properties"); - -function insertUploadGrantListener(provider) -{ - this.provider = provider; -} - -insertUploadGrantListener.prototype = -{ - id: null, - - onStartRequest: function(aRequest, aContext) - { - // show some progress - ToggleWindowLock(true); - document.getElementById("compose-progressmeter").setAttribute("mode", "undetermined"); - document.getElementById("statusbar-progresspanel").collapsed = false; - - let msg = composeBundle.GetStringFromName("newGrantProgress"); - document.getElementById('statusText').setAttribute('label', msg); - }, - - onStopRequest: function(aRequest, aContext, aStatusCode) - { - // restore progress state - ToggleWindowLock(false); - document.getElementById("compose-progressmeter").setAttribute("mode", "normal"); - document.getElementById("compose-progressmeter").setAttribute("value", 0); - document.getElementById("statusbar-progresspanel").collapsed = true; - - if(aStatusCode != Cr.NS_OK) - { - let msg = composeBundle.GetStringFromName("newGrantFailure"); - document.getElementById('statusText').setAttribute('label', msg); - } - else - { - // insert grant URL - let url = this.provider.urlForGrant(this.id); - let editor = GetCurrentEditor(); - editor.beginTransaction(); - editor.insertHTML("" + encodeURI(url) + "\n"); - editor.endTransaction(); - document.getElementById('statusText').setAttribute('label', ''); - } - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver, Ci.nsISupportsWeakReference]) -}; - -function insertUploadGrant() -{ - // search for a DL account - let provider = Cc["@thregr.org/thunderbird-filelink-dl;1"].getService(Ci.nsIDL); - let accounts = cloudFileAccounts.getAccountsForType(provider.type); - if(!accounts.length) - { - let title = composeBundle.GetStringFromName("accountNeededTitle"); - let msg = composeBundle.GetStringFromName("accountNeededMsg"); - let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService); - if(prompts.confirm(window, title, msg)) - cloudFileAccounts.addAccountDialog(); - return; - } - - // initialize the first valid DL account - let accountKey = accounts[0].accountKey; - try { provider.init(accountKey); } - catch(e) - { - Cu.reportError(e); - return; - } - - // request a new grant URL - let listener = new insertUploadGrantListener(provider); - listener.id = provider.newGrant(listener, gCurrentIdentity.email); -} diff --git a/client/thunderbird-filelink-dl/chrome/content/compose.xul b/client/thunderbird-filelink-dl/chrome/content/compose.xul deleted file mode 100644 index 9cdf58d..0000000 --- a/client/thunderbird-filelink-dl/chrome/content/compose.xul +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/client/thunderbird-filelink-dl/chrome/content/management.js b/client/thunderbird-filelink-dl/chrome/content/management.js deleted file mode 100644 index e1cf024..0000000 --- a/client/thunderbird-filelink-dl/chrome/content/management.js +++ /dev/null @@ -1,77 +0,0 @@ -Components.utils.import("resource:///modules/Services.jsm"); - -function onLoadProvider(provider) -{ - let messenger = Components.classes["@mozilla.org/messenger;1"] - .createInstance(Components.interfaces.nsIMessenger); - - let bundle = Services.strings.createBundle("chrome://messenger/locale/messenger.properties"); - let unknownSize = bundle.GetStringFromName("attachmentSizeUnknown"); - - let urlElem = document.getElementById("provider-url"); - urlElem.textContent = provider.serviceURL; - urlElem.setAttribute("href", provider.serviceURL); - - // Preferences - let prefBranch = Services.prefs.getBranch("mail.cloud_files.accounts." - + provider.accountKey + "."); - - let defTotalDays = Math.ceil(prefBranch.getIntPref("defaults.total") / (3600 * 24)); - let defTotalElem = document.getElementById("defaults-total"); - defTotalElem.textContent = defTotalDays; - - let defLastDlDays = Math.ceil(prefBranch.getIntPref("defaults.lastdl") / (3600 * 24)); - let defLastDlElem = document.getElementById("defaults-lastdl"); - defLastDlElem.textContent = defLastDlDays; - - let defMaxDl = prefBranch.getIntPref("defaults.maxdl"); - let defMaxDlElem = document.getElementById("defaults-maxdl"); - defMaxDlElem.textContent = defMaxDl; - - // Total/Used space chart - let mfsElem = document.getElementById("max-file-size"); - let mfs = provider.fileUploadSizeLimit; - mfsElem.textContent = (mfs < 0? unknownSize: messenger.formatFileSize(mfs)); - - let fsuElem = document.getElementById("file-space-used"); - let fsu = provider.fileSpaceUsed; - fsuElem.textContent = (fsu < 0? unknownSize: messenger.formatFileSize(fsu)); - let fileSpaceUsedSwatch = document.getElementById("file-space-used-swatch"); - fileSpaceUsedSwatch.style.backgroundColor = pv.Colors.category20.values[0]; - - let fsrElem = document.getElementById("remaining-file-space"); - let fsr = provider.remainingFileSpace; - fsrElem.textContent = (fsr < 0? unknownSize: messenger.formatFileSize(fsr)); - let remainingFileSpaceSwatch = document.getElementById("remaining-file-space-swatch"); - remainingFileSpaceSwatch.style.backgroundColor = pv.Colors.category20.values[1]; - - let totalSpace = fsu + fsr; - if(totalSpace <= 0) - document.getElementById("provider-spacebox").setAttribute("unknown-space", "true"); - else - { - let pieScale = 2 * Math.PI / totalSpace; - let spaceDiv = document.getElementById("provider-space-visuals"); - let vis = new pv.Panel().canvas(spaceDiv) - .width(150) - .height(150); - vis.add(pv.Wedge) - .data([fsu, fsr]) - .left(75) - .top(75) - .innerRadius(30) - .outerRadius(65) - .angle(function(d) d * pieScale); - - vis.add(pv.Label) - .left(75) - .top(75) - .font("14px Sans-Serif") - .textAlign("center") - .textBaseline("middle") - .text(messenger.formatFileSize(totalSpace)); - - vis.render(); - document.getElementById("provider-spacebox").removeAttribute("unknown-space"); - } -} diff --git a/client/thunderbird-filelink-dl/chrome/content/management.xhtml b/client/thunderbird-filelink-dl/chrome/content/management.xhtml deleted file mode 100644 index b377df8..0000000 --- a/client/thunderbird-filelink-dl/chrome/content/management.xhtml +++ /dev/null @@ -1,73 +0,0 @@ - - %htmlDTD; - %managementDTD; - %mngtDTD; -]> - - - - - - - - - - - &DL_mngt.name; - - - - - - Server settings - - &DL_mngt.maxSize; - - - - &DL_mngt.total; - - - - &DL_mngt.lastdl; - - - - &DL_mngt.maxdl; - - - - - - - - - &cloudfileMgmt.usedSpace; - - - - - &cloudfileMgmt.unusedSpace; - - - - - - - diff --git a/client/thunderbird-filelink-dl/chrome/content/settings.js b/client/thunderbird-filelink-dl/chrome/content/settings.js deleted file mode 100644 index a337173..0000000 --- a/client/thunderbird-filelink-dl/chrome/content/settings.js +++ /dev/null @@ -1,7 +0,0 @@ -function extraArgs() -{ - return { - "restURL": { type: "char", value: document.getElementById("restURL").value }, - "username": { type: "char", value: document.getElementById("username").value }, - }; -} diff --git a/client/thunderbird-filelink-dl/chrome/content/settings.xhtml b/client/thunderbird-filelink-dl/chrome/content/settings.xhtml deleted file mode 100644 index 83f137b..0000000 --- a/client/thunderbird-filelink-dl/chrome/content/settings.xhtml +++ /dev/null @@ -1,22 +0,0 @@ - - %htmlDTD; - %settingsDTD; -]> - - - - - - - - &DL_settings.restURL; - - &DL_settings.username; - - - - diff --git a/client/thunderbird-filelink-dl/chrome/locale/en-US/compose.dtd b/client/thunderbird-filelink-dl/chrome/locale/en-US/compose.dtd deleted file mode 100644 index 7cf2822..0000000 --- a/client/thunderbird-filelink-dl/chrome/locale/en-US/compose.dtd +++ /dev/null @@ -1 +0,0 @@ - diff --git a/client/thunderbird-filelink-dl/chrome/locale/en-US/compose.properties b/client/thunderbird-filelink-dl/chrome/locale/en-US/compose.properties deleted file mode 100644 index 5d53de9..0000000 --- a/client/thunderbird-filelink-dl/chrome/locale/en-US/compose.properties +++ /dev/null @@ -1,4 +0,0 @@ -accountNeededTitle=A DL FileLink account is required -accountNeededMsg=Do you want to create an account now? -newGrantFailure=Cannot generate a new grant -newGrantProgress=Requesting new grant… diff --git a/client/thunderbird-filelink-dl/chrome/locale/en-US/management.dtd b/client/thunderbird-filelink-dl/chrome/locale/en-US/management.dtd deleted file mode 100644 index 99f31b5..0000000 --- a/client/thunderbird-filelink-dl/chrome/locale/en-US/management.dtd +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/client/thunderbird-filelink-dl/chrome/locale/en-US/settings.dtd b/client/thunderbird-filelink-dl/chrome/locale/en-US/settings.dtd deleted file mode 100644 index aef9fc3..0000000 --- a/client/thunderbird-filelink-dl/chrome/locale/en-US/settings.dtd +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/thunderbird-filelink-dl/chrome/locale/hu/compose.dtd b/client/thunderbird-filelink-dl/chrome/locale/hu/compose.dtd deleted file mode 100644 index 6ca04a9..0000000 --- a/client/thunderbird-filelink-dl/chrome/locale/hu/compose.dtd +++ /dev/null @@ -1 +0,0 @@ - diff --git a/client/thunderbird-filelink-dl/chrome/locale/hu/compose.properties b/client/thunderbird-filelink-dl/chrome/locale/hu/compose.properties deleted file mode 100644 index 3d7abae..0000000 --- a/client/thunderbird-filelink-dl/chrome/locale/hu/compose.properties +++ /dev/null @@ -1,4 +0,0 @@ -accountNeededTitle=A DL-fájlhivatkozás fiók szükséges -accountNeededMsg=Fiók létrehozása most? -newGrantFailure=Nem lehet új támogatást létrehozni -newGrantProgress=Új támogatás kérése… diff --git a/client/thunderbird-filelink-dl/chrome/locale/hu/management.dtd b/client/thunderbird-filelink-dl/chrome/locale/hu/management.dtd deleted file mode 100644 index 347bcc3..0000000 --- a/client/thunderbird-filelink-dl/chrome/locale/hu/management.dtd +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/client/thunderbird-filelink-dl/chrome/locale/hu/settings.dtd b/client/thunderbird-filelink-dl/chrome/locale/hu/settings.dtd deleted file mode 100644 index 3b2e241..0000000 --- a/client/thunderbird-filelink-dl/chrome/locale/hu/settings.dtd +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/client/thunderbird-filelink-dl/chrome/skin/compose.css b/client/thunderbird-filelink-dl/chrome/skin/compose.css deleted file mode 100644 index a028e16..0000000 --- a/client/thunderbird-filelink-dl/chrome/skin/compose.css +++ /dev/null @@ -1,4 +0,0 @@ -#menuitem-dl-insertgrant, -#button-dl-insertgrant { - list-style-image: url("chrome://thunderbird-filelink-dl/skin/dl-icon.png"); -} diff --git a/client/thunderbird-filelink-dl/components/nsDL.idl b/client/thunderbird-filelink-dl/components/nsDL.idl deleted file mode 100644 index 5d69cbb..0000000 --- a/client/thunderbird-filelink-dl/components/nsDL.idl +++ /dev/null @@ -1,9 +0,0 @@ -#include "nsIMsgCloudFileProvider.idl" - -[scriptable, uuid(044bc680-05d3-11e4-bc1f-83368bc98e1f)] -interface nsIDL : nsIMsgCloudFileProvider -{ - ACString newGrant(in nsIRequestObserver aCallback, in ACString aEmail); - void deleteGrant(in ACString aId, in nsIRequestObserver aCallback); - ACString urlForGrant(in ACString aId); -}; diff --git a/client/thunderbird-filelink-dl/components/nsDL.js b/client/thunderbird-filelink-dl/components/nsDL.js deleted file mode 100644 index 6fee1f4..0000000 --- a/client/thunderbird-filelink-dl/components/nsDL.js +++ /dev/null @@ -1,393 +0,0 @@ -const TYP = "DL"; -const AID = "thunderbird-filelink-dl@thregr.org"; -const CID = "{c0bee36d-3c0d-460b-bb9a-f0e9c873a833}"; -const VER = "0.17.2"; - -const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource:///modules/cloudFileAccounts.js"); - -// 'File' property not available in in TB<38 -try { Cu.importGlobalProperties(['File']); } -catch(e) {} - -if(!("createFromNsIFile" in File)) -{ - // 'createFromNsIFile' was introduced in TB 52 while breaking the old File - // constructor at the same time. Nice. Wire a stub for old versions of TB. - File.createFromNsIFile = function(file) - { - return new File(file); - }; -} - -function nsDL() {} - -nsDL.prototype = -{ - // Required interface - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDL, Ci.nsIMsgCloudFileProvider]), - classID: Components.ID(CID), - - get type() TYP, - get displayName() TYP, - get version() VER, - get iconClass() "chrome://thunderbird-filelink-dl/skin/dl-icon.png", - get settingsURL() "chrome://thunderbird-filelink-dl/content/settings.xhtml", - get managementURL() "chrome://thunderbird-filelink-dl/content/management.xhtml", - get accountKey() this._accountKey, - get serviceURL() this._masterPath, - get lastError() this._lastErrorText, - get fileUploadSizeLimit() this._maxSize, - get remainingFileSpace() -1, - get fileSpaceUsed() -1, - - - // Internal variables - _accountKey: null, - _prefBranch: null, - _username: null, - _password: null, - _defaults: null, - - _restURL: null, - _masterPath: null, - _maxSize: null, - - _lastErrorText: null, - _tickets: {}, - _grants: {}, - _grantCount: 0, - - - // Support functions - _request: function(request, msg, success_cb, failure_cb, abort_cb=null, file=null) - { - let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest); - let method = (!msg && !file? "GET": "POST"); - req.mozBackgroundRequest = true; - req.open(method, this._restURL + "/" + request, true); - req.setRequestHeader("User-agent", AID + "/" + VER); - - let auth = "Basic " + btoa(this._username + ":" + this._password); - req.setRequestHeader("Authorization", auth); - req.setRequestHeader("X-Authorization", auth); - - req.onerror = function() - { - failure_cb(req, null); - }; - - req.onabort = function() - { - if(abort_cb) - abort_cb(req); - else - failure_cb(req, null); - }; - - req.onload = function() - { - // try to parse the output (if any) - let res = null; - - try - { - if(req.responseText) - res = JSON.parse(req.responseText); - } - catch(e if e instanceof SyntaxError) - { - // ignored - } - - if(req.status < 200 || req.status >= 400) - failure_cb(req, res); - else - success_cb(req, res); - }; - - if(!msg && !file) - req.send(); - else - { - let data = Cc["@mozilla.org/files/formdata;1"].createInstance(Ci.nsIDOMFormData); - if(msg) data.append("msg", JSON.stringify(msg)); - if(file) data.append("file", File.createFromNsIFile(file)); - req.send(data); - } - - return req; - }, - - - _setDefaults: function(v) - { - this._prefBranch.setIntPref("defaults.total", v.total); - this._prefBranch.setIntPref("defaults.lastdl", v.lastdl); - this._prefBranch.setIntPref("defaults.maxdl", v.maxdl); - this._defaults = v; - }, - - - _getPassword: function(aWithUI=true) - { - let logins = Services.logins.findLogins({}, this._restURL, null, this._restURL); - for each(let info in logins) - { - if(info.username == this._username) - return loginInfo.password; - } - if(!aWithUI) - return null; - - // no login data, prompt for a new password - let serverURL = this._restURL; - let userPos = serverURL.indexOf("//") + 2; - let usernamePart = encodeURIComponent(this._username) + '@'; - serverURL = serverURL.substr(0, userPos) + usernamePart + serverURL.substr(userPos); - - let messengerBundle = Services.strings.createBundle( - "chrome://messenger/locale/messenger.properties"); - let promptString = messengerBundle.formatStringFromName( - "passwordPrompt", [this._username, this.displayName], 2); - - let win = Services.wm.getMostRecentWindow(null); - let prompt = Services.ww.getNewAuthPrompter(win); - let password = {value: null}; - if(prompt.promptPassword(this.displayName, promptString, serverURL, - prompt.SAVE_PASSWORD_PERMANENTLY, password)) - return password.value; - - return null; - }, - - - _clearPassword: function() - { - this._password = null; - let logins = Services.logins.findLogins({}, this._restURL, null, this._restURL); - for each(let info in logins) - { - if(info.username == this._username) - Services.logins.removeLogin(info); - } - }, - - - _genericFailure: function(req, res, aCallback) - { - // set the error text, if any - if(res && res.error) - this._lastErrorText = res.error; - - // check for authentication failures - if(req.status == 401) - { - this._clearPassword(); - aCallback.onStopRequest(null, this, Ci.nsIMsgCloudFileProvider.authErr); - return; - } - - aCallback.onStopRequest(null, this, Cr.NS_ERROR_FAILURE); - }, - - - // Implementation - init: function(aAccountKey) - { - this._accountKey = aAccountKey; - this._prefBranch = Services.prefs.getBranch("mail.cloud_files.accounts." + aAccountKey + "."); - this._restURL = this._prefBranch.getCharPref("restURL"); - this._username = this._prefBranch.getCharPref("username"); - - // try to fetch ticket defaults (otherwise wait for init) - if(this._prefBranch.prefHasUserValue("defaults.total")) - { - /* TODO: for now, always fetch server defaults until values are not fully - customizable, in order for the client not getting "stuck" forever. - - this._defaults = {total: this._prefBranch.getIntPref("defaults.total"), - lastdl: this._prefBranch.getIntPref("defaults.lastdl"), - maxdl: this._prefBranch.getIntPref("defaults.maxdl")}; - */ - } - }, - - - createExistingAccount: function(aCallback) - { - this.refreshUserInfo(true, aCallback); - }, - - - refreshUserInfo: function(aWithUI, aCallback) - { - if(Services.io.offline) - throw Ci.nsIMsgCloudFileProvider.offlineErr; - aCallback.onStartRequest(null, this); - if(!(this._password = this._getPassword(aWithUI))) - { - aCallback.onStopRequest(null, this, Ci.nsIMsgCloudFileProvider.authErr); - return; - } - - let success_cb = function(req, res) - { - // get some interesting variables from the service - this._masterPath = res.masterpath; - this._maxSize = res.maxsize; - - // set ticket defaults if we don't have any yet - if(!this._defaults) - { - this._setDefaults({total: res.defaults.ticket.total, - lastdl: res.defaults.ticket.lastdl, - maxdl: res.defaults.ticket.maxdl}); - } - - aCallback.onStopRequest(null, this, Cr.NS_OK); - }.bind(this); - - let failure_cb = function(req, res) - { - this._genericFailure(req, res, aCallback); - }.bind(this); - - this._request("info", null, success_cb, failure_cb); - }, - - - uploadFile: function(aFile, aCallback) - { - if(Services.io.offline) - throw Ci.nsIMsgCloudFileProvider.offlineErr; - aCallback.onStartRequest(null, this); - if(!(this._password = this._getPassword())) - { - aCallback.onStopRequest(null, this, Ci.nsIMsgCloudFileProvider.authErr); - return; - } - - let success_cb = function(req, res) - { - this._tickets[aFile.spec].res = res; - aCallback.onStopRequest(null, this, Cr.NS_OK); - }.bind(this); - - let failure_cb = function(req, res) - { - delete this._tickets[aFile.spec]; - this._genericFailure(req, res, aCallback); - }.bind(this); - - let abort_cb = function(req) - { - delete this._tickets[aFile.spec]; - aCallback.onStopRequest(null, this, Ci.nsIMsgCloudFileProvider.uploadCanceled); - }.bind(this); - - let req = this._request("newticket", {}, success_cb, failure_cb, abort_cb, aFile); - this._tickets[aFile.spec] = {req: req, res: null}; - }, - - - urlForFile: function(aFile) - { - return this._tickets[aFile.spec].res.url; - }, - - - cancelFileUpload: function(aFile) - { - this._tickets[aFile.spec].req.abort(); - }, - - - deleteFile: function(aFile, aCallback) - { - if(Services.io.offline) - throw Ci.nsIMsgCloudFileProvider.offlineErr; - aCallback.onStartRequest(null, this); - if(!(this._password = this._getPassword())) - { - aCallback.onStopRequest(null, this, Ci.nsIMsgCloudFileProvider.authErr); - return; - } - - let success_cb = function(req, res) - { - delete this._tickets[aFile.spec]; - aCallback.onStopRequest(null, this, Cr.NS_OK); - }.bind(this); - - let failure_cb = function(req, res) - { - this._genericFailure(req, res, aCallback); - }.bind(this); - - let id = encodeURIComponent(this._tickets[aFile.spec].res.id); - this._request("purgeticket/" + id, {}, success_cb, failure_cb); - }, - - - newGrant: function(aCallback, aEmail) - { - if(Services.io.offline) - throw Ci.nsIMsgCloudFileProvider.offlineErr; - aCallback.onStartRequest(null, this); - if(!(this._password = this._getPassword())) - { - aCallback.onStopRequest(null, this, Ci.nsIMsgCloudFileProvider.authErr); - return; - } - - let id = this._grantCount++; - - let success_cb = function(req, res) - { - this._grants[id].res = res; - aCallback.onStopRequest(null, this, Cr.NS_OK); - }.bind(this); - - let failure_cb = function(req, res) - { - delete this._grants[id]; - this._genericFailure(req, res, aCallback); - }.bind(this); - - let req = this._request("newgrant", {'notify': aEmail}, success_cb, failure_cb); - this._grants[id] = {req: req, res: null}; - return id; - }, - - - urlForGrant: function(id) - { - return this._grants[id].res.url; - }, - - - deleteGrant: function(id, aCallback) - { - throw Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - - - // Stubs - createNewAccount: function() - { - return Cr.NS_ERROR_NOT_IMPLEMENTED; - }, - - - providerUrlForError: function(aError) - { - return ""; - }, -}; - - -const NSGetFactory = XPCOMUtils.generateNSGetFactory([nsDL]); diff --git a/client/thunderbird-filelink-dl/config_build.sh b/client/thunderbird-filelink-dl/config_build.sh deleted file mode 100644 index 6437b12..0000000 --- a/client/thunderbird-filelink-dl/config_build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# Build config for the build script, build.sh. Look there for more info. - -APP_NAME=thunderbird-filelink-dl -CHROME_PROVIDERS="chrome" -CLEAN_UP=1 -ROOT_FILES= -ROOT_DIRS="components" -BEFORE_BUILD="/usr/lib/thunderbird-devel/sdk/bin/typelib.py -I /usr/share/idl/thunderbird components/nsDL.idl -o components/nsDL.xpt" -AFTER_BUILD= diff --git a/client/thunderbird-filelink-dl/content/management.css b/client/thunderbird-filelink-dl/content/management.css new file mode 100644 index 0000000..a62bff6 --- /dev/null +++ b/client/thunderbird-filelink-dl/content/management.css @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * Portions Copyright (C) Philipp Kewisch, 2019 */ + + +label { + display: block; +} diff --git a/client/thunderbird-filelink-dl/content/management.js b/client/thunderbird-filelink-dl/content/management.js new file mode 100644 index 0000000..f6dfc2e --- /dev/null +++ b/client/thunderbird-filelink-dl/content/management.js @@ -0,0 +1,76 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * Portions Copyright (C) Philipp Kewisch, 2019 */ + +let currentAccountId = new URL(location.href).searchParams.get("accountId"); + +async function accountPrefs(accountId, values) { + if (values) { + return messenger.storage.local.set({ + [`accounts.${accountId}.restURL`]: values.restURL, + [`accounts.${accountId}.username`]: values.username, + [`accounts.${accountId}.password`]: values.password + }); + } else { + let { + [`accounts.${accountId}.restURL`]: restURL, + [`accounts.${accountId}.username`]: username, + [`accounts.${accountId}.password`]: password + } = await messenger.storage.local.get({ + [`accounts.${accountId}.restURL`]: "", + [`accounts.${accountId}.username`]: "", + [`accounts.${accountId}.password`]: "" + }); + + return { restURL, username, password }; + } +} + +// https://davidwalsh.name/javascript-debounce-function +// which was adapted from underscore, which is under MIT license. +// Some adaptions to be more ES6-like and match eslint +// TODO This function needs to be adapted to wait for the promise that func +// returns to be resolved before calling the next func. +function debounce(func, wait, immediate) { + let timeout; + return function(...args) { + let callNow = immediate && !timeout; + clearTimeout(timeout); + + timeout = setTimeout(() => { + timeout = null; + if (!immediate) { + func.apply(this, args); + } + }, wait); + + if (callNow) { + func.apply(this, args); + } + }; +} +// End MIT license code + +document.body.addEventListener("input", debounce(async () => { + let settings = { + restURL: document.getElementById("restURL").value, + username: document.getElementById("username").value, + password: document.getElementById("password").value + }; + + await accountPrefs(currentAccountId, settings); + + let configured = !!(settings.restURL && settings.username && settings.password); + await messenger.cloudFile.updateAccount(currentAccountId, { configured }); +}, 500)); + +document.querySelectorAll("[data-l10n-id]").forEach(node => { + node.textContent = messenger.i18n.getMessage(node.getAttribute("data-l10n-id")); +}); + +accountPrefs(currentAccountId).then((prefs) => { + document.getElementById("restURL").value = prefs.restURL; + document.getElementById("username").value = prefs.username; + document.getElementById("password").value = prefs.password; +}); diff --git a/client/thunderbird-filelink-dl/chrome/skin/dl-icon.png b/client/thunderbird-filelink-dl/images/dl-icon.png similarity index 100% rename from client/thunderbird-filelink-dl/chrome/skin/dl-icon.png rename to client/thunderbird-filelink-dl/images/dl-icon.png diff --git a/client/thunderbird-filelink-dl/images/logo.svg b/client/thunderbird-filelink-dl/images/logo.svg new file mode 100644 index 0000000..22a5a8f --- /dev/null +++ b/client/thunderbird-filelink-dl/images/logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/client/thunderbird-filelink-dl/install.rdf b/client/thunderbird-filelink-dl/install.rdf deleted file mode 100644 index 57fe43c..0000000 --- a/client/thunderbird-filelink-dl/install.rdf +++ /dev/null @@ -1,37 +0,0 @@ - - - - - thunderbird-filelink-dl@thregr.org - DL FileLink Provider for Thunderbird - Convert large attachments to links automatically, directly within the Composer window, using your own “DL” server/service instead of relying on 3rd-party providers - https://www.thregr.org/~wavexx/software/dl/ - Yuri D'Elia - Yuri D'Elia (en-US) - Óvári (hu) - 0.17.3 - 2 - - - - - {3550f703-e582-4d05-9a08-453d09bdfdc6} - 13.0 - 52.* - - - - - - - hu - A „DL” fájlhivatkozás szolgáltató a Thunderbird számára (DL FileLink Provider for Thunderbird) - Átalakítja a nagy mellékleteket önműködően az üzenetszerkesztő ablakban lévő hivatkozásoké, saját „DL” kiszolgálóéval/szolgáltatásával, a harmadik féltől származó szolgáltatókra való hivatkozás helyett - Yuri D'Elia (en-US) - Óvári (hu) - - - - - diff --git a/client/thunderbird-filelink-dl/manifest.json b/client/thunderbird-filelink-dl/manifest.json new file mode 100644 index 0000000..df702ab --- /dev/null +++ b/client/thunderbird-filelink-dl/manifest.json @@ -0,0 +1,53 @@ +{ + "manifest_version": 2, + "name": "__MSG_extensionName__", + "description": "__MSG_extensionDescription__", + "version": "1.0.0", + "applications": { + "gecko": { + "id": "thunderbird-filelink-dl@thregr.org", + "strict_min_version": "68.1.1" + } + }, + "default_locale": "en", + + "icons": { + "24": "images/dl-icon.png" + }, + + "cloud_file": { + "name": "__MSG_serviceName__", + "management_url": "/content/management.html" + }, + + "compose_action": { + "default_title": "__MSG_insertUploadGrant__", + "default_icon": { + "24" : "/images/dl-icon.png" + } + }, + + "permissions": [ + "storage", + "", + "http://localhost:8080/*" + ], + + "background": { + "scripts": [ + "background/background.js" + ] + }, + "experiment_apis": { + "dl": { + "schema": "api/schema.json", + "parent": { + "scopes": ["addon_parent"], + "script": "api/api.js", + "paths": [ + ["dl"] + ] + } + } + } +}