├── _locales ├── ca │ └── messages.json ├── cs │ └── messages.json ├── de │ └── messages.json ├── el │ └── messages.json ├── en │ └── messages.json ├── es │ └── messages.json ├── fi │ └── messages.json ├── fr │ └── messages.json ├── id_ID │ └── messages.json ├── it │ └── messages.json ├── ja │ └── messages.json ├── nl │ └── messages.json ├── pl │ └── messages.json ├── pt │ └── messages.json ├── pt_BR │ └── messages.json ├── ru │ └── messages.json ├── sl │ └── messages.json ├── sr │ └── messages.json ├── sv │ └── messages.json ├── uk │ └── messages.json ├── vi │ └── messages.json ├── zh_CN │ └── messages.json └── zh_TW │ └── messages.json ├── build.bat ├── build.sh ├── change-log.txt ├── chrome ├── content │ ├── about.xhtml │ ├── api │ │ ├── LegacyPrefs │ │ │ ├── README.md │ │ │ ├── implementation.js │ │ │ └── schema.json │ │ ├── NotifyTools │ │ │ ├── README.md │ │ │ ├── implementation.js │ │ │ └── schema.json │ │ ├── Utilities │ │ │ ├── implementation.js │ │ │ └── schema.json │ │ └── WindowListener │ │ │ ├── README.md │ │ │ ├── changelog.md │ │ │ ├── implementation.js │ │ │ └── schema.json │ ├── help-html.js │ ├── help-xml.js │ ├── help.js │ ├── help.xhtml │ ├── i18n.js │ ├── register.xhtml │ ├── scripts │ │ ├── hackToolbarbutton.js │ │ ├── notifyTools.js │ │ ├── smartTemplate-defaults.js │ │ ├── st-am-adressing.js │ │ ├── st-composer.js │ │ ├── st-customizetoolbar.js │ │ ├── st-messagePane.js │ │ ├── st-messageWindow.js │ │ ├── st-messenger.js │ │ └── st-settings.js │ ├── skin │ │ ├── common │ │ │ ├── license.css │ │ │ ├── smartTemplate-about.css │ │ │ ├── smartTemplate-accounts.css │ │ │ ├── smartTemplate-actionButton.css │ │ │ ├── smartTemplate-overlay.css │ │ │ ├── smartTemplate-register.css │ │ │ ├── smartTemplate-toolButton.css │ │ │ └── style.css │ │ ├── compose-overlay.css │ │ ├── contribute.css │ │ ├── flags │ │ │ ├── cn.png │ │ │ ├── de.png │ │ │ ├── es.png │ │ │ ├── fi.png │ │ │ ├── fr.png │ │ │ ├── it.png │ │ │ ├── jp.png │ │ │ ├── nl.png │ │ │ ├── oc.png │ │ │ ├── pl.png │ │ │ ├── pt.png │ │ │ ├── ru.png │ │ │ ├── sv.png │ │ │ ├── tw.png │ │ │ ├── ua.png │ │ │ └── us.png │ │ ├── icon128x128.png │ │ ├── icon32x32.png │ │ ├── icon64x64.png │ │ ├── icons │ │ │ ├── accounts.svg │ │ │ ├── add.png │ │ │ ├── advanced.png │ │ │ ├── arrow-left.png │ │ │ ├── arrow-right.png │ │ │ ├── bug.svg │ │ │ ├── chat.svg │ │ │ ├── checkMark.png │ │ │ ├── configure.png │ │ │ ├── disabled.png │ │ │ ├── docs.svg │ │ │ ├── edit-size-down.png │ │ │ ├── edit-size-up.png │ │ │ ├── enabled.png │ │ │ ├── fg-user-support.png │ │ │ ├── file-load.png │ │ │ ├── find-next.svg │ │ │ ├── find-previous.svg │ │ │ ├── fugue-cross.png │ │ │ ├── fugue-disk.png │ │ │ ├── fugue-down-off.png │ │ │ ├── fugue-down.png │ │ │ ├── fugue-up-off.png │ │ │ ├── fugue-up.png │ │ │ ├── fugue-update.png │ │ │ ├── global.png │ │ │ ├── help-find-in-page.svg │ │ │ ├── help.svg │ │ │ ├── icon16x16.png │ │ │ ├── icon24x24.png │ │ │ ├── icons-licenses.txt │ │ │ ├── info-new.svg │ │ │ ├── info.png │ │ │ ├── info.svg │ │ │ ├── large │ │ │ │ ├── ST4-icon-128.png │ │ │ │ ├── ST4-icon.png │ │ │ │ ├── mail_forward.png │ │ │ │ ├── mail_new.png │ │ │ │ ├── mail_replay.png │ │ │ │ └── mail_reply.png │ │ │ ├── layout.png │ │ │ ├── left-svgrepo-com.svg │ │ │ ├── mail-fwd.png │ │ │ ├── mail-new.png │ │ │ ├── mail-reply.png │ │ │ ├── menu-arrow.png │ │ │ ├── new.svg │ │ │ ├── open.svg │ │ │ ├── pencil-field.png │ │ │ ├── pro-default.svg │ │ │ ├── pro-expired.svg │ │ │ ├── pro-paid.svg │ │ │ ├── save.svg │ │ │ ├── select-template.svg │ │ │ ├── settings-advanced.svg │ │ │ ├── settings-simple.svg │ │ │ ├── settings.png │ │ │ ├── settings.svg │ │ │ ├── snippets-icon.svg │ │ │ ├── snippets.svg │ │ │ ├── st4-cleandeferred-bright-focus.png │ │ │ ├── st4-cleandeferred-bright.png │ │ │ ├── st4-cleandeferred-focus.png │ │ │ ├── st4-cleandeferred.png │ │ │ ├── template-load.png │ │ │ ├── templates.svg │ │ │ ├── three-dots-svgrepo-com.svg │ │ │ ├── thunderbird │ │ │ │ ├── forward-bright.svg │ │ │ │ ├── forward.svg │ │ │ │ ├── new-mail.svg │ │ │ │ ├── new-msg-bright.svg │ │ │ │ ├── new-msg.svg │ │ │ │ ├── reply-all.svg │ │ │ │ ├── reply-bright.svg │ │ │ │ ├── reply-list.svg │ │ │ │ ├── reply.svg │ │ │ │ └── synchronize.svg │ │ │ ├── tooltip.svg │ │ │ ├── variable-keyword.png │ │ │ ├── variable.png │ │ │ ├── variable.svg │ │ │ ├── warning.svg │ │ │ ├── webex.png │ │ │ ├── youtube-svgrepo-com.svg │ │ │ └── youtube.png │ │ ├── licensing.png │ │ ├── logo-pro.png │ │ ├── logo.png │ │ ├── mac │ │ │ └── styleOS.css │ │ ├── proFeature.png │ │ ├── settings.css │ │ ├── smartTemplate-about.css │ │ ├── smartTemplate-accounts.css │ │ ├── smartTemplate-overlay-102.css │ │ ├── smartTemplate-overlay.css │ │ ├── st-toolbar-overlay.css │ │ ├── style.css │ │ ├── theming-frame.css │ │ ├── theming.css │ │ ├── unix │ │ │ └── styleOS.css │ │ ├── variables.css │ │ └── win │ │ │ └── styleOS.css │ ├── smartTemplate-compose.js │ ├── smartTemplate-composer.js │ ├── smartTemplate-fileTemplates.js │ ├── smartTemplate-help.js │ ├── smartTemplate-main.js │ ├── smartTemplate-overlay.js │ ├── smartTemplate-prefs.js │ ├── smartTemplate-register-dlg.js │ ├── smartTemplate-rsa.js │ ├── smartTemplate-signature.js │ ├── smartTemplate-styles.js │ ├── smartTemplate-unitTests.js │ ├── smartTemplate-util.js │ ├── smarttemplates_main_popup.html │ ├── smarttemplates_popup.js │ └── variables.html └── locale │ ├── ca │ └── calender.properties │ ├── cs │ └── calender.properties │ ├── de │ └── calender.properties │ ├── en │ └── calender.properties │ ├── es │ └── calender.properties │ ├── fi │ └── calender.properties │ ├── fr │ └── calender.properties │ ├── id-ID │ └── calender.properties │ ├── it │ └── calender.properties │ ├── ja │ └── calender.properties │ ├── nl │ └── calender.properties │ ├── oc │ └── calender.properties │ ├── pl │ └── calender.properties │ ├── pt-BR │ └── calender.properties │ ├── ru │ └── calender.properties │ ├── sl │ └── calender.properties │ ├── sr │ └── calender.properties │ ├── sv │ └── calender.properties │ ├── uk │ └── calender.properties │ ├── zh-CN │ └── calender.properties │ └── zh-TW │ └── calender.properties ├── crowdin.yml ├── html ├── html-compatibility.css ├── smartTemplate-message.html ├── smartTemplate-settings.html ├── smartTemplate-settings.js ├── smarttemplate-settings.css ├── st-common-shared.css ├── st-common.css ├── st-help.js ├── st-layout.css ├── st-log.mjs ├── st-message.css ├── st-message.js ├── st-settings-layout.css ├── st-settings-main.js ├── st-settings-ui.mjs └── st-settings-util.js ├── icon.png ├── license.txt ├── manifest.json ├── popup ├── animation.js ├── bargain25new.png ├── bargain33.png ├── bargainUpgrade33.png ├── coins-animation-dlr.png ├── installed.css ├── installed.html ├── installed.js ├── popup.css ├── popup.js ├── sales.js ├── update.html └── update.js ├── release-notes.html ├── release-notes.md ├── revision.txt ├── scripts ├── Licenser.mjs.js ├── ical.js ├── mozilla-version-comparator.js ├── rsa │ ├── Barrett.mjs.js │ ├── BigIntModule.mjs.js │ └── RSA.mjs.js ├── st-compose.mjs.js ├── st-composer.mjs.js ├── st-crypto.mjs.js ├── st-main.mjs.js ├── st-parser.mjs.js ├── st-prefs.mjs.js ├── st-process.mjs.js ├── st-signature.mjs.js ├── st-styles.mjs.js └── st-util.mjs.js ├── st-background.html └── st-background.js /build.bat: -------------------------------------------------------------------------------- 1 | set /P smartTemplateRev= revision.txt 7 | move smartTemplate-*.xpi "..\..\..\Test Versions\4.12\" 8 | powershell -Command "Start-Sleep -m 1000" 9 | rename smartTemplateWeb.zip smartTemplate-fx-4.12pre%smartTemplateRev%.xpi -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | smartTemplateRev=$( cat revision.txt | xargs ) 4 | oldRev=$smartTemplateRev 5 | smartTemplateRev=$((smartTemplateRev+1)) 6 | 7 | sed -i "s/pre$oldRev/pre$smartTemplateRev/g" manifest.json 8 | 9 | 7z a -xr!.svn smartTemplateWeb.zip manifest.json _locales chrome locale popup st-background.js license.txt icon.png release-notes.html 10 | 11 | echo $smartTemplateRev > revision.txt 12 | mv smartTemplate-*.xpi "../../../Test Versions/3.5/" 13 | mv smartTemplateWeb.zip smartTemplate-fx-3.5pre$smartTemplateRev.xpi 14 | -------------------------------------------------------------------------------- /chrome/content/api/LegacyPrefs/README.md: -------------------------------------------------------------------------------- 1 | ## Objective 2 | 3 | Use this API to access Thunderbird's system preferences or to migrate your own preferences from the Thunderbird preference system to the local storage of your MailExtension. 4 | 5 | ## Usage 6 | 7 | Add the [LegacyPrefs API](https://github.com/thunderbird/addon-developer-support/tree/master/auxiliary-apis/LegacyPrefs) to your add-on. Your `manifest.json` needs an entry like this: 8 | 9 | ``` 10 | "experiment_apis": { 11 | "LegacyPrefs": { 12 | "schema": "api/LegacyPrefs/schema.json", 13 | "parent": { 14 | "scopes": ["addon_parent"], 15 | "paths": [["LegacyPrefs"]], 16 | "script": "api/LegacyPrefs/implementation.js" 17 | } 18 | } 19 | }, 20 | ``` 21 | 22 | ## API Functions 23 | 24 | This API provides the following functions: 25 | 26 | ### async getPref(aName, [aFallback]) 27 | 28 | Returns the value for the ``aName`` preference. If it is not defined or has no default value assigned, ``aFallback`` will be returned (which defaults to ``null``). 29 | 30 | ### async getUserPref(aName) 31 | 32 | Returns the user defined value for the ``aName`` preference. This will ignore any defined default value and will only return an explicitly set value, which differs from the default. Otherwise it will return ``null``. 33 | 34 | ### clearUserPref(aName) 35 | 36 | Clears the user defined value for preference ``aName``. Subsequent calls to ``getUserPref(aName)`` will return ``null``. 37 | 38 | ### async setPref(aName, aValue) 39 | 40 | Set the ``aName`` preference to the given value. Will return false and log an error to the console, if the type of ``aValue`` does not match the type of the preference. 41 | 42 | ## API Events 43 | 44 | This API provides the following events: 45 | 46 | ### onChanged.addListener(listener, branch) 47 | 48 | Register a listener which is notified each time a value in the specified branch is changed. The listener returns the name and the new value of the changed preference. 49 | 50 | Example: 51 | 52 | ``` 53 | browser.LegacyPrefs.onChanged.addListener(async (name, value) => { 54 | console.log(`Changed value in "mailnews.": ${name} = ${value}`); 55 | }, "mailnews."); 56 | ``` 57 | 58 | --- 59 | 60 | A detailed example using the LegacyPref API to migrate add-on preferences to the local storage can be found in [/scripts/preferences/](https://github.com/thunderbird/addon-developer-support/tree/master/scripts/preferences). 61 | -------------------------------------------------------------------------------- /chrome/content/api/NotifyTools/schema.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "namespace": "NotifyTools", 4 | "events": [ 5 | { 6 | "name": "onNotifyBackground", 7 | "type": "function", 8 | "description": "Fired when a new notification from notifyTools.js in an Experiment has been received.", 9 | "parameters": [ 10 | { 11 | "name": "data", 12 | "type": "any", 13 | "description": "Restrictions of the structured clone algorithm apply." 14 | } 15 | ] 16 | } 17 | ], 18 | "functions": [ 19 | { 20 | "name": "notifyExperiment", 21 | "type": "function", 22 | "async": true, 23 | "description": "Notifies notifyTools.js in an Experiment and sends data.", 24 | "parameters": [ 25 | { 26 | "name": "data", 27 | "type": "any", 28 | "description": "Restrictions of the structured clone algorithm apply." 29 | } 30 | ] 31 | } 32 | ] 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /chrome/content/api/WindowListener/README.md: -------------------------------------------------------------------------------- 1 | Usage description can be found in the [wiki](https://github.com/thundernest/addon-developer-support/wiki/Using-the-WindowListener-API-to-convert-a-Legacy-Overlay-WebExtension-into-a-MailExtension-for-Thunderbird-78). 2 | -------------------------------------------------------------------------------- /chrome/content/api/WindowListener/schema.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "namespace": "WindowListener", 4 | "functions": [ 5 | { 6 | "name": "registerDefaultPrefs", 7 | "type": "function", 8 | "parameters": [ 9 | { 10 | "name": "aPath", 11 | "type": "string", 12 | "description": "Relative path to the default file." 13 | } 14 | ] 15 | }, 16 | { 17 | "name": "registerOptionsPage", 18 | "type": "function", 19 | "parameters": [ 20 | { 21 | "name": "aPath", 22 | "type": "string", 23 | "description": "Path to the options page, which should be made accessible in the (legacy) Add-On Options menu." 24 | } 25 | ] 26 | }, 27 | { 28 | "name": "registerChromeUrl", 29 | "type": "function", 30 | "description": "Register folders which should be available as chrome:// urls (as defined in the legacy chrome.manifest)", 31 | "parameters": [ 32 | { 33 | "name": "data", 34 | "type": "array", 35 | "items": { 36 | "type": "array", 37 | "items": { 38 | "type": "string" 39 | } 40 | }, 41 | "description": "Array of manifest url definitions (content, locale, resource)" 42 | } 43 | ] 44 | }, 45 | { 46 | "name": "waitForMasterPassword", 47 | "type": "function", 48 | "async": true, 49 | "parameters": [] 50 | }, 51 | { 52 | "name": "openOptionsDialog", 53 | "type": "function", 54 | "parameters": [ 55 | { 56 | "name": "windowId", 57 | "type": "integer", 58 | "description": "Id of the window the dialog should be opened from." 59 | } 60 | ] 61 | }, 62 | { 63 | "name": "startListening", 64 | "type": "function", 65 | "async": true, 66 | "parameters": [] 67 | }, 68 | { 69 | "name": "registerWindow", 70 | "type": "function", 71 | "parameters": [ 72 | { 73 | "name": "windowHref", 74 | "type": "string", 75 | "description": "Url of the window, which should be listen for." 76 | }, 77 | { 78 | "name": "jsFile", 79 | "type": "string", 80 | "description": "Path to the JavaScript file, which should be loaded into the window." 81 | } 82 | ] 83 | }, 84 | { 85 | "name": "registerStartupScript", 86 | "type": "function", 87 | "parameters": [ 88 | { 89 | "name": "aPath", 90 | "type": "string", 91 | "description": "Path to a JavaScript file, which should be executed on add-on startup. The script will be executed after the main application window has been sucessfully loaded." 92 | } 93 | ] 94 | }, 95 | { 96 | "name": "registerShutdownScript", 97 | "type": "function", 98 | "parameters": [ 99 | { 100 | "name": "aPath", 101 | "type": "string", 102 | "description": "Path to a JavaScript file, which should be executed on add-on shutdown." 103 | } 104 | ] 105 | } 106 | ] 107 | } 108 | ] -------------------------------------------------------------------------------- /chrome/content/help-xml.js: -------------------------------------------------------------------------------- 1 | /* load help.js first */ 2 | 3 | function initXHTML() { 4 | // avoid running xul code: 5 | if (findOrigin() == "html") { 6 | // EARLY EXIT, let's run help-html.js instead 7 | console.log("help.js early exit..."); 8 | return; 9 | } 10 | isDebugLegacyOption = function () { 11 | const isDebug = true; 12 | return isDebug; 13 | } 14 | // [mx l10n] 15 | 16 | var { ExtensionParent } = ChromeUtils.importESModule("resource://gre/modules/ExtensionParent.sys.mjs"); 17 | 18 | let extension = ExtensionParent.GlobalManager.getExtension("smarttemplate4@thunderbird.extension"); 19 | Services.scriptloader.loadSubScript( 20 | extension.rootURI.resolve("chrome/content/i18n.js"), 21 | window, 22 | "UTF-8" 23 | ); 24 | window.i18n.updateDocument({extension}); 25 | 26 | var myheadings = Array.from(document.getElementsByClassName("helpchapter")); 27 | myheadings.forEach((el) => { 28 | // for purpose of search / focus() 29 | el.setAttribute("tabindex", -1); 30 | }); 31 | 32 | fixClipboardNote(); 33 | initSearch(); 34 | } 35 | 36 | window.document.addEventListener('DOMContentLoaded', 37 | initXHTML, 38 | { once: true }); 39 | 40 | -------------------------------------------------------------------------------- /chrome/content/i18n.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is provided by the addon-developer-support repository at 3 | * https://github.com/thundernest/addon-developer-support 4 | * 5 | * For usage descriptions, please check: 6 | * https://github.com/thundernest/addon-developer-support/tree/master/scripts/i18n 7 | * 8 | * Version: 1.1 9 | * 10 | * Derived from: 11 | * http://github.com/piroor/webextensions-lib-l10n 12 | * 13 | * Original license: 14 | * The MIT License, Copyright (c) 2016-2019 YUKI "Piro" Hiroshi 15 | * 16 | */ 17 | 18 | var i18n = { 19 | updateString(string) { 20 | let re = new RegExp(this.keyPrefix + "(.+?)__", "g"); 21 | return string.replace(re, (matched) => { 22 | const key = matched.slice(this.keyPrefix.length, -2); 23 | let rv = this.extension 24 | ? this.extension.localeData.localizeMessage(key) 25 | : messenger.i18n.getMessage(key); 26 | return rv || matched; 27 | }); 28 | }, 29 | 30 | updateSubtree(node) { 31 | const texts = document.evaluate( 32 | 'descendant::text()[contains(self::text(), "' + this.keyPrefix + '")]', 33 | node, 34 | null, 35 | XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, 36 | null 37 | ); 38 | for (let i = 0, maxi = texts.snapshotLength; i < maxi; i++) { 39 | const text = texts.snapshotItem(i); 40 | if (text.nodeValue.includes(this.keyPrefix)) 41 | text.nodeValue = this.updateString(text.nodeValue); 42 | } 43 | 44 | const attributes = document.evaluate( 45 | 'descendant::*/attribute::*[contains(., "' + this.keyPrefix + '")]', 46 | node, 47 | null, 48 | XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, 49 | null 50 | ); 51 | for (let i = 0, maxi = attributes.snapshotLength; i < maxi; i++) { 52 | const attribute = attributes.snapshotItem(i); 53 | if (attribute.value.includes(this.keyPrefix)) 54 | attribute.value = this.updateString(attribute.value); 55 | } 56 | }, 57 | 58 | updateDocument(options = {}) { 59 | this.extension = null; 60 | this.keyPrefix = "__MSG_"; 61 | if (options) { 62 | if (options.extension) this.extension = options.extension; 63 | if (options.keyPrefix) this.keyPrefix = options.keyPrefix; 64 | } 65 | this.updateSubtree(document); 66 | }, 67 | }; 68 | -------------------------------------------------------------------------------- /chrome/content/scripts/notifyTools.js: -------------------------------------------------------------------------------- 1 | // Set this to the ID of your add-on. 2 | var ADDON_ID = "smarttemplate4@thunderbird.extension"; 3 | 4 | /* 5 | * This file is provided by the addon-developer-support repository at 6 | * https://github.com/thundernest/addon-developer-support 7 | * 8 | * For usage descriptions, please check: 9 | * https://github.com/thundernest/addon-developer-support/tree/master/scripts/notifyTools 10 | * 11 | * Version: 1.3 12 | * - registered listeners for notifyExperiment can return a value 13 | * - remove WindowListener from name of observer 14 | * 15 | * Author: John Bieling (john@thunderbird.net) 16 | * 17 | * This Source Code Form is subject to the terms of the Mozilla Public 18 | * License, v. 2.0. If a copy of the MPL was not distributed with this 19 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. 20 | */ 21 | 22 | 23 | 24 | var notifyTools = { 25 | registeredCallbacks: {}, 26 | registeredCallbacksNextId: 1, 27 | 28 | onNotifyExperimentObserver: { 29 | observe: async function (aSubject, aTopic, aData) { 30 | if (ADDON_ID == "") { 31 | throw new Error("notifyTools: ADDON_ID is empty!"); 32 | } 33 | if (aData != ADDON_ID) { 34 | return; 35 | } 36 | let payload = aSubject.wrappedJSObject; 37 | if (payload.resolve) { 38 | let observerTrackerPromises = []; 39 | // Push listener into promise array, so they can run in parallel 40 | for (let registeredCallback of Object.values( 41 | notifyTools.registeredCallbacks 42 | )) { 43 | observerTrackerPromises.push(registeredCallback(payload.data)); 44 | } 45 | // We still have to await all of them but wait time is just the time needed 46 | // for the slowest one. 47 | let results = []; 48 | for (let observerTrackerPromise of observerTrackerPromises) { 49 | let rv = await observerTrackerPromise; 50 | if (rv != null) results.push(rv); 51 | } 52 | if (results.length == 0) { 53 | payload.resolve(); 54 | } else { 55 | if (results.length > 1) { 56 | console.warn( 57 | "Received multiple results from onNotifyExperiment listeners. Using the first one, which can lead to inconsistent behavior.", 58 | results 59 | ); 60 | } 61 | payload.resolve(results[0]); 62 | } 63 | } else { 64 | // Just call the listener. 65 | for (let registeredCallback of Object.values( 66 | notifyTools.registeredCallbacks 67 | )) { 68 | registeredCallback(payload.data); 69 | } 70 | } 71 | }, 72 | }, 73 | 74 | registerListener: function (listener) { 75 | let id = this.registeredCallbacksNextId++; 76 | this.registeredCallbacks[id] = listener; 77 | return id; 78 | }, 79 | 80 | removeListener: function (id) { 81 | delete this.registeredCallbacks[id]; 82 | }, 83 | 84 | notifyBackground: function (data) { 85 | if (ADDON_ID == "") { 86 | throw new Error("notifyTools: ADDON_ID is empty!"); 87 | } 88 | return new Promise((resolve) => { 89 | Services.obs.notifyObservers( 90 | { data, resolve }, 91 | "NotifyBackgroundObserver", 92 | ADDON_ID 93 | ); 94 | }); 95 | }, 96 | 97 | enable: function() { 98 | Services.obs.addObserver( 99 | this.onNotifyExperimentObserver, 100 | "NotifyExperimentObserver", 101 | false 102 | ); 103 | }, 104 | 105 | disable: function() { 106 | Services.obs.removeObserver( 107 | this.onNotifyExperimentObserver, 108 | "NotifyExperimentObserver" 109 | ); 110 | }, 111 | }; 112 | 113 | 114 | if (window) { 115 | window.addEventListener( 116 | "load", 117 | function (event) { 118 | notifyTools.enable(); 119 | window.addEventListener( 120 | "unload", 121 | function (event) { 122 | notifyTools.disable(); 123 | }, 124 | false 125 | ); 126 | }, 127 | false 128 | ); 129 | } 130 | -------------------------------------------------------------------------------- /chrome/content/scripts/st-am-adressing.js: -------------------------------------------------------------------------------- 1 | // Likely Obsolete for THunderbird 78 2 | // Web Extensions will probably not be allowed to modify Thunderbird Options. :( 3 | 4 | Services.scriptloader.loadSubScript("chrome://smarttemplate4/content/smartTemplate-main.js", window, "UTF-8"); 5 | 6 | function onLoad(activatedWhileWindowOpen) { 7 | let layout = WL.injectCSS("chrome://smarttemplate4/content/skin/smartTemplate-accounts.css"); 8 | 9 | WL.injectElements(` 10 | 11 | 12 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /html/st-common-shared.css: -------------------------------------------------------------------------------- 1 | /* Sidebar footer links */ 2 | 3 | .sidebar-footer-list { 4 | list-style-type: none; 5 | margin-block: 0; 6 | margin-inline: 10px; 7 | padding: 0; 8 | } 9 | 10 | .sidebar-footer-link { 11 | height: 36px; 12 | cursor: default; 13 | border: 1px solid var(--in-content-button-border-color); 14 | border-radius: 4px; 15 | display: flex; 16 | align-items: center; 17 | } 18 | 19 | 20 | @media (forced-colors) { 21 | .sidebar-footer-link { 22 | /* We need a true transparent but in HCM this would compute to an actual color, 23 | * so select the page's background color instead: */ 24 | border-color: var(--in-content-page-background); 25 | } 26 | } 27 | 28 | .sidebar-footer-link, 29 | .sidebar-footer-link:visited { 30 | /* Override link style for :hover and :hover:active states */ 31 | text-decoration: none !important; 32 | color: inherit; 33 | } 34 | 35 | *.sidebar-footer-link { 36 | display: flex; 37 | align-items: center; 38 | } 39 | 40 | .sidebar-footer-link:hover { 41 | background-color: var(--in-content-button-background-hover); 42 | color: var(--in-content-button-text-color-hover); 43 | border-color: var(--in-content-button-border-color-hover); 44 | } 45 | 46 | .sidebar-footer-link:hover:active:not([disabled]) { 47 | background-color: var(--in-content-button-background-active); 48 | color: var(--in-content-button-text-color-active); 49 | border-color: var(--in-content-button-border-color-active); 50 | } 51 | 52 | .sidebar-footer-link:focus-visible { 53 | outline: var(--in-content-focus-outline); 54 | outline-offset: var(--in-content-focus-outline-inset); 55 | } 56 | 57 | .sidebar-footer-icon { 58 | -moz-context-properties: fill, fill-opacity; 59 | fill: currentColor; 60 | width: 16px; 61 | height: 16px; 62 | margin: 10px; 63 | margin-inline-start: 13px; 64 | } 65 | 66 | .sidebar-footer-label { 67 | font-size: .9em; 68 | margin: 0 4px; 69 | user-select: none; 70 | } 71 | 72 | @media (max-width: 830px) { 73 | .sidebar-footer-link { 74 | width: 36px; 75 | height: 36px; 76 | padding-inline-start: 0; 77 | margin-inline-start: 1px; 78 | } 79 | 80 | .sidebar-footer-icon { 81 | margin-inline-start: 10px; 82 | } 83 | 84 | #sidebar-footer-list .category { 85 | background-position: center; 86 | } 87 | 88 | .sidebar-footer-label { 89 | display: none; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /html/st-common.css: -------------------------------------------------------------------------------- 1 | /*** common.css ***/ 2 | 3 | /** this uses rules from common-shared and layout! **/ 4 | :root { 5 | 6 | --in-content-button-border-color: color-mix(in srgb, currentColor 9%, transparent); 7 | --in-content-button-border-color-hover: color-mix(in srgb, currentColor 17%, transparent); 8 | --in-content-sidebar-width: auto; 9 | --menu-item-margin: 0 3px; 10 | 11 | @media not (prefers-contrast) { 12 | --in-content-box-info-background: light-dark(var(--layout-background-1), var(--layout-background-2)); 13 | --in-content-box-info-border: light-dark(var(--layout-border-0), transparent); 14 | --in-content-button-background: light-dark(var(--grey-90-a10), rgba(249, 249, 250, 0.1)); 15 | --in-content-button-background-hover: light-dark(var(--grey-90-a20), rgba(249, 249, 250, 0.15)); 16 | --in-content-button-background-active: light-dark(var(--grey-90-a30), rgba(249, 249, 250, 0.2)); 17 | --in-content-categories-background: var(--layout-background-2); 18 | --in-content-categories-border: var(--in-content-categories-background); 19 | --in-content-item-selected-unfocused: light-dark(var(--color-gray-20), rgba(249, 249, 250, 0.05)); 20 | --in-content-item-hover: color-mix(in srgb, currentColor 12%, transparent); 21 | --in-content-item-selected: color-mix(in srgb, currentColor 20%, transparent); 22 | --in-content-item-selected-text: var(--in-content-page-color); 23 | --in-content-primary-button-background: AccentColor; 24 | --in-content-primary-button-background-hover: color-mix(in srgb, AccentColor 80%, black); 25 | --in-content-primary-button-background-active: color-mix(in srgb, AccentColor 70%, black); 26 | --in-content-primary-button-text-color: AccentColorText; 27 | --in-content-focus-outline-color: AccentColor; 28 | --focus-outline-color: AccentColor; 29 | } 30 | 31 | @media (prefers-contrast) { 32 | --in-content-box-info-background: transparent; 33 | --in-content-box-info-border: currentColor; 34 | --in-content-categories-background: transparent; 35 | --in-content-categories-border: currentColor; 36 | --in-content-primary-button-background: SelectedItem; 37 | --in-content-primary-button-background-hover: SelectedItem; 38 | --in-content-primary-button-background-active: SelectedItem; 39 | --in-content-primary-button-text-color: SelectedItemText; 40 | --in-content-primary-button-text-color-active: SelectedItemText; 41 | } 42 | 43 | --version-background: linear-gradient(to bottom, #0380bf 0%,#006eb7 100%) !important; 44 | } 45 | 46 | #categories, #sidebarcategories { 47 | & > .category { 48 | margin-inline: 6px; 49 | border-color: transparent !important; 50 | 51 | &[selected] { 52 | font-weight: 500; 53 | } 54 | } 55 | 56 | @media not (prefers-contrast) { 57 | & > .category[selected] { 58 | background-color: var(--in-content-button-background) !important; 59 | color: unset; 60 | } 61 | 62 | &[keyboard-navigation="true"]:focus-visible > .category[current], 63 | & > .category:focus-visible { 64 | background-color: var(--in-content-item-selected) !important; 65 | color: var(--in-content-item-selected-text); 66 | outline: none; 67 | } 68 | } 69 | } 70 | 71 | .showSplash, .showSplash:focus { 72 | color: white !important; 73 | background-color: #006EB7 !important; /* blue */ 74 | background-image: var(--version-background) !important; 75 | } 76 | .showSplash label, .showSplash:focus label { 77 | color: white; 78 | } 79 | 80 | .showSplash:hover, .showSplash:focus:hover { 81 | color: black !important; 82 | background-color: #ffd65e !important; /* yellow */ 83 | background-image: linear-gradient(to bottom, #fff65e 0%,#febf04 100%) !important; 84 | } 85 | 86 | .showSplash:hover *, .showSplash:focus:hover * { 87 | color: rgb(60,0,0) !important; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /html/st-help.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | BEGIN LICENSE BLOCK 4 | 5 | SmartTemplates is released under the Creative Commons (CC BY-ND 4.0) 6 | Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0) 7 | For details, please refer to license.txt in the root folder of this extension 8 | 9 | END LICENSE BLOCK 10 | */ 11 | 12 | SmartTemplates.Help = { 13 | onBodyClick : function onClick (element, evt) { 14 | SmartTemplates.Util.logDebug("Help.onBodyClick (" + element.tagName + ") "); 15 | }, 16 | onLoad: async function () { 17 | // custom event listener for clicking code words 18 | browser.runtime.onMessage.addListener( 19 | (message, sender) => { 20 | switch (message.msg) { 21 | case "SmartTemplate4CodeWord": 22 | console.log(`st-help: Received ${message.msg} from:`, { sender }); 23 | navigator.clipboard.write(message.code); // copy element to clipboard! 24 | return true; 25 | case "SmartTemplate4CAD": // default address book settings 26 | // open advanced page 27 | SmartTemplates.Settings.selectCategoryMenu("catSettingsAdvanced"); 28 | // highlight & focus settings input 29 | const txtDefaultFormat = document.getElementById("default_address_format"); 30 | txtDefaultFormat.classList.add("highlighted"); 31 | txtDefaultFormat.focus(); 32 | console.log(`st-help: Received ${message.msg} for ${message.code} from:`, { sender }); 33 | return true; 34 | case "SmartTemplate4Website": 35 | console.log(`st-help: Received ${message.msg} from:`, { sender }); 36 | const href = message.href; 37 | if (href) { 38 | SmartTemplates.Util.openLinkInTab(href); 39 | } 40 | return true; 41 | } 42 | return false; 43 | } 44 | ) 45 | 46 | const variablesDocument = document.getElementById("helpFrame")?.contentDocument; 47 | const preheaderDesc = variablesDocument?.getElementById("preHeaderText"); 48 | if (preheaderDesc) { 49 | preheaderDesc.innerHTML = SmartTemplates.Util.getBundleString("preheader.text", [ 50 | "clipboard", 51 | "*selection*", 52 | "*clipboard*", 53 | ]); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /html/st-layout.css: -------------------------------------------------------------------------------- 1 | /**** layout.css ****/ 2 | :host, 3 | :root { 4 | --layout-background-0: var(--color-white); 5 | --layout-background-1: var(--color-gray-05); 6 | --layout-background-2: var(--color-gray-10); 7 | --layout-background-3: var(--color-gray-20); 8 | --layout-background-4: var(--color-gray-30); 9 | 10 | --layout-color-0: var(--color-black); 11 | --layout-color-1: var(--color-gray-90); 12 | --layout-color-2: var(--color-gray-70); 13 | --layout-color-3: var(--color-gray-50); 14 | 15 | --layout-border-0: var(--color-gray-30); 16 | --layout-border-1: var(--color-gray-40); 17 | --layout-border-2: var(--color-gray-50); 18 | } 19 | 20 | @media (prefers-color-scheme: dark) { 21 | :host, 22 | :root { 23 | --layout-background-0: var(--color-gray-90); 24 | --layout-background-1: var(--color-gray-80); 25 | --layout-background-2: var(--color-gray-70); 26 | --layout-background-3: var(--color-gray-60); 27 | --layout-background-4: var(--color-gray-50); 28 | 29 | --layout-color-0: var(--color-white); 30 | --layout-color-1: var(--color-gray-10); 31 | --layout-color-2: var(--color-gray-30); 32 | --layout-color-3: var(--color-gray-50); 33 | 34 | --layout-border-0: var(--color-gray-70); 35 | --layout-border-1: var(--color-gray-60); 36 | --layout-border-2: var(--color-gray-50); 37 | } 38 | } 39 | 40 | @media (prefers-contrast) { 41 | :host, 42 | :root:not([lwtheme]) { 43 | --layout-background-0: Window; 44 | --layout-background-1: -moz-Dialog; 45 | --layout-background-2: transparent; 46 | --layout-background-3: transparent; 47 | --layout-background-4: transparent; 48 | 49 | --layout-color-0: WindowText; 50 | --layout-color-1: -moz-DialogText; 51 | --layout-color-2: currentColor; 52 | --layout-color-3: currentColor; 53 | 54 | --layout-border-0: currentColor; 55 | --layout-border-1: currentColor; 56 | --layout-border-2: currentColor; 57 | } 58 | } -------------------------------------------------------------------------------- /html/st-log.mjs: -------------------------------------------------------------------------------- 1 | export function logMissingFunction(txt) { 2 | // Log missing items for Conversion to Thunderbird 115 3 | console.log(`SmartTemplates %c[issue 259] to do: %c ${txt} `, 4 | "color:darkred", 5 | "background: darkred; color:yellow;"); 6 | } 7 | -------------------------------------------------------------------------------- /html/st-message.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --canvas: rgb(245,245,245); 3 | --canvastext: rgb(15,15,15); 4 | --commandbar: rgba(10,10,10,0.1) 5 | --actionbtn-backcolor: darkred; 6 | --actionbtn-color: white; 7 | color-scheme: light dark; 8 | } 9 | @media (prefers-color-scheme: dark) { 10 | :root { 11 | --canvas: rgb(15,15,15); 12 | --canvastext:rgb(245,245,245); 13 | --commandbar: rgba(250,250,250,0.1) 14 | } 15 | } 16 | 17 | body { 18 | background-color: var(--canvas); 19 | color: var(--canvastext); 20 | } 21 | 22 | /** STYLES FOR THE MODELESS message window smarteTemplate-msg.xul ****/ 23 | #titleBox { 24 | background-image: url("../chrome/content/skin/logo.png") !important; 25 | background-position: center; 26 | background-repeat: no-repeat; 27 | height: 55px; 28 | color: transparent; /* test: rgba(80, 5, 5, 0.1); */ 29 | font-size: large; 30 | } 31 | 32 | #messageCanvas { 33 | background-position: top right; 34 | background-repeat: no-repeat; 35 | background-image: url("../chrome/content/skin/icons/large/ST4-icon-128.png"); 36 | background-size: 128px 128px; 37 | border: 1px solid rgba(64, 2, 2, 0.1); /* test */ 38 | border-radius: 0.3rem; 39 | box-sizing: border-box; 40 | min-width: 200px; 41 | min-height: 200px; 42 | width: 100%; 43 | } 44 | 45 | .bottomhint { 46 | text-align: center; 47 | } 48 | 49 | 50 | #commands { 51 | display: flex; 52 | justify-content: center; /* aligns buttons left, change as needed */ 53 | gap: 2em; /* spacing between buttons */ 54 | padding: 1em 0; 55 | } 56 | 57 | #commands button { 58 | box-shadow: 3px 3px 2px rgba(50,0,0,0.1); 59 | background-color: var(--actionbtn-backcolor,darkred); 60 | color: var(--actionbtn-color,white); 61 | border: none; 62 | padding: 8px 16px; 63 | font-size: 12pt; 64 | cursor: pointer; 65 | border-radius: 4px; 66 | } 67 | 68 | #commands button:hover { 69 | background-image: linear-gradient(to bottom, #6d0019 0%, #8f0222 34%, #e20425 100%); 70 | } 71 | 72 | #commands button:active { 73 | background-image: linear-gradient(to bottom, #633b00 0%, #750202 34%, #ef8204 100%); 74 | } 75 | 76 | /* remove default buttons, we add our own */ 77 | .dialog-button-box { 78 | display: none; 79 | } 80 | 81 | #ok, #cancel, #yes, #no, #countDown { 82 | font-size: 12pt; 83 | } 84 | 85 | 86 | #innerMessage { 87 | font-size: 12pt; 88 | min-width: 300px; 89 | height: auto; 90 | margin: 0 3em 1.5em; 91 | width: 80%; 92 | flex-direction: column; 93 | } 94 | 95 | #innerMessage p, #innerMessage br { 96 | display: block; 97 | line-height: 1.2em; 98 | } 99 | #innerMessage p { 100 | /*! text-align: justify; */ 101 | /* color: rgb(2,2,2) !important; */ /* leave text color to theme! */ 102 | margin-bottom: 0.6em; 103 | max-width: 850px; 104 | } 105 | 106 | #innerMessage #code { 107 | background-color: #FFFFFF; 108 | box-shadow: inset 0 0 5px rgba(0,0,0,0.5); 109 | color: rgb(40,40,40); 110 | font-size: 10pt; 111 | font-family: Consolas,monaco,monospace !important; 112 | min-height: 50px; 113 | max-height: 250px !important; 114 | overflow-y: scroll; 115 | } 116 | 117 | #innerMessage #code p { 118 | margin-top: 2px; 119 | margin-bottom: 2px; 120 | } 121 | 122 | #messageCanvas { 123 | height: 100%; 124 | display: flex; 125 | flex-direction: column; 126 | overflow: hidden; 127 | } 128 | 129 | .messageContents { 130 | flex-grow: 1; 131 | overflow-y: auto; 132 | } 133 | 134 | html, body { 135 | height: 100%; 136 | margin: 0; 137 | padding: 0; 138 | } 139 | 140 | #commands { 141 | position: sticky; 142 | bottom: 0; 143 | background: var(--commandbar,rgba(250,250,250,0.1)); 144 | padding: 0.5rem; 145 | border-top: 1px solid #ccc; 146 | z-index: 10; 147 | } 148 | 149 | 150 | /* use this for pringin html code */ 151 | pre { 152 | font-size: 0.85rem; 153 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 154 | white-space: pre-wrap; 155 | max-width: 100%; 156 | overflow-wrap: break-word; 157 | } 158 | -------------------------------------------------------------------------------- /html/st-settings-main.js: -------------------------------------------------------------------------------- 1 | var SmartTemplates = {}; 2 | -------------------------------------------------------------------------------- /html/st-settings-ui.mjs: -------------------------------------------------------------------------------- 1 | export let SettingsUI = { 2 | // doing what instantApply really should provide... 3 | toggleBoolPreference: async function(cb, noUpdate = false) { 4 | const SMARTTEMPLATES_EXTPREFIX = "extensions.smartTemplate4."; 5 | 6 | let prefString = cb.getAttribute("data-pref-name"); 7 | // using the new preference system, this attribute should be the actual full string of the pref. 8 | // pref = document.getElementById(prefString); 9 | 10 | if (prefString) { 11 | await messenger.LegacyPrefs.setPref(prefString, cb.checked); 12 | } 13 | 14 | if (noUpdate) return true; 15 | 16 | // UI messages create message for main window - to pass on to background: 17 | switch (prefString) { 18 | case SMARTTEMPLATES_EXTPREFIX + "collapseCategories": 19 | // //// ST.Util.notifyTools.notifyBackground({ func: "updateCategoryBox" }); 20 | // messenger.runtime.sendMessage({ command:"updateCategoryBox" }); 21 | return false; 22 | } 23 | // messenger.runtime.sendMessage({ command:"updateMainWindow" }); 24 | return true; 25 | }, 26 | 27 | initVersionPanel: async function () { 28 | const manifest = await messenger.runtime.getManifest(); 29 | document.getElementById("versionBox").textContent = manifest.version; 30 | }, 31 | 32 | } -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealRaven2000/SmartTemplates/328f7228734e66089a0ada97799afaa405674320/icon.png -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | LICENSE 2 | 3 | SmartTemplates is released under the Creative Commons (CC BY-ND 4.0) 4 | Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0) 5 | 6 | Terms: 7 | The Program - the SmartTemplates Add-on (distributed as a XPI file) and all files contained within it 8 | Premium Feature - a feature or function of the software which is protected by the mechanism outlined below 9 | SmartTemplates Pro - Refers to the registered version of SmartTemplates 10 | 11 | 12 | All contents of The Program are subject to the Creative Commons License (CC BY-ND 4.0) 13 | (the "License"); you may not use the file except in compliance with 14 | the License. You may obtain a copy of the complete License at 15 | http://creativecommons.org/licenses/by-nd/4.0/legalcode 16 | For a human-readable summary thereof please refer 17 | http://creativecommons.org/licenses/by-nd/4.0/ 18 | 19 | 20 | 21 | Pro Version 22 | This Program contains a subset of features "Premium Features" which are protected by 23 | a paid registration scheme. Registration keys can be obtained via various licensing links 24 | from within the software (Settings > Advanced > SmartTemplates Pro tab, SmartTemplates context menu, 25 | premium notification messages). The profits from Registration are used to develop 26 | and distribute the program further and to feed the author, as he would like to spend 27 | more time developing open source software. Some Premium features may be available in 28 | the free software, but they may be restricted (e.g. through a notification to the 29 | registration). Premium features are not essential to the core functionality of 30 | the Program, but are there to provide an incentive for financially supporting the 31 | enhancement and support of the Software. 32 | 33 | Registration Scheme 34 | Registration is carried out via our web shop (FastSpring) which sells registration keys. 35 | Registration keys are personal, non-transferrable and usually restricted to a time period 36 | (typically one year). To protect their personal nature they are tied to the user's 37 | Email address. 38 | 39 | Motivation 40 | As regards licensing, we want to avoid a situation where the project is reused 41 | in order to avoid our monetisation by giving this away for free or cheaper than us 42 | thus disincentivising the current developers from putting a lot of time into 43 | development and support. 44 | 45 | 46 | If plan to you use large portions of the code please contact the author 47 | (Axel Grude) 48 | And Support (Marky Mark DE) 49 | 50 | This program is distributed in the hope that it will be useful, 51 | but WITHOUT ANY WARRANTY; without even the implied warranty of 52 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 53 | Creative Commons (CC BY-ND 4.0) License for more details. 54 | 55 | 56 | ATTRIBUTIONS 57 | 58 | SmartTemplates includes work by 59 | 60 | Current developer: 61 | Axel Grude 62 | Marky Mark DE 63 | 64 | 65 | Contributors: 66 | Aris - style support 67 | tool8 - development, Version 0.7.2 - 0.8.0 68 | Benito van der Zander - Turing patch [Bug 25676] 69 | Klaus Buecher - conversion to Thunderbird 78 70 | 71 | Translations: 72 | Translators were listed in the legacy versions of SmartTemplates (before 2.2) 73 | Since the Babelzilla project cannot parse the new installation manifest 74 | from now on translations are now made by Axel Grude with the help of google translate. 75 | 76 | Source Code: 77 | The source code and current issue tracker can be found here: 78 | https://github.com/RealRaven2000/SmartTemplate4 79 | 80 | NOIA ICON SET: 81 | This Iconset is Published under GNU LESSER GENERAL PUBLIC LICENSE 82 | -> see:Noia_KDE_0.95.tar_4.tgz / lesser.txt 83 | 84 | Made by Carlitus (Carles Carbonell Bernado) 85 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Axel Grude", 3 | "manifest_version": 2, 4 | "name": "SmartTemplates", 5 | "description": "__MSG_extensionDescription__", 6 | "version": "4.12", 7 | "default_locale": "en", 8 | "developer": { 9 | "name": "Axel Grude (author)", 10 | "url": "https://smarttemplates.quickfolders.org/index.html" 11 | }, 12 | "applications": { 13 | "gecko": { 14 | "id": "smarttemplate4@thunderbird.extension", 15 | "strict_min_version": "111.0", 16 | "strict_max_version": "140.*" 17 | } 18 | }, 19 | "background": { 20 | "page": "st-background.html" 21 | }, 22 | "permissions": [ 23 | "accountsRead", 24 | "addressBooks", 25 | "clipboardRead", 26 | "clipboardWrite", 27 | "compose", 28 | "menus", 29 | "messagesRead", 30 | "notifications", 31 | "tabs", 32 | "storage" 33 | ], 34 | "browser_action": { 35 | "default_icon": { 36 | "19": "chrome/content/skin/icon32x32.png" 37 | }, 38 | "default_title": "SmartTemplates", 39 | "default_windows": [ "normal" ], 40 | "allowed_spaces": ["mail"], 41 | "type" : "menu" 42 | }, 43 | "message_display_action" : { 44 | "browser_style" : true, 45 | "default_label" : "SmartTemplates", 46 | "default_icon": { 47 | "19": "chrome/content/skin/icon16x16.png", 48 | "32": "chrome/content/skin/icon32x32.png" 49 | }, 50 | "type" : "menu" 51 | }, 52 | "experiment_apis": { 53 | "WindowListener": { 54 | "schema": "chrome/content/api/WindowListener/schema.json", 55 | "parent": { 56 | "scopes": ["addon_parent"], 57 | "paths": [["WindowListener"]], 58 | "script": "chrome/content/api/WindowListener/implementation.js" 59 | } 60 | }, 61 | "LegacyPrefs": { 62 | "schema": "chrome/content/api/LegacyPrefs/schema.json", 63 | "parent": { 64 | "scopes": ["addon_parent"], 65 | "paths": [["LegacyPrefs"]], 66 | "script": "chrome/content/api/LegacyPrefs/implementation.js" 67 | } 68 | }, 69 | "NotifyTools": { 70 | "schema": "chrome/content/api/NotifyTools/schema.json", 71 | "parent": { 72 | "scopes": ["addon_parent"], 73 | "paths": [["NotifyTools"]], 74 | "script": "chrome/content/api/NotifyTools/implementation.js", 75 | "events": ["startup"] 76 | } 77 | }, 78 | "Utilities": { 79 | "schema": "chrome/content/api/Utilities/schema.json", 80 | "parent": { 81 | "scopes": ["addon_parent"], 82 | "paths": [["Utilities"]], 83 | "script": "chrome/content/api/Utilities/implementation.js" 84 | } 85 | } 86 | }, 87 | "icons": { 88 | "32": "chrome/content/skin/icon32x32.png", 89 | "64": "chrome/content/skin/icon64x64.png" 90 | }, 91 | "options_ui": { 92 | "page": "html/smartTemplate-settings.html", 93 | "open_in_tab": true 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /popup/animation.js: -------------------------------------------------------------------------------- 1 | /* 2 | http://jsfiddle.net/realraven2000/rh6k0z34/14/ 3 | */ 4 | 5 | // add animation to body element (pass 'body' as id) 6 | async function addAnimation(el) { 7 | let licenseInfo = await messenger.runtime.sendMessage({command:"getLicenseInfo"}); 8 | let isExpired = licenseInfo.isExpired, 9 | isValid = licenseInfo.isValid; 10 | 11 | if (isValid && !isExpired) return; 12 | 13 | var exists = document.getElementById('gimmick'); 14 | if (exists) { 15 | exists.parentNode.removeChild(exists); 16 | return false; 17 | } 18 | 19 | let element = document.querySelector(el), 20 | canvas = document.createElement('canvas'), 21 | ctx = canvas.getContext('2d'), 22 | focused = false; 23 | 24 | canvas.width = window.innerWidth; 25 | canvas.height = window.innerHeight; 26 | canvas.id = 'gimmick'; 27 | 28 | var coins = [], 29 | coin = new Image(); 30 | // 'http://i.imgur.com/5ZW2MT3.png'; 31 | // 440 wide, 40 high, 10 states 32 | coin.onload = function () { 33 | element.appendChild(canvas); 34 | focused = true; 35 | drawloop(); 36 | } 37 | coin.src = 'coins-animation-dlr.png'; 38 | 39 | function drawloop() { 40 | if (focused) { 41 | requestAnimationFrame(drawloop); 42 | } 43 | 44 | ctx.clearRect(0, 0, canvas.width, canvas.height) 45 | 46 | if (Math.random() < .3) { 47 | coins.push({ 48 | x: Math.random() * canvas.width | 0, 49 | y: -20, 50 | dy: 3, 51 | s: 0.5 + Math.random(), 52 | state: Math.random() * 10 | 0 53 | }) 54 | } 55 | var i = coins.length 56 | while (i--) { 57 | var x = coins[i].x 58 | var y = coins[i].y 59 | var s = coins[i].s 60 | var state = coins[i].state 61 | coins[i].state = (state > 9) ? 0 : state + 0.1 62 | coins[i].dy += 0.13 63 | coins[i].y += coins[i].dy 64 | 65 | ctx.drawImage(coin, 44 * Math.floor(state), 0, 44, 40, x, y, 44 * s, 40 * s) 66 | 67 | if (y > canvas.height) { 68 | coins.splice(i, 1); 69 | } 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /popup/bargain25new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealRaven2000/SmartTemplates/328f7228734e66089a0ada97799afaa405674320/popup/bargain25new.png -------------------------------------------------------------------------------- /popup/bargain33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealRaven2000/SmartTemplates/328f7228734e66089a0ada97799afaa405674320/popup/bargain33.png -------------------------------------------------------------------------------- /popup/bargainUpgrade33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealRaven2000/SmartTemplates/328f7228734e66089a0ada97799afaa405674320/popup/bargainUpgrade33.png -------------------------------------------------------------------------------- /popup/coins-animation-dlr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RealRaven2000/SmartTemplates/328f7228734e66089a0ada97799afaa405674320/popup/coins-animation-dlr.png -------------------------------------------------------------------------------- /popup/installed.css: -------------------------------------------------------------------------------- 1 | ul.actions { 2 | 3 | } 4 | 5 | .actionlinks { 6 | text-align: center; 7 | } 8 | 9 | .actionlinks a { 10 | background-color: darkred; 11 | box-shadow: 5px 5px 5px rgba(50,50,50,0.5); 12 | color: white; 13 | padding: 5px 8px; 14 | cursor: pointer; 15 | } 16 | 17 | .actionlinks a:hover { 18 | background-image: linear-gradient(to bottom, #6d0019 0%,#8f0222 34%,#e20425 100%); 19 | } 20 | 21 | .actionlinks a:active { 22 | background-image: linear-gradient(to bottom, #633b00 0%,#750202 34%,#ef8204 100%); 23 | } 24 | 25 | body * { 26 | background-color: white; 27 | } 28 | 29 | h1, h2, h3, h4 { 30 | color: #1a566d; 31 | font-family: Impact,Haettenschweiler,Franklin Gothic Bold,Charcoal,Helvetica Inserat,Bitstream Vera Sans Bold,Arial Black,sans serif; 32 | text-align: center; 33 | } 34 | 35 | h1 { 36 | font-size: 24pt; 37 | } 38 | 39 | h2 { 40 | font-size: 20pt; 41 | font-weight: normal; 42 | } 43 | 44 | h3 { 45 | font-size: 16pt; 46 | } -------------------------------------------------------------------------------- /popup/installed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |

