diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/mail/actors | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/mail/actors')
-rw-r--r-- | comm/mail/actors/ChatActionChild.sys.mjs | 55 | ||||
-rw-r--r-- | comm/mail/actors/ChatActionParent.sys.mjs | 32 | ||||
-rw-r--r-- | comm/mail/actors/ContextMenuParent.sys.mjs | 45 | ||||
-rw-r--r-- | comm/mail/actors/LinkClickHandlerChild.jsm | 178 | ||||
-rw-r--r-- | comm/mail/actors/LinkClickHandlerParent.jsm | 30 | ||||
-rw-r--r-- | comm/mail/actors/LinkHandlerParent.sys.mjs | 57 | ||||
-rw-r--r-- | comm/mail/actors/MailLinkChild.jsm | 42 | ||||
-rw-r--r-- | comm/mail/actors/MailLinkParent.jsm | 96 | ||||
-rw-r--r-- | comm/mail/actors/PromptParent.jsm | 180 | ||||
-rw-r--r-- | comm/mail/actors/VCardChild.jsm | 23 | ||||
-rw-r--r-- | comm/mail/actors/VCardParent.jsm | 17 | ||||
-rw-r--r-- | comm/mail/actors/moz.build | 24 |
12 files changed, 779 insertions, 0 deletions
diff --git a/comm/mail/actors/ChatActionChild.sys.mjs b/comm/mail/actors/ChatActionChild.sys.mjs new file mode 100644 index 0000000000..92af66d3df --- /dev/null +++ b/comm/mail/actors/ChatActionChild.sys.mjs @@ -0,0 +1,55 @@ +/* -*- mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ts=2 sw=2 sts=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export class ChatActionChild extends JSWindowActorChild { + constructor() { + super(); + + this.messageActions = null; + } + + receiveMessage(message) { + if (!this.messageActions) { + return; + } + if (message.name === "ChatAction:Run") { + this.messageActions[message.data.index].run(); + } else if (message.name === "ChatAction:Hide") { + this.messageActions = null; + } + } + + async handleEvent(event) { + let node = event.composedTarget; + + // Set the node to containing <video>/<audio>/<embed>/<object> if the node + // is in the videocontrols UA Widget. + if (node.containingShadowRoot?.isUAWidget()) { + const host = node.containingShadowRoot.host; + if ( + this.contentWindow.HTMLMediaElement.isInstance(host) || + this.contentWindow.HTMLEmbedElement.isInstance(host) || + this.contentWindow.HTMLObjectElement.isInstance(host) + ) { + node = host; + } + } + + while (node) { + if (node._originalMsg) { + this.messageActions = node._originalMsg.getActions(); + break; + } + node = node.parentNode; + } + if (!this.messageActions) { + return; + } + this.sendAsyncMessage("ChatAction:Actions", { + actions: this.messageActions.map(action => action.label), + }); + } +} diff --git a/comm/mail/actors/ChatActionParent.sys.mjs b/comm/mail/actors/ChatActionParent.sys.mjs new file mode 100644 index 0000000000..15b67419f5 --- /dev/null +++ b/comm/mail/actors/ChatActionParent.sys.mjs @@ -0,0 +1,32 @@ +/* -*- mode: js; indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ts=2 sw=2 sts=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export class ChatActionParent extends JSWindowActorParent { + receiveMessage(message) { + if (message.name === "ChatAction:Actions") { + let browser = this.manager.rootFrameLoader.ownerElement; + if (browser.contentWindow?.gChatContextMenu) { + browser.contentWindow.gChatContextMenu.initActions( + message.data.actions + ); + return; + } + + // Otherwise, send them to the outer window. + let win = browser.ownerGlobal; + if (win.gChatContextMenu) { + win.gChatContextMenu.initActions(message.data.actions); + return; + } + this.actions = message.data.actions; + } + } + + reportHide() { + this.sendAsyncMessage("ChatAction:Hide"); + this.actions = null; + } +} diff --git a/comm/mail/actors/ContextMenuParent.sys.mjs b/comm/mail/actors/ContextMenuParent.sys.mjs new file mode 100644 index 0000000000..5cf1d5dbe2 --- /dev/null +++ b/comm/mail/actors/ContextMenuParent.sys.mjs @@ -0,0 +1,45 @@ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at http://mozilla.org/MPL/2.0/. */ + +export class ContextMenuParent extends JSWindowActorParent { + receiveMessage(message) { + if (message.name != "contextmenu") { + return; + } + + let browser = this.manager.rootFrameLoader.ownerElement; + let win = browser.ownerGlobal.top; + + // Send events from a message display browser to about:3pane or + // about:message if possible. + let tabmail = win.document.getElementById("tabmail"); + if (tabmail) { + let chromeBrowser = tabmail.currentTabInfo.chromeBrowser; + if ( + chromeBrowser?.contentWindow.openContextMenu(message, browser, this) + ) { + return; + } + } + let messageBrowser = win.document.getElementById("messageBrowser"); + if (messageBrowser?.contentWindow.openContextMenu(message, browser, this)) { + return; + } + + // Otherwise, send them to the outer window. + if ("openContextMenu" in win) { + win.openContextMenu(message, browser, this); + } + } + + hiding() { + try { + this.sendAsyncMessage("ContextMenu:Hiding", {}); + } catch (e) { + // This will throw if the content goes away while the + // context menu is still open. + } + } +} diff --git a/comm/mail/actors/LinkClickHandlerChild.jsm b/comm/mail/actors/LinkClickHandlerChild.jsm new file mode 100644 index 0000000000..8ad42a7a23 --- /dev/null +++ b/comm/mail/actors/LinkClickHandlerChild.jsm @@ -0,0 +1,178 @@ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = [ + "LinkClickHandlerChild", + "StrictLinkClickHandlerChild", +]; + +const { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +const lazy = {}; + +XPCOMUtils.defineLazyServiceGetter( + lazy, + "protocolSvc", + "@mozilla.org/uriloader/external-protocol-service;1", + "nsIExternalProtocolService" +); + +/** + * Extract the href from the link click event. + * We look for HTMLAnchorElement, HTMLAreaElement, HTMLLinkElement, + * HTMLInputElement.form.action, and nested anchor tags. + * If the clicked element was a HTMLInputElement or HTMLButtonElement + * we return the form action. + * + * @returns the url and the text for the link being clicked. + */ +function hRefForClickEvent(aEvent) { + let target = aEvent.target; + + if ( + HTMLImageElement.isInstance(target) && + target.hasAttribute("overflowing") + ) { + // Click on zoomed image. + return [null, null]; + } + + let href = null; + if ( + HTMLAnchorElement.isInstance(target) || + HTMLAreaElement.isInstance(target) || + HTMLLinkElement.isInstance(target) + ) { + if (target.hasAttribute("href") && !target.download) { + href = target.href; + } + } else { + // We may be nested inside of a link node. + let linkNode = aEvent.target; + while (linkNode && !HTMLAnchorElement.isInstance(linkNode)) { + linkNode = linkNode.parentNode; + } + + if (linkNode && !linkNode.download) { + href = linkNode.href; + } + } + return href; +} + +/** + * Listens for click events and, if the click would result in loading a page + * on a different base domain from the current page, cancels the click event, + * redirecting the URI to an external browser, effectively creating a + * single-site browser. + * + * This actor applies to browsers in the "single-site" message manager group. + */ +class LinkClickHandlerChild extends JSWindowActorChild { + handleEvent(event) { + // Don't handle events that: + // a) are in the parent process (handled by onclick), + // b) aren't trusted, + // c) have already been handled or + // d) aren't left-click. + if ( + this.manager.isInProcess || + !event.isTrusted || + event.defaultPrevented || + event.button + ) { + return; + } + + let eventHRef = hRefForClickEvent(event); + if (!eventHRef) { + return; + } + + let pageURI = Services.io.newURI(this.document.location.href); + let eventURI = Services.io.newURI(eventHRef); + + try { + if (pageURI.host == eventURI.host) { + // Avoid using the eTLD service, and this also works for IP addresses. + return; + } + + try { + if ( + Services.eTLD.getBaseDomain(eventURI) == + Services.eTLD.getBaseDomain(pageURI) + ) { + return; + } + } catch (ex) { + if (ex.result != Cr.NS_ERROR_HOST_IS_IP_ADDRESS) { + console.error(ex); + } + } + } catch (ex) { + // The page or link might be from a host-less URL scheme such as about, + // blob, or data. The host is never going to match, carry on. + } + + if ( + !lazy.protocolSvc.isExposedProtocol(eventURI.scheme) || + eventURI.schemeIs("http") || + eventURI.schemeIs("https") + ) { + event.preventDefault(); + this.sendAsyncMessage("openLinkExternally", eventHRef); + } + } +} + +/** + * Listens for click events and, if the click would result in loading a + * different page from the current page, cancels the click event, redirecting + * the URI to an external browser, effectively creating a single-page browser. + * + * This actor applies to browsers in the "single-page" message manager group. + */ +class StrictLinkClickHandlerChild extends JSWindowActorChild { + handleEvent(event) { + // Don't handle events that: + // a) are in the parent process (handled by onclick), + // b) aren't trusted, + // c) have already been handled or + // d) aren't left-click. + if ( + this.manager.isInProcess || + !event.isTrusted || + event.defaultPrevented || + event.button + ) { + return; + } + + let eventHRef = hRefForClickEvent(event); + if (!eventHRef) { + return; + } + + let pageURI = Services.io.newURI(this.document.location.href); + let eventURI = Services.io.newURI(eventHRef); + if (eventURI.specIgnoringRef == pageURI.specIgnoringRef) { + return; + } + + if ( + !lazy.protocolSvc.isExposedProtocol(eventURI.scheme) || + eventURI.schemeIs("http") || + eventURI.schemeIs("https") + ) { + event.preventDefault(); + this.sendAsyncMessage("openLinkExternally", eventHRef); + } + } +} diff --git a/comm/mail/actors/LinkClickHandlerParent.jsm b/comm/mail/actors/LinkClickHandlerParent.jsm new file mode 100644 index 0000000000..5fc0dd2b90 --- /dev/null +++ b/comm/mail/actors/LinkClickHandlerParent.jsm @@ -0,0 +1,30 @@ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = [ + "LinkClickHandlerParent", + "StrictLinkClickHandlerParent", +]; + +const { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +XPCOMUtils.defineLazyScriptGetter( + // eslint-disable-next-line mozilla/reject-global-this + this, + "openLinkExternally", + "chrome://browser/content/utilityOverlay.js" +); + +class LinkClickHandlerParent extends JSWindowActorParent { + receiveMessage({ data }) { + openLinkExternally(data); + } +} + +class StrictLinkClickHandlerParent extends LinkClickHandlerParent {} diff --git a/comm/mail/actors/LinkHandlerParent.sys.mjs b/comm/mail/actors/LinkHandlerParent.sys.mjs new file mode 100644 index 0000000000..269405c4ff --- /dev/null +++ b/comm/mail/actors/LinkHandlerParent.sys.mjs @@ -0,0 +1,57 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export class LinkHandlerParent extends JSWindowActorParent { + receiveMessage(msg) { + let browser = this.browsingContext.top.embedderElement; + if (!browser) { + return; + } + + switch (msg.name) { + case "Link:SetIcon": + this.setIconFromLink(browser, msg.data.iconURL, msg.data.canUseForTab); + break; + } + } + + setIconFromLink(browser, iconURL, canUseForTab) { + let tabmail = browser.ownerDocument.getElementById("tabmail"); + if (!tabmail) { + return; + } + + let tab = tabmail.getTabForBrowser(browser); + if (tab?.mode?.type != "contentTab") { + return; + } + + let iconURI; + try { + iconURI = Services.io.newURI(iconURL); + } catch (ex) { + console.error(ex); + return; + } + if (iconURI.scheme != "data") { + try { + Services.scriptSecurityManager.checkLoadURIWithPrincipal( + browser.contentPrincipal, + iconURI, + Services.scriptSecurityManager.ALLOW_CHROME + ); + } catch (ex) { + return; + } + } + + if (canUseForTab) { + tabmail.setTabFavIcon( + tab, + iconURL, + "chrome://messenger/skin/icons/new/compact/draft.svg" + ); + } + } +} diff --git a/comm/mail/actors/MailLinkChild.jsm b/comm/mail/actors/MailLinkChild.jsm new file mode 100644 index 0000000000..401b869fad --- /dev/null +++ b/comm/mail/actors/MailLinkChild.jsm @@ -0,0 +1,42 @@ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = ["MailLinkChild"]; + +const PROTOCOLS = ["mailto:", "mid:", "news:", "snews:"]; + +class MailLinkChild extends JSWindowActorChild { + handleEvent(event) { + let href = event.target.href; + let location = this.document.location; + if ( + !href || + // Do nothing if not the main button clicked. + event.button > 0 || + // Do nothing if in the compose window. + location.href == "about:blank?compose" + ) { + return; + } + + let url = new URL(href); + let protocol = url.protocol; + if ( + PROTOCOLS.includes(protocol) || + // A link to an attachment, e.g. cid: link. + (["imap:", "mailbox:"].includes(protocol) && + url.searchParams.get("part") && + // Prevent opening new tab for internal pdf link. + (!location.search.includes("part=") || + url.origin != location.origin || + url.pathname != location.pathname)) + ) { + this.sendAsyncMessage(protocol, href); + event.preventDefault(); + } + } +} diff --git a/comm/mail/actors/MailLinkParent.jsm b/comm/mail/actors/MailLinkParent.jsm new file mode 100644 index 0000000000..6c371658f6 --- /dev/null +++ b/comm/mail/actors/MailLinkParent.jsm @@ -0,0 +1,96 @@ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = ["MailLinkParent"]; + +const { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + AttachmentInfo: "resource:///modules/AttachmentInfo.sys.mjs", +}); + +XPCOMUtils.defineLazyModuleGetters(lazy, { + MailServices: "resource:///modules/MailServices.jsm", + MailUtils: "resource:///modules/MailUtils.jsm", +}); + +class MailLinkParent extends JSWindowActorParent { + receiveMessage(value) { + switch (value.name) { + case "imap:": + case "mailbox:": + this._handleMailboxLink(value); + break; + case "mailto:": + this._handleMailToLink(value); + break; + case "mid:": + this._handleMidLink(value); + break; + case "news:": + case "snews:": + this._handleNewsLink(value); + break; + default: + throw Components.Exception( + `Unsupported name=${value.name} url=${value.data}`, + Cr.NS_ERROR_ILLEGAL_VALUE + ); + } + } + + _handleMailboxLink({ data, target }) { + // AttachmentInfo is defined in msgHdrView.js. + let url = new URL(data); + new lazy.AttachmentInfo({ + contentType: "", + url: data, + name: url.searchParams.get("filename"), + uri: "", + isExternalAttachment: false, + }).open(target.browsingContext.topChromeWindow, target.browsingContext.id); + } + + _handleMailToLink({ data, target }) { + let identity = null; + + // If the document with the link is a message, try to get the identity + // from the message and use it when composing. + let documentURI = target.windowContext.documentURI; + if (documentURI instanceof Ci.nsIMsgMessageUrl) { + documentURI.QueryInterface(Ci.nsIMsgMessageUrl); + [identity] = lazy.MailUtils.getIdentityForHeader( + documentURI.messageHeader + ); + } + + lazy.MailServices.compose.OpenComposeWindowWithURI( + undefined, + Services.io.newURI(data), + identity + ); + } + + _handleMidLink({ data }) { + // data is the mid: url. + lazy.MailUtils.openMessageByMessageId(data.slice(4)); + } + + _handleNewsLink({ data }) { + Services.ww.openWindow( + null, + "chrome://messenger/content/messageWindow.xhtml", + "_blank", + "all,chrome,dialog=no,status,toolbar", + Services.io.newURI(data) + ); + } +} diff --git a/comm/mail/actors/PromptParent.jsm b/comm/mail/actors/PromptParent.jsm new file mode 100644 index 0000000000..5aedf5a1b9 --- /dev/null +++ b/comm/mail/actors/PromptParent.jsm @@ -0,0 +1,180 @@ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +var EXPORTED_SYMBOLS = ["PromptParent"]; + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + PromptUtils: "resource://gre/modules/PromptUtils.sys.mjs", +}); + +/** + * @typedef {object} Prompt + * @property {Function} resolver + * The resolve function to be called with the data from the Prompt + * after the user closes it. + * @property {object} tabModalPrompt + * The TabModalPrompt being shown to the user. + */ + +/** + * gBrowserPrompts weakly maps BrowsingContexts to a Map of their currently + * active Prompts. + * + * @type {WeakMap<BrowsingContext, Prompt>} + */ +let gBrowserPrompts = new WeakMap(); + +class PromptParent extends JSWindowActorParent { + didDestroy() { + // In the event that the subframe or tab crashed, make sure that + // we close any active Prompts. + this.forceClosePrompts(); + } + + /** + * Registers a new Prompt to be tracked for a particular BrowsingContext. + * We need to track a Prompt so that we can, for example, force-close the + * TabModalPrompt if the originating subframe or tab unloads or crashes. + * + * @param {object} tabModalPrompt + * The TabModalPrompt that will be shown to the user. + * @param {string} id + * A unique ID to differentiate multiple Prompts coming from the same + * BrowsingContext. + * @returns {Promise} + * @resolves {object} + * Resolves with the arguments returned from the TabModalPrompt when it + * is dismissed. + */ + registerPrompt(tabModalPrompt, id) { + let prompts = gBrowserPrompts.get(this.browsingContext); + if (!prompts) { + prompts = new Map(); + gBrowserPrompts.set(this.browsingContext, prompts); + } + + let promise = new Promise(resolve => { + prompts.set(id, { + tabModalPrompt, + resolver: resolve, + }); + }); + + return promise; + } + + /** + * Removes a Prompt for a BrowsingContext with a particular ID from the registry. + * This needs to be done to avoid leaking <xul:browser>'s. + * + * @param {string} id + * A unique ID to differentiate multiple Prompts coming from the same + * BrowsingContext. + */ + unregisterPrompt(id) { + let prompts = gBrowserPrompts.get(this.browsingContext); + if (prompts) { + prompts.delete(id); + } + } + + /** + * Programmatically closes all Prompts for the current BrowsingContext. + */ + forceClosePrompts() { + let prompts = gBrowserPrompts.get(this.browsingContext) || []; + + for (let [, prompt] of prompts) { + prompt.tabModalPrompt && prompt.tabModalPrompt.abortPrompt(); + } + } + + receiveMessage(message) { + let args = message.data; + + switch (message.name) { + case "Prompt:Open": { + return this.openWindowPrompt(args); + } + } + + return undefined; + } + + /** + * Opens a window prompt for a BrowsingContext, and puts the associated + * browser in the modal state until the prompt is closed. + * + * @param {object} args + * The arguments passed up from the BrowsingContext to be passed + * directly to the modal window. + * @returns {Promise} + * Resolves when the window prompt is dismissed. + * @resolves {object} + * The arguments returned from the window prompt. + */ + async openWindowPrompt(args) { + const COMMON_DIALOG = "chrome://global/content/commonDialog.xhtml"; + const SELECT_DIALOG = "chrome://global/content/selectDialog.xhtml"; + let uri = args.promptType == "select" ? SELECT_DIALOG : COMMON_DIALOG; + + let browsingContext = this.browsingContext.top; + + let browser = browsingContext.embedderElement; + let win; + + // If we are a chrome actor we can use the associated chrome win. + if (!browsingContext.isContent && browsingContext.window) { + win = browsingContext.window; + } else { + win = browser?.ownerGlobal; + if (!win?.isChromeWindow) { + win = browsingContext.topChromeWindow; + } + } + + // There's a requirement for prompts to be blocked if a window is + // passed and that window is hidden (eg, auth prompts are suppressed if the + // passed window is the hidden window). + // See bug 875157 comment 30 for more.. + if (win?.winUtils && !win.winUtils.isParentWindowMainWidgetVisible) { + throw new Error("Cannot call openModalWindow on a hidden window"); + } + + try { + if (browser) { + // The compose editor does not support enter/leaveModalState. + browser.enterModalState?.(); + lazy.PromptUtils.fireDialogEvent( + win, + "DOMWillOpenModalDialog", + browser + ); + } + + let bag = lazy.PromptUtils.objectToPropBag(args); + + Services.ww.openWindow( + win, + uri, + "_blank", + "centerscreen,chrome,modal,titlebar", + bag + ); + + lazy.PromptUtils.propBagToObject(bag, args); + } finally { + if (browser) { + browser.leaveModalState?.(); + lazy.PromptUtils.fireDialogEvent(win, "DOMModalDialogClosed", browser); + } + } + return args; + } +} diff --git a/comm/mail/actors/VCardChild.jsm b/comm/mail/actors/VCardChild.jsm new file mode 100644 index 0000000000..db43b6c145 --- /dev/null +++ b/comm/mail/actors/VCardChild.jsm @@ -0,0 +1,23 @@ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = ["VCardChild"]; + +class VCardChild extends JSWindowActorChild { + handleEvent(event) { + // This link comes from VCardMimeConverter.convertToHTML in VCardUtils.jsm. + if (event.target.classList.contains("moz-vcard-badge")) { + if (event.button == 0) { + // The href is a data:text/vcard URL. + let href = event.target.href; + href = href.substring(href.indexOf(",") + 1); + this.sendAsyncMessage("addVCard", href); + } + event.preventDefault(); + } + } +} diff --git a/comm/mail/actors/VCardParent.jsm b/comm/mail/actors/VCardParent.jsm new file mode 100644 index 0000000000..71454a4a93 --- /dev/null +++ b/comm/mail/actors/VCardParent.jsm @@ -0,0 +1,17 @@ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = ["VCardParent"]; + +class VCardParent extends JSWindowActorParent { + receiveMessage({ data, target }) { + target.browsingContext.topChromeWindow.toAddressBook({ + action: "create", + vCard: decodeURIComponent(data), + }); + } +} diff --git a/comm/mail/actors/moz.build b/comm/mail/actors/moz.build new file mode 100644 index 0000000000..da87ba7f0b --- /dev/null +++ b/comm/mail/actors/moz.build @@ -0,0 +1,24 @@ +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at http://mozilla.org/MPL/2.0/. + +EXTRA_JS_MODULES += [ + "../../../browser/modules/FaviconLoader.jsm", +] + +FINAL_TARGET_FILES.actors += [ + "../../../browser/actors/ContextMenuChild.sys.mjs", + "../../../browser/actors/LinkHandlerChild.sys.mjs", + "ChatActionChild.sys.mjs", + "ChatActionParent.sys.mjs", + "ContextMenuParent.sys.mjs", + "LinkClickHandlerChild.jsm", + "LinkClickHandlerParent.jsm", + "LinkHandlerParent.sys.mjs", + "MailLinkChild.jsm", + "MailLinkParent.jsm", + "PromptParent.jsm", + "VCardChild.jsm", + "VCardParent.jsm", +] |