### LegacyPrefs API Functions Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/LegacyPrefs/README.md This section details the functions available in the LegacyPrefs API for managing Thunderbird preferences. ```APIDOC ## LegacyPrefs API Functions ### async getPref(aName, [aFallback]) #### Description 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``). #### Method GET #### Endpoint /realraven2000/quickfilters/LegacyPrefs #### Parameters ##### Query Parameters - **aName** (string) - Required - The name of the preference to retrieve. - **aFallback** (any) - Optional - The fallback value to return if the preference is not found. #### Response ##### Success Response (200) - **value** (any) - The value of the preference or the fallback value. ### async getUserPref(aName) #### Description 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``. #### Method GET #### Endpoint /realraven2000/quickfilters/LegacyPrefs/user #### Parameters ##### Query Parameters - **aName** (string) - Required - The name of the user preference to retrieve. #### Response ##### Success Response (200) - **value** (any) - The user-defined value of the preference or null. ### clearUserPref(aName) #### Description Clears the user defined value for preference ``aName``. Subsequent calls to ``getUserPref(aName)`` will return ``null``. #### Method DELETE #### Endpoint /realraven2000/quickfilters/LegacyPrefs/user/{aName} #### Parameters ##### Path Parameters - **aName** (string) - Required - The name of the user preference to clear. ### async setPref(aName, aValue) #### Description 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. #### Method POST #### Endpoint /realraven2000/quickfilters/LegacyPrefs #### Parameters ##### Request Body - **aName** (string) - Required - The name of the preference to set. - **aValue** (any) - Required - The value to set the preference to. #### Response ##### Success Response (200) - **success** (boolean) - True if the preference was set successfully, false otherwise. ``` -------------------------------- ### LegacyPrefs API Events Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/LegacyPrefs/README.md This section details the events provided by the LegacyPrefs API for monitoring preference changes. ```APIDOC ## LegacyPrefs API Events ### onChanged.addListener(listener, branch) #### Description 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. #### Method POST #### Endpoint /realraven2000/quickfilters/LegacyPrefs/onChanged/addListener #### Parameters ##### Request Body - **listener** (function) - Required - The callback function to execute when a preference changes. - **branch** (string) - Required - The specific branch of preferences to monitor. #### Example ```javascript browser.LegacyPrefs.onChanged.addListener(async (name, value) => { console.log(`Changed value in \"mailnews.\": ${name} = ${value}`); }, "mailnews."); ``` #### Response ##### Success Response (200) - **status** (string) - Indicates the subscription status. ``` -------------------------------- ### Register Scripts for Thunderbird Windows - JavaScript Source: https://context7.com/realraven2000/quickfilters/llms.txt This code snippet illustrates how to use `messenger.WindowListener` to inject custom JavaScript files into specific Thunderbird windows upon their opening. It covers registering default preferences, defining chrome content URLs, and associating script files with particular XUL windows like the messenger, filter editor, filter list, and a 'about:3pane' view. This enables interaction between WebExtension code and legacy Thunderbird components. The listener must be started with `startListening()`. ```javascript // Register default preferences messenger.WindowListener.registerDefaultPrefs( "chrome/content/scripts/quickFilter-prefs.js" ); // Register chrome content URLs messenger.WindowListener.registerChromeUrl([ ["content", "quickfilters", "chrome/content/"] ]); // Register scripts for specific windows messenger.WindowListener.registerWindow( "chrome://messenger/content/messenger.xhtml", "chrome/content/scripts/qFi-messenger.js" ); messenger.WindowListener.registerWindow( "chrome://messenger/content/FilterEditor.xhtml", "chrome/content/scripts/qFi-filterEditor.js" ); messenger.WindowListener.registerWindow( "chrome://messenger/content/FilterListDialog.xhtml", "chrome/content/scripts/qFi-filterlist.js" ); messenger.WindowListener.registerWindow( "about:3pane", "chrome/content/scripts/qFi-3pane.js" ); // Start listening for window opens messenger.WindowListener.startListening(); // Each registered script is loaded into an object namespace // in the target window's global scope, preventing collisions ``` -------------------------------- ### Listen for Preference Changes with LegacyPrefs API Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/LegacyPrefs/README.md This example demonstrates how to use the `onChanged.addListener` function from the LegacyPrefs API to be notified when a preference within a specific branch changes. The listener receives the name and new value of the changed preference. ```javascript browser.LegacyPrefs.onChanged.addListener(async (name, value) => { console.log(`Changed value in \"mailnews.\": ${name} = ${value}`); }, "mailnews."); ``` -------------------------------- ### Add LegacyPrefs API to manifest.json Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/LegacyPrefs/README.md This snippet shows the necessary configuration in your add-on's manifest.json file to include the LegacyPrefs API. It specifies the schema, scopes, paths, and implementation script for the API. ```json { "experiment_apis": { "LegacyPrefs": { "schema": "api/LegacyPrefs/schema.json", "parent": { "scopes": ["addon_parent"], "paths": [["LegacyPrefs"]], "script": "api/LegacyPrefs/implementation.js" } } } } ``` -------------------------------- ### Handle Runtime Messages with onMessage Listener - JavaScript Source: https://context7.com/realraven2000/quickfilters/llms.txt This code snippet demonstrates how to use the `messenger.runtime.onMessage.addListener` function to process command messages from popup windows and settings pages. It handles various commands such as retrieving license information, fetching filters, resolving assistant requests, updating licenses, and resizing assistant windows. Dependencies include the `messenger` API and potentially `currentLicense` and `Licenser` objects. ```javascript messenger.runtime.onMessage.addListener(async (data, sender) => { if (!data.command) { return; } switch (data.command) { case "getLicenseInfo": return currentLicense.info; case "getFilters": { const { sourceUri, targetUri, filterAction, filterActionExt } = data; try { const filters = await messenger.FiltersAPI.getFilters( sourceUri, targetUri || "", filterAction || null, filterActionExt || null ); return filters; } catch (error) { console.error("getFilters failed:", error); return []; } } case "assistantResult": { const { requestId, result, params } = data; const mergeFilter = params?.mergeFilter || null; const resultIdx = mergeFilter ? mergeFilter.index : -1; await messenger.Utilities.resolveAssistant(requestId, result, { answer: params?.answer, selectedMergedFilterIndex: resultIdx, mergeFilter }); break; } case "updateLicense": { const newLicense = new Licenser(data.key, licenseOptions); await newLicense.validate(); if (newLicense.info.isValid || newLicense.info.isExpired) { await messenger.LegacyPrefs.setPref( "extensions.quickfilters.LicenseKey", newLicense.info.licenseKey ); currentLicense = newLicense; // Broadcast license update await messenger.NotifyTools.notifyExperiment({ licenseInfo: currentLicense.info }); return true; } return false; } case "resizeAssistant": { if (sender.tab) { const windowId = sender.tab.windowId; const maxHeight = window.screen.availHeight; const newHeight = Math.min(data.height, maxHeight); await browser.windows.update(windowId, { height: newHeight }); } break; } } }); ``` -------------------------------- ### Create Folder Pane Context Menu Item - JavaScript Source: https://context7.com/realraven2000/quickfilters/llms.txt Adds a custom context menu item to the folder pane, allowing users to trigger a 'runFilters' command. It includes custom icons and an asynchronous click handler that identifies the selected folder, retrieves its URI, and notifies an experiment with command details. ```javascript const RUNFILTER_ID = "runFiltersFolderPane"; const menuLabel = messenger.i18n.getMessage("quickfilters.RunButton.label"); const menuProps = { contexts: ["folder_pane"], id: RUNFILTER_ID, title: menuLabel, enabled: true, icons: { 16: "chrome/content/skin/runFilters.svg" }, onclick: async (event) => { const selectedFolder = event?.selectedFolder || null; const selectedFolders = event?.selectedFolders || null; if (selectedFolders && selectedFolders.length > 1) { console.log("Cannot execute on multiple folders"); return; } const folderUri = await messenger.Utilities.getFolderUri( selectedFolder.accountId, selectedFolder.path ); const currentTab = await messenger.mailTabs.getCurrent(); await messenger.NotifyTools.notifyExperiment({ event: "doCommand", detail: { commandItem: { id: RUNFILTER_ID }, windowId: currentTab.windowId, tabId: currentTab.id, folderURI: folderUri } }); } }; messenger.menus.create(menuProps); ``` -------------------------------- ### Access Thunderbird Preferences - LegacyPrefsAPI Source: https://context7.com/realraven2000/quickfilters/llms.txt Provides read and write access to Thunderbird's legacy preference system, allowing the extension to manage its configuration. It supports reading values with fallbacks, setting new values, and listening for changes to specific preference branches. ```javascript // Read preference with fallback try { const isDebug = await messenger.LegacyPrefs.getPref( "extensions.quickfilters.debug", false // fallback value if not set ); if (isDebug) { console.log("Debug mode is enabled"); } // Set preference value await messenger.LegacyPrefs.setPref( "extensions.quickfilters.hasNews", true ); // Listen for preference changes messenger.LegacyPrefs.onChanged.addListener( async (name, value) => { console.log(`Preference ${name} changed to:`, value); }, "extensions.quickfilters" // branch to observe ); } catch (error) { console.error("Preference operation failed:", error); } ``` -------------------------------- ### Display Filter Assistant Popup (JavaScript) Source: https://context7.com/realraven2000/quickfilters/llms.txt Opens the filter assistant HTML popup. It takes context from selected messages, folders, or existing filters to help create or merge filter rules. Dependencies include the Thunderbird browser extension APIs like runtime, mailTabs, and FiltersAPI. It returns a popup window for user interaction. ```javascript async function displayAssistant(data) { const assistantURL = browser.runtime.getURL("html/filterAssistant.html"); const url = new URL(assistantURL); // Set context and request ID url.searchParams.set("context", data?.context || ""); url.searchParams.set("requestId", data.requestId); // Resolve source folder let sourceFolder = data.sourceFolder; if (!sourceFolder && data.context === "fromMessageContext") { const tabs = await messenger.mailTabs.query({ active: true, currentWindow: true }); const currentTab = tabs?.length ? tabs[0] : null; if (currentTab?.displayedFolder) { sourceFolder = currentTab.displayedFolder; } } // Set folder parameters if (sourceFolder) { const uri = await messenger.Utilities.getFolderUri( sourceFolder.accountId, sourceFolder.path ); const source = { accountId: sourceFolder.accountId, path: sourceFolder.path, uri: uri }; url.searchParams.set("sourceFolder", JSON.stringify(source)); // Find mergeable filters if (data.context !== "mergeList") { try { const { filterAction, filterActionExt, targetFolder } = data; const targetUri = targetFolder ? await messenger.Utilities.getFolderUri( targetFolder.accountId, targetFolder.path ) : ""; const mergableFilters = await messenger.FiltersAPI.getFilters( uri, targetUri, filterAction || null, filterActionExt || null ); if (mergableFilters?.length) { url.searchParams.set("matchedFilters", JSON.stringify(mergableFilters)); } } catch (ex) { console.warn("FiltersAPI.getFilters failed:", ex); } } } // Set message IDs const { selectedApiMessages } = data; if (selectedApiMessages?.length) { const messageIds = selectedApiMessages .map((msg) => msg.messageId) .filter(Boolean); if (messageIds.length) { url.searchParams.set("messageIds", JSON.stringify(messageIds)); url.searchParams.set("selectedApiMessages", JSON.stringify(selectedApiMessages)); } } // Create popup window const screenH = window.screen.height; const windowHeight = screenH > 650 ? 650 : screenH; await browser.windows.create({ url: url.toString(), type: "popup", width: 780, height: windowHeight, allowScriptsToClose: true }); } // Trigger from NotifyTools listener messenger.NotifyTools.onNotifyBackground.addListener(async (data) => { if (data.func === "quickFiltersAssistant") { try { await displayAssistant(data); } catch (ex) { console.error("displayAssistant failed:", ex); if (data?.requestId?.startsWith("assistant_")) { await messenger.Utilities.resolveAssistant( data.requestId, "error", { answer: null, selectedMergedFilterIndex: -1, error: ex.message } ); } } } }); ``` -------------------------------- ### Retrieve Filters with Criteria - FiltersAPI Source: https://context7.com/realraven2000/quickfilters/llms.txt Fetches email filters from a specified account that match certain criteria, such as a target folder and action type. This is useful for finding filters that can be merged or displayed to the user. It requires the source account URI, and optionally accepts target URI and action type. ```javascript // Get all filters that move messages to a specific folder const sourceUri = "mailbox://user@example.com/Inbox"; const targetUri = "mailbox://user@example.com/Projects"; const filterAction = 4; // MoveToFolder action type try { const filters = await messenger.FiltersAPI.getFilters( sourceUri, targetUri, filterAction, null // filterActionExt ); // filters = [ // { // filterName: "Project Emails", // accountId: "account1", // type: "standard", // templateName: null, // description: "Move project-related emails", // enabled: true, // matchedActionType: 4, // matchedActionExt: null // } // ] console.log(`Found ${filters.length} matching filters`); } catch (error) { console.error("Failed to retrieve filters:", error); } ``` -------------------------------- ### Receiving Notifications in WebExtension Background Page (JavaScript) Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/NotifyTools/README.md This JavaScript code demonstrates how to set up a listener in your WebExtension's background page to receive notifications from Experiment scripts using the NotifyTools API. It handles incoming commands and returns responses. ```javascript messenger.NotifyTools.onNotifyBackground.addListener(async (info) => { switch (info.command) { case "doSomething": //do something let rv = await doSomething(); return rv; break; } }); ``` -------------------------------- ### Notify Experiment Code - NotifyToolsAPI Source: https://context7.com/realraven2000/quickfilters/llms.txt Enables communication from the background script to legacy experiment implementations, typically within the XUL-based UI layer. This allows triggering specific commands or actions in response to user interactions or background events, often passing context like window and tab IDs. ```javascript // Notify experiment to execute a command const menuItem = { id: "runFiltersFolderPane" }; const currentTab = await messenger.mailTabs.getCurrent(); const selectedFolder = { accountId: "account1", path: "/Inbox" }; const folderURI = await messenger.Utilities.getFolderUri( selectedFolder.accountId, selectedFolder.path ); try { await messenger.NotifyTools.notifyExperiment({ event: "doCommand", detail: { commandItem: menuItem, windowId: currentTab.windowId, tabId: currentTab.id, folderURI: folderURI, selectedFolder: selectedFolder, selectedAccount: null } }); } catch (error) { console.error("Failed to notify experiment:", error); } ``` -------------------------------- ### Validate License Key - JavaScript Source: https://context7.com/realraven2000/quickfilters/llms.txt Validates a license key using RSA decryption and checks for email match and expiration date. It initializes a Licenser object with the key and options, attempts validation, and logs the license status or any errors encountered. It also includes functionality to update license dates at midnight. ```javascript import { Licenser } from "./scripts/Licenser.mjs.js"; // Initialize and validate license const licenseKey = "QF-user@example.com:2025-12-31;ENCRYPTED_STRING"; const options = { forceSecondaryIdentity: false, debug: true }; const licenser = new Licenser(licenseKey, options); try { await licenser.validate(); const info = licenser.info; // info = { // status: "Valid" | "Expired" | "Invalid" | "MailNotConfigured" | "MailDifferent" | "Empty", // description: "Valid but expired since 5 days", // licensedDaysLeft: 0, // expiredDays: 5, // expiryDate: "2025-12-31", // email: "user@example.com", // licenseKey: "QF-user@example.com:2025-12-31;...", // decryptedPart: "QF-user@example.com:2025-12-31", // keyType: 0, // 0=pro, 1=domain // isValid: false, // isExpired: true // } if (info.isValid) { console.log(`License valid for ${info.licensedDaysLeft} days`); } else if (info.isExpired) { console.log(`License expired ${info.expiredDays} days ago`); } else { console.error(`License invalid: ${info.status}`); } } catch (error) { console.error("License validation failed:", error); } // Update license dates at midnight await licenser.updateLicenseDates(); ``` -------------------------------- ### QuickFilters UI Button Styling (CSS) Source: https://github.com/realraven2000/quickfilters/blob/ESR115/html/filterAssistant.html This CSS defines the styling for the quick filters button, including its appearance, hover effects, and transitions. It uses background images for icons and specifies various visual properties to ensure a consistent user interface. ```CSS #quickFiltersBtnHelp { background-image: url("../chrome/content/skin/help-new.svg"); border: none; height: 24px; width: 24px; background-size: contain; background-repeat: no-repeat; background-position: center center; background-color: transparent !important; cursor: pointer; display: inline-block; transition: transform 0.2s ease, filter 0.2s ease, border 0.2s ease; } #quickFiltersBtnHelp:hover { transform: scale(1.25); filter: brightness(0.9); border: 1px solid var(--button-hover-border-color, #0064a7) !important; } ``` -------------------------------- ### Manifest Configuration for NotifyTools Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/NotifyTools/README.md This snippet shows how to configure the NotifyTools API in your add-on's manifest.json file. It specifies the schema, implementation script, and event listeners required for the NotifyTools to function within the Thunderbird environment. ```json { "experiment_apis": { "NotifyTools": { "schema": "api/NotifyTools/schema.json", "parent": { "scopes": ["addon_parent"], "paths": [["NotifyTools"]], "script": "api/NotifyTools/implementation.js", "events": ["startup"] } } } } ``` -------------------------------- ### Sending Notifications from Experiment Scripts (JavaScript) Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/NotifyTools/README.md This JavaScript code shows how to send a notification from an Experiment script to the WebExtension's background page using the notifyTools.js script and the notifyBackground function. It expects a response from the background page. ```javascript notifyTools.notifyBackground({command: "doSomething"}).then((data) => { console.log(data); }); ``` -------------------------------- ### Sending Notifications from Background Page to Experiments (JavaScript) Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/NotifyTools/README.md This JavaScript code illustrates how to send a notification from the WebExtension's background page to Experiment scripts using the NotifyTools API's notifyExperiment function. It allows for communication initiated by the background process. ```javascript messenger.NotifyTools.notifyExperiment({command: "doSomething"}).then((data) => { console.log(data) }); ``` -------------------------------- ### Convert Folder Path to URI - UtilitiesAPI Source: https://context7.com/realraven2000/quickfilters/llms.txt Converts a folder's account ID and path into a legacy URI string, which is essential for Thunderbird's internal filter operations and identifying folders within the XPCOM system. This function is often used in conjunction with other APIs like FiltersAPI. ```javascript // Get URI for a specific folder const folder = { accountId: "account1", path: "/Inbox/Work" }; try { const uri = await messenger.Utilities.getFolderUri( folder.accountId, folder.path ); // uri = "mailbox://user@example.com/Inbox/Work" // Use with FiltersAPI const filters = await messenger.FiltersAPI.getFilters(uri); console.log(`Folder URI: ${uri}`); } catch (error) { console.error("Failed to get folder URI:", error); } ``` -------------------------------- ### Toggle IMAP Filter Application - JavaScript Source: https://context7.com/realraven2000/quickfilters/llms.txt Provides functionality to toggle the application of incoming filters for IMAP folders. It creates a checkbox menu item that, when clicked, retrieves the current state of filter application for the selected folder and updates it. It also ensures the checkbox state is correctly displayed when the menu is shown. ```javascript // Toggle incoming filters for IMAP folder const TOGGLE_ID = "toggleApplyIncomingFilters"; messenger.menus.create({ contexts: ["folder_pane"], id: TOGGLE_ID, title: "Apply Incoming Filters", type: "checkbox", enabled: true, onclick: async (event) => { const folders = event?.selectedFolders; if (!Array.isArray(folders) || folders.length !== 1) { return; } const folder = folders[0]; const uri = await messenger.Utilities.getFolderUri( folder.accountId, folder.path ); try { const currentState = await messenger.Utilities.getApplyIncomingFilters(uri); await messenger.Utilities.setApplyIncomingFilters(uri, !currentState); console.log(`Filter application ${!currentState ? "enabled" : "disabled"}`); } catch (ex) { console.error("Error toggling applyIncomingFilters:", ex); } } }); // Update checkbox state when menu is shown messenger.menus.onShown.addListener(async (info) => { if (!info.contexts.includes("folder_pane")) return; const folder = info?.selectedFolders?.[0]; if (!folder) return; const account = await messenger.accounts.get(folder.accountId); const isImap = account.type === "imap"; const uri = await messenger.Utilities.getFolderUri( folder.accountId, folder.path ); await messenger.menus.update(TOGGLE_ID, { visible: isImap, checked: isImap ? await messenger.Utilities.getApplyIncomingFilters(uri) : false }); await messenger.menus.refresh(); }); ``` -------------------------------- ### Add Listener to NotifyTools Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/NotifyTools/README.md Adds a callback function to be executed when a notification is received from the WebExtension's background page. The function returns an ID that can be used to remove the listener. Note that NotifyTools has slightly different behavior regarding return values compared to runtime.sendMessage. ```javascript function doSomething(data) { console.log(data); return true; } let id = notifyTools.addListener(doSomething); ``` -------------------------------- ### Set Add-on ID for NotifyTools Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/NotifyTools/README.md Sets the unique identifier for the add-on. This ID is necessary for the notifyTools.js script to correctly listen for messages from the background page. The ID can also be defined directly in the script. ```javascript notifyTools.setAddOnId(add_on_id); ``` -------------------------------- ### Remove All Listeners from NotifyTools Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/NotifyTools/README.md Removes all registered listeners. This function should be called when an add-on is disabled or reloaded to ensure all active listeners are cleaned up. ```javascript notifyTools.removeAllListeners(); ``` -------------------------------- ### Remove Listener from NotifyTools Source: https://github.com/realraven2000/quickfilters/blob/ESR115/chrome/content/api/NotifyTools/README.md Removes a previously added listener using its unique identifier. This is essential for managing resources and preventing memory leaks. ```javascript notifyTools.removeListener(id); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.