__MSG_heading-installed__

12 |

13 | __MSG_thanks-for-installing-intro__ 14 | __MSG_active-version-info__ 15 |

16 | 17 | 18 | 19 |

20 | __MSG_license-is-extended__ 21 |

22 | 23 |
24 |

__MSG_newsHead__

25 |
__MSG_newsSection.intro__
26 |
__MSG_newsSection.important__
27 |

28 | __MSG_whats-new-intro__ 29 | __MSG_whats-new-btn__ 30 |

31 |
32 | 33 |

34 | __MSG_support-suggestion__ 35 |

36 | 37 | 38 |
    39 | 40 | 41 | 42 |
43 | 44 |

__MSG_purchase-heading__

45 | 46 |

47 | __MSG_support-preference__ 48 |

49 |

50 | __MSG_ongoing-work__ 51 |

52 | 53 | 59 | 60 | 61 |

__MSG_donate-heading__

62 | 63 |

64 | __MSG_cost-of-independence__ 65 | __MSG_mozillas-basic-platform__ 66 |

67 | 68 |

__MSG_addon-authors-struggle__

69 | 70 | 73 | 74 | 75 |
76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /popup/installed.js: -------------------------------------------------------------------------------- 1 | /* BEGIN LICENSE BLOCK 2 | 3 | SmartTemplates is released under the Creative Commons (CC BY-ND 4.0) 4 | Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0) 5 | For details, please refer to license.txt in the root folder of this extension 6 | 7 | END LICENSE BLOCK */ 8 | // Script for splash screen displayed when installing this Extension 9 | 10 | addEventListener("click", async (event) => { 11 | if (event.target.id.startsWith("register")) { 12 | messenger.windows.openDefaultBrowser("https://sites.fastspring.com/quickfolders/product/smarttemplate4?referrer=landing-install"); 13 | } 14 | if ( 15 | event.target.id.startsWith("extend") || 16 | event.target.id.startsWith("renew") || 17 | event.target.id.startsWith("upgrade") 18 | ) { 19 | messenger.Utilities.showXhtmlPage("chrome://smarttemplate4/content/register.xhtml"); 20 | window.close(); 21 | } 22 | if (event.target.id.startsWith("donate")) { 23 | messenger.windows.openDefaultBrowser("https://smarttemplates.quickfolders.org/contribute.html#donate"); 24 | } 25 | if (event.target.id == "whatsNew") { 26 | messenger.Utilities.showVersionHistory(); 27 | } 28 | }); 29 | 30 | window.addEventListener("keydown", (event) => { 31 | if (event.key == "Escape") { 32 | window.close(); 33 | } 34 | }); 35 | 36 | 37 | addEventListener("load", async (event) => { 38 | const manifest = await messenger.runtime.getManifest(), 39 | browserInfo = await messenger.runtime.getBrowserInfo(), 40 | addonName = manifest.name, 41 | addonVer = manifest.version, 42 | appVer = browserInfo.version; 43 | 44 | // force replacement for __MSG_xx__ entities 45 | // using John's helper method (which calls i18n API) 46 | i18n.updateDocument(); 47 | 48 | const h1 = document.getElementById("heading-installed"); 49 | ariaPoliteUpdate(h1, messenger.i18n.getMessage('heading-installed', addonName)); 50 | 51 | const thanksInfo = document.getElementById('thanks-for-installing-intro'); 52 | ariaPoliteUpdate(thanksInfo, messenger.i18n.getMessage("thanks-for-installing-intro", addonName)); 53 | 54 | const verInfo = document.getElementById("active-version-info"); 55 | // HTML replacement 56 | ariaPoliteUpdate(verInfo, 57 | messenger.i18n.getMessage("active-version-info", [addonVer, appVer]) 58 | .replace("{boldStart}","") 59 | .replace("{boldEnd}",""), 60 | true 61 | ); 62 | 63 | const suggestion = document.getElementById("support-suggestion"); 64 | ariaPoliteUpdate(suggestion, messenger.i18n.getMessage("support-suggestion", addonName)); 65 | 66 | const preference = document.getElementById("support-preference"); 67 | ariaPoliteUpdate(preference, messenger.i18n.getMessage("support-preference", addonName)); 68 | 69 | 70 | const ongoing = document.getElementById("ongoing-work"); 71 | ariaPoliteUpdate(ongoing, messenger.i18n.getMessage("ongoing-work", addonName)); 72 | 73 | const title = document.getElementById("window-title"); 74 | ariaPoliteUpdate(title, messenger.i18n.getMessage("window-title", addonName)); 75 | 76 | updateActions(addonName); 77 | 78 | ariaPoliteUpdate( 79 | document.getElementById("newsIntro"), 80 | formatAll(messenger.i18n.getMessage("newsSection.intro")), 81 | true 82 | ); 83 | 84 | ariaPoliteUpdate( 85 | document.getElementById("newsImportant"), 86 | formatAll(messenger.i18n.getMessage("newsSection.important")), 87 | true 88 | ); 89 | 90 | const innerWrapper = document.getElementById("innerwrapper"); 91 | innerWrapper.querySelectorAll("a.contactsupport").forEach((link) => { 92 | link.addEventListener("click", (event) => { 93 | event.preventDefault(); 94 | const topic = link.dataset.topic || null; 95 | openSupportForm(topic); 96 | }); 97 | }); 98 | 99 | setTimeout( 100 | () => { 101 | show("newsHead"); 102 | show("newsIntro"); 103 | show("newsImportant"); 104 | show("newsSection"); 105 | }, 106 | 150 107 | ); 108 | 109 | // you can close the window using ESC 110 | addAriaHint(); 111 | }); 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /popup/sales.js: -------------------------------------------------------------------------------- 1 | // used in popup.js 2 | const sales_end = new Date("2025-06-13"); // Next Sale End Date (replaces endSale in popup.js) 3 | 4 | // used in update.js 5 | const discountRate = { 6 | discountPro: "33%", 7 | discountUpgrade: "33%", 8 | discountRenewal: "25%" 9 | } 10 | 11 | // => to localize update special-offer-expiry in messages.json! 12 | const compatibleVer = "140.*"; // Thunderbird for newsSection 13 | -------------------------------------------------------------------------------- /release-notes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The full change log with screen shots can be found here 5 | 6 | Maintenance Release 4.12 7 |
    8 |
  • 9 | Official Thunderbird 140 ESR compatibility 10 |
  • 11 |
  • SmartTemplates is now fully compatible with Thunderbird 140 in preparation for the upcoming annual Thunderbird ESR, expected within the next month (June / July 2025). Users who opt into Thunderbird’s monthly update channel can rest assured: SmartTemplates will continue to deliver compatible, stable releases every month.
  • 12 |
  • Modernized internal dialogs: replaced legacy XHTML-based windows with native Thunderbird popups for improved appearance and compatibility. This is part of the ongoing effort of removing legacy (experimental) technology from the Add-on. [issue 378] 13 |
  • 14 |
15 | 16 | Miscellaneous 17 |
    18 |
  • License Management Fix: Clicking 'Extend License' for any license now correctly opens the matching product page, instead of incorrectly opening the New License screen. [issue 377] 19 |
  • 20 |
21 | 22 | -------------------------------------------------------------------------------- /release-notes.md: -------------------------------------------------------------------------------- 1 | The full change log with screen shots [can be found here](https://smarttemplates.quickfolders.org/version.html#4.11.3) 2 | 3 | 4 | 5 | **Official Thunderbird 140 ESR compatibility** 6 | 7 | * SmartTemplates is now fully compatible with Thunderbird 140 in preparation for the upcoming annual Thunderbird ESR, expected within the next month (June / July 2025). Users who opt into Thunderbird’s monthly update channel can rest assured: SmartTemplates will continue to deliver compatible, stable releases every month. Thankfully this work is covered by license sales. 8 | * Modernized internal dialogs: replaced legacy XHTML-based windows with native Thunderbird popups for improved appearance and compatibility. This is part of the ongoing effort of removing legacy (experimental) technology from the Add-on. [issue #378] 9 | 10 | 11 | 12 | **Bug Fixes** 13 | 14 | * Fixed: Renewal of any License opens wrong product (New License) [issue #375] 15 | 16 | -------------------------------------------------------------------------------- /revision.txt: -------------------------------------------------------------------------------- 1 | 23 2 | -------------------------------------------------------------------------------- /scripts/mozilla-version-comparator.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | BEGIN LICENSE BLOCK 4 | 5 | Copyright (C) 2007 6 | 7 | The code in this module is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | The code in this module is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with The code in this module. If not, see . 19 | 20 | See details & full license here: 21 | https://cdn.jsdelivr.net/npm/mozilla-version-comparator@1.0.2/LICENSE 22 | 23 | END LICENSE BLOCK 24 | */ 25 | 26 | 27 | /* 28 | * return the indexOf the first occurrence of one of char in chars within string. 29 | * see c++ strpbrk function. 30 | */ 31 | var strpbrk = function(string, chars) { 32 | for (var i = 0; i < string.length; i++) { 33 | var index = chars.indexOf(string.charAt(i)); 34 | if (index >= 0) { 35 | return string.indexOf(chars[index]); 36 | } 37 | } 38 | return -1; 39 | }; 40 | 41 | var parseVersionParts = function(versionPart) { 42 | var result = { 43 | numberA: 0, 44 | numberC: 0 45 | }; 46 | 47 | if (!versionPart) { 48 | return result; 49 | } 50 | 51 | if (versionPart === '*') { 52 | result.numberA = Number.MAX_VALUE; 53 | result.stringB = ''; 54 | return result; 55 | } else { 56 | result.numberA = parseInt(versionPart, 10); 57 | result.stringB = versionPart.substr(result.numberA.toString().length); 58 | } 59 | 60 | if (result.stringB[0] === '+') { 61 | result.stringB = result.stringB.replace('+', 'pre'); 62 | ++result.numberA; 63 | } else { 64 | var indexOfNextNumber = strpbrk(result.stringB, '0123456789+-'); 65 | if (indexOfNextNumber >= 0) { 66 | var extra = result.stringB.substr(indexOfNextNumber); 67 | result.numberC = parseInt(extra, 10); 68 | result.stringD = result.stringB.slice(indexOfNextNumber + result.numberC.toString().length); 69 | result.stringB = result.stringB.slice(0, result.stringB.length - extra.length); 70 | } 71 | } 72 | 73 | return result; 74 | }; 75 | 76 | var compare = function(a, b) { 77 | if (a > b) { 78 | return 1; 79 | } else if (a === b) { 80 | return 0; 81 | } else { 82 | return -1; 83 | } 84 | }; 85 | 86 | var strcmp = function(str1, str2) { 87 | if (!str1) { 88 | return (str2) ? 1 : 0; 89 | } else if (!str2) { 90 | return -1; 91 | } else { 92 | return compare(str1.replace(/00/g, '0'), str2.replace(/00/g, '0')); 93 | } 94 | }; 95 | 96 | var compareVersionPart = function(versionPart1, versionPart2) { 97 | if (!versionPart1) { 98 | return -1; 99 | } else if (!versionPart2) { 100 | return 1; 101 | } else { 102 | var result = compare(versionPart1.numberA, versionPart2.numberA); 103 | if (result) { 104 | return result; 105 | } 106 | 107 | result = strcmp(versionPart1.stringB, versionPart2.stringB); 108 | if (result) { 109 | return result; 110 | } 111 | 112 | result = compare(versionPart1.numberC, versionPart2.numberC); 113 | if (result) { 114 | return result; 115 | } 116 | 117 | result = strcmp(versionPart1.stringD, versionPart2.stringD); 118 | return result; 119 | } 120 | }; 121 | 122 | export var compareVersions = function(version1, version2) { 123 | var result = 0; 124 | 125 | var partsOfVersion1 = version1.split('.'); 126 | var partsOfVersion2 = version2.split('.'); 127 | 128 | if (version2=="?") return 1; 129 | if (version1=="?") return -1; 130 | 131 | var maxLength = Math.max(partsOfVersion1.length, partsOfVersion2.length); 132 | 133 | for (var i = 0; i < maxLength; i++) { 134 | var versionPart1 = parseVersionParts(partsOfVersion1[i]); 135 | var versionPart2 = parseVersionParts(partsOfVersion2[i]); 136 | result = compareVersionPart(versionPart1, versionPart2); 137 | if (result) { 138 | return result; 139 | } 140 | } 141 | 142 | return result; 143 | }; 144 | -------------------------------------------------------------------------------- /scripts/rsa/Barrett.mjs.js: -------------------------------------------------------------------------------- 1 | import {BigIntModule} from './BigIntModule.mjs.js'; 2 | 3 | // BarrettMu, a class for performing Barrett modular reduction computations in 4 | // JavaScript. 5 | // 6 | // Requires BigInt.js. 7 | // 8 | // Copyright 2004-2005 David Shapiro. 9 | // 10 | // You may use, re-use, abuse, copy, and modify this code to your liking, but 11 | // please keep this header. 12 | // 13 | // Thanks! 14 | // 15 | // Dave Shapiro 16 | // dave@ohdave.com 17 | 18 | export class Barrett { 19 | constructor(m) { 20 | BigIntModule.init(); 21 | BigIntModule.logDebug("New Barrett instance!"); 22 | this.modulus = BigIntModule.biCopy(m); 23 | this.k = BigIntModule.biHighIndex(this.modulus) + 1; 24 | let b2k = new BigIntModule.BigInt(); 25 | b2k.digits[2 * this.k] = 1; // b2k = b^(2k) 26 | this.mu = BigIntModule.biDivide(b2k, this.modulus); 27 | this.bkplus1 = new BigIntModule.BigInt(); 28 | this.bkplus1.digits[this.k + 1] = 1; // bkplus1 = b^(k+1) 29 | this.modulo = this.BarrettMu_modulo; 30 | this.multiplyMod = this.BarrettMu_multiplyMod; 31 | this.powMod = this.BarrettMu_powMod; 32 | } 33 | 34 | log(txt) { 35 | console.log(txt); 36 | } 37 | 38 | BarrettMu_modulo(x) { 39 | BigIntModule.init(); 40 | let q1 = BigIntModule.biDivideByRadixPower(x, this.k - 1), 41 | q2 = BigIntModule.biMultiply(q1, this.mu), 42 | q3 = BigIntModule.biDivideByRadixPower(q2, this.k + 1), 43 | r1 = BigIntModule.biModuloByRadixPower(x, this.k + 1), 44 | r2term = BigIntModule.biMultiply(q3, this.modulus), 45 | r2 = BigIntModule.biModuloByRadixPower(r2term, this.k + 1), 46 | r = BigIntModule.biSubtract(r1, r2); 47 | if (r.isNeg) { 48 | r = BigIntModule.biAdd(r, this.bkplus1); 49 | } 50 | let rgtem = BigIntModule.biCompare(r, this.modulus) >= 0; 51 | while (rgtem) { 52 | r = BigIntModule.biSubtract(r, this.modulus); 53 | rgtem = BigIntModule.biCompare(r, this.modulus) >= 0; 54 | } 55 | return r; 56 | } 57 | 58 | BarrettMu_multiplyMod(x, y) { 59 | let xy = BigIntModule.biMultiply(x, y); 60 | return this.modulo(xy); 61 | } 62 | 63 | BarrettMu_powMod(x, y) { 64 | 65 | let isLog = true; //use LegacyPrefs API messenger.LegacyPrefs.getPref(); SmartTemplate4.Preferences.isDebugOption('premium.rsa'); 66 | 67 | BigIntModule.logDebug('BarrettMu_powMod()'); 68 | BigIntModule.init(); 69 | let result = new BigIntModule.BigInt(); 70 | result.digits[0] = 1; 71 | let a = x, 72 | k = y, 73 | count = 0, 74 | testStrng = ''; 75 | while (true) { 76 | if (isLog) { 77 | testStrng = testStrng + (' ' + (++count)).slice(-3) + '.' // left pad counter 78 | + ' digits[0] = ' 79 | + (' ' + k.digits[0]).slice(-5) // left pad number 80 | + ' a=' + a.digits + '\n'; 81 | } 82 | if ((k.digits[0] & 1) != 0) result = this.multiplyMod(result, a); 83 | k = BigIntModule.biShiftRight(k, 1); 84 | if (k.digits[0] == 0 && BigIntModule.biHighIndex(k) == 0) break; 85 | a = this.multiplyMod(a, a); 86 | } 87 | if (isLog) { 88 | BigIntModule.logDebug(testStrng); 89 | BigIntModule.logDebug('BarrettMu_powMod().result =' + result.digits); 90 | } 91 | return result; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /scripts/st-composer.mjs.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* 3 | BEGIN LICENSE BLOCK 4 | 5 | SmartTemplates is released under the Creative Commons (CC BY-ND 4.0) 6 | Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0) 7 | For details, please refer to license.txt in the root folder of this extension 8 | 9 | END LICENSE BLOCK 10 | */ 11 | 12 | // this module will replace all SmartTemplate4.composer 13 | // objects in smartTemplate-composer.js 14 | 15 | export let composer = { 16 | 17 | } -------------------------------------------------------------------------------- /scripts/st-crypto.mjs.js: -------------------------------------------------------------------------------- 1 | /* note the encryption key is private. Do not reverse engineer */ 2 | /* 3 | BEGIN LICENSE BLOCK 4 | 5 | SmartTemplates is released under the Creative Commons (CC BY-ND 4.0) 6 | Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0) 7 | For details, please refer to license.txt in the root folder of this extension 8 | 9 | END LICENSE BLOCK 10 | */ 11 | 12 | export function getDecryption_key(key_type) { 13 | switch (key_type) { 14 | case 0: // Pro 15 | case 2: // Standard 16 | return "494d467df07bdf71e8f83d99e73f203f08bfaa9d8345b69a0b8069aff6b35569"; 17 | case 1: // domain 18 | return "68a025ffe52fd5cf9beaf0693b6e77e58278f6089f01bdac4afe965241f5cf8a5d9e25d0750091a7c8bcb3807909ddc290f00ed9ab6437d801ab1a2ac14cd5b"; 19 | default: 20 | return -1; // unknown or free license 21 | } 22 | } 23 | 24 | export function getModulus(key_type) { 25 | switch (key_type) { 26 | case 0: // Pro 27 | case 2: // Standard 28 | return "49e2f5a409ecc3c96171df82f4cb0cbf274668e713008feb6d67f0ba45058ad5"; 29 | case 1: // domain 30 | return "12c127d3fb813f8bba7e863ab31c9943b76505f96cb87bfa9d4f9dc503a1bfe0c74e0057cff6ee9f3814fb90bc42207fdd908fbdb00cbf9a8f8c53dc7c4ed7b5"; 31 | default: 32 | return -1; // unknown or free license 33 | } 34 | } 35 | 36 | // determine the type of key from the prefix - this is Add-on specific! 37 | // extend this method to introduce other types of licenses. 38 | export function getKeyType(licenseKey) { 39 | if (!licenseKey) 40 | return 0; // default to Pro, but that doesn't mean there is a valid license! 41 | if (licenseKey.startsWith('STD')) { 42 | return 1; // Domain License 43 | } else if (licenseKey.startsWith('S1')) { 44 | return 2; // Standard License 45 | } else { 46 | return 0; // Pro License 47 | } // SmartTemplates uses "S1" for standard licenses with key_type=2 48 | } 49 | 50 | 51 | export function getMaxDigits(key_type) { 52 | switch (key_type) { 53 | case 0: // Pro 54 | case 2: // Standard 55 | return 35; 56 | case 1: // domain 57 | return 67; 58 | default: 59 | return 0; // unknown or free license 60 | } 61 | } 62 | 63 | export function getKeyLength(key_type) { 64 | switch (key_type) { 65 | case 0: // Pro 66 | case 2: // Standard 67 | return 256; 68 | case 1: // domain 69 | return 512; 70 | default: 71 | return 0; // unknown or free license 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /scripts/st-main.mjs.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* 3 | BEGIN LICENSE BLOCK 4 | 5 | SmartTemplates is released under the Creative Commons (CC BY-ND 4.0) 6 | Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0) 7 | For details, please refer to license.txt in the root folder of this extension 8 | 9 | END LICENSE BLOCK 10 | */ 11 | 12 | 13 | /* creates the SmartTemplates namespace by importing from other ESR modules */ 14 | 15 | import {Preferences} from "./st-prefs.mjs.js"; 16 | import {Util} from "./st-util.mjs.js"; 17 | import * as classSmartTemplate from "./st-compose.mjs.js"; 18 | import {composer} from "./st-composer.mjs.js"; 19 | import {Styles} from "./st-styles.mjs.js"; 20 | import {Sig} from "./st-signature.mjs.js"; 21 | // Parser = {classGetHeaders, clsGetAltHeader, mimeDecoder, parseModifier, regularize, getProcessedText} 22 | import { Parser } from "./st-parser.mjs.js"; 23 | 24 | 25 | let SmartTemplates = { 26 | Util, 27 | Preferences, 28 | ...classSmartTemplate, 29 | Parser, // a class for stuff that was directly in SmartTemplate4 namespace (from smartTemplate-overlay.js) 30 | composer, 31 | Sig, 32 | prefs : Preferences.identityPrefs 33 | } 34 | 35 | // ************************************** 36 | // TO DO: GLOBAL REPLACEMENTS IN MODULES 37 | // SmartTemplates.pref = Preferences.identityPrefs; // but what if this is used in one of the sub modules??????? 38 | // this is used in st-compose.mjs.js , st-parser.mjs.js , st-util.mjs.js 39 | // but according to John this would be a circular reference. 40 | // could be a CONST structure 41 | SmartTemplates.PreprocessingFlags = { 42 | hasCursor: false, 43 | hasSignature: false, 44 | omitSignature: false, 45 | hasQuotePlaceholder: false, 46 | hasQuoteHeader: false, // WIP 47 | hasTemplatePlaceHolder: false, // future use 48 | isStationery: false, 49 | isThunderbirdTemplate: false, 50 | isFileTemplate: false 51 | } 52 | 53 | 54 | export { SmartTemplates }; -------------------------------------------------------------------------------- /scripts/st-signature.mjs.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* 3 | BEGIN LICENSE BLOCK 4 | 5 | SmartTemplates is released under the Creative Commons (CC BY-ND 4.0) 6 | Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0) 7 | For details, please refer to license.txt in the root folder of this extension 8 | 9 | END LICENSE BLOCK 10 | */ 11 | 12 | // this module will replace all SmartTemplate4.Sig 13 | // object in smartTemplate-signature.js 14 | 15 | export let Sig = { 16 | 17 | } -------------------------------------------------------------------------------- /scripts/st-styles.mjs.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* 3 | BEGIN LICENSE BLOCK 4 | 5 | SmartTemplates is released under the Creative Commons (CC BY-ND 4.0) 6 | Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0) 7 | For details, please refer to license.txt in the root folder of this extension 8 | 9 | END LICENSE BLOCK 10 | */ 11 | 12 | // this module will replace all SmartTemplate4.Styles 13 | // object in smartTemplate-styles.js 14 | 15 | export let Styles = { 16 | 17 | } -------------------------------------------------------------------------------- /st-background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | --------------------------------------------------------------------------------