Bug 1455471 - Backed out changeset 95b0887a1895 for test failures. a=jorgk DONTBUILD
authorJorg K <jorgk@jorgk.com>
Mon, 25 Jun 2018 13:16:44 +0200
changeset 32259 7f6264949d3fc70bf96f562fb1561e502b419b58
parent 32258 7c455c3e60260772e74cb1f8fb40fc79b4fad5b6
child 32260 226cb0a4c0698b4442baf32d9e965beadcb01f78
push id385
push userclokep@gmail.com
push dateTue, 04 Sep 2018 23:26:14 +0000
reviewersjorgk
bugs1455471
Bug 1455471 - Backed out changeset 95b0887a1895 for test failures. a=jorgk DONTBUILD
.eslintignore
mail/base/content/messenger.xul
mail/base/content/msgMail3PaneWindow.js
mail/base/content/specialTabs.js
mail/base/content/tabmail.xml
mail/components/extensions/child/ext-mail.js
mail/components/extensions/child/ext-tabs.js
mail/components/extensions/ext-mail.json
mail/components/extensions/extensions-mail.manifest
mail/components/extensions/jar.mn
mail/components/extensions/moz.build
mail/components/extensions/parent/ext-mail.js
mail/components/extensions/parent/ext-tabs.js
mail/components/extensions/parent/ext-windows.js
mail/components/extensions/schemas/LICENSE
mail/components/extensions/schemas/tabs.json
mail/components/extensions/schemas/windows.json
mail/components/moz.build
mail/installer/package-manifest.in
--- a/.eslintignore
+++ b/.eslintignore
@@ -19,34 +19,20 @@ testing/**
 # We ignore all these directories by default, until we get them enabled.
 # If you are enabling a directory, please add directory specific exclusions
 # below.
 build/**
 chat/**
 editor/**
 im/**
 ldap/**
+mail/**
 mailnews/**
 suite/**
 
-# mail exclusions
-mail/app/**
-mail/base/**
-mail/branding/**
-mail/config/**
-mail/extensions/**
-mail/installer/**
-mail/locales/**
-mail/test/**
-mail/themes/**
-
-# mail/components exclusions
-mail/components/*
-!mail/components/extensions
-
 # calendar/ exclusions
 
 # prefs files
 calendar/lightning/content/lightning.js
 calendar/locales/en-US/lightning-l10n.js
 
 # third party library
 calendar/base/modules/ical.js
--- a/mail/base/content/messenger.xul
+++ b/mail/base/content/messenger.xul
@@ -330,17 +330,17 @@
     <hbox id="titlebar-fullscreen-button"/>
 #endif
   </hbox>
 </vbox>
 
   <!-- navigation-toolbox with main menubar and tabs toolbar -->
 #include mainNavigationToolbox.inc
 
-    <toolbar id="tabs-toolbar" class="chromeclass-toolbar">
+    <toolbar id="tabs-toolbar">
       <!-- class tabmail-tabs is unused and only maintained for add-ons. -->
       <tabs flex="1"
             id="tabmail-tabs"
             align="end"
             setfocus="false"
             onclick="document.getElementById('tabmail').onTabClick(event);"
             class="tabmail-tabs"
             tooltip="tabmail-tabs-tooltip"
--- a/mail/base/content/msgMail3PaneWindow.js
+++ b/mail/base/content/msgMail3PaneWindow.js
@@ -717,20 +717,17 @@ function loadExtraTabs()
 
   if (!("arguments" in window) || window.arguments.length < 2)
     return;
 
   let tab = window.arguments[1];
   if ((!tab) || (typeof tab != "object"))
     return;
 
-  if ("wrappedJSObject" in tab)
-    tab = tab.wrappedJSObject;
-
-  let tabmail = document.getElementById("tabmail");
+  let tabmail =  document.getElementById("tabmail");
 
   // we got no action, so suppose its "legacy" code
   if (!("action" in tab)) {
 
     if ("tabType" in tab)
       tabmail.openTab(tab.tabType, tab.tabParams);
 
     return;
@@ -748,19 +745,20 @@ function loadExtraTabs()
     // we currently do not support opening in background or opening a
     // special position. So select the last tab opened.
     tabmail.switchToTab(tabmail.tabInfo[tabmail.tabInfo.length-1])
 
     return;
   }
 
   if (tab.action == "open") {
+
     for (let i = 0; i < tab.tabs.length; i++)
-      if("tabType" in tab.tabs[i])
-        tabmail.openTab(tab.tabs[i].tabType,tab.tabs[i].tabParams);
+      if("tabType" in tabs.tab[i])
+        tabmail.openTab(tabs.tab[i].tabType,tabs.tab[i].tabParams);
 
     return;
   }
 
 }
 
 /**
  * Loads the given message header at window open. Exactly one out of this and
@@ -1791,22 +1789,16 @@ var TabsInTitlebar = {
 
   update() {
     if (!this._initialized || window.fullScreen) {
       return;
     }
 
     let allowed = this.systemSupported &&
                   (Object.keys(this._disallowed)).length == 0;
-
-    if (document.documentElement.getAttribute("chromehidden").includes("toolbar")) {
-      // Don't draw in titlebar in case of a popup window
-      allowed = false;
-    }
-
     if (allowed) {
       document.documentElement.setAttribute("tabsintitlebar", "true");
       if (AppConstants.platform == "macosx") {
         document.documentElement.setAttribute("chromemargin", "0,-1,-1,-1");
         document.documentElement.removeAttribute("drawtitle");
       } else {
         document.documentElement.setAttribute("chromemargin", "0,2,2,2");
       }
--- a/mail/base/content/specialTabs.js
+++ b/mail/base/content/specialTabs.js
@@ -291,31 +291,28 @@ var contentTabBaseType = {
 
       aDocument.getElementById("category-box")
                .insertBefore(hbox, aDocument.getElementById("categories"));
     },
 
     // about:preferences
     null],
 
-  shouldSwitchTo: function onSwitchTo({contentPage: aContentPage, duplicate: aDuplicate}) {
-    if (aDuplicate) {
-      return -1;
-    }
-
+  shouldSwitchTo: function onSwitchTo({contentPage: aContentPage}) {
     let tabmail = document.getElementById("tabmail");
     let tabInfo = tabmail.tabInfo;
 
     // Remove any anchors - especially for the about: pages, we just want
     // to re-use the same tab.
     let regEx = new RegExp("#.*");
 
     let contentUrl = aContentPage.replace(regEx, "");
 
-    for (let selectedIndex = 0; selectedIndex < tabInfo.length; ++selectedIndex) {
+    for (let selectedIndex = 0; selectedIndex < tabInfo.length;
+         ++selectedIndex) {
       if (tabInfo[selectedIndex].mode.name == this.name &&
           tabInfo[selectedIndex].browser.currentURI.spec
                                 .replace(regEx, "") == contentUrl) {
         // Ensure we go to the correct location on the page.
         tabInfo[selectedIndex].browser
                               .setAttribute("src", aContentPage);
         return selectedIndex;
       }
@@ -817,19 +814,18 @@ var specialTabs = {
       return {
         tabURI: aTab.browser.currentURI.spec,
         clickHandler: onClick ? onClick : null
       };
     },
     restoreTab: function onRestoreTab(aTabmail, aPersistedState) {
       aTabmail.openTab("contentTab", { contentPage: aPersistedState.tabURI,
                                        clickHandler: aPersistedState.clickHandler,
-                                       duplicate: aPersistedState.duplicate,
                                        background: true } );
-    }
+    },
   },
 
   /**
    * Split a version number into a triple (major, minor, extension)
    * For example, 7.0.1 => [7, 0, 1]
    *             10.1a3 => [10, 1, a3]
    *             10.0 => [10, 0, ""]
    * This could be a static function, but no current reason for it to
--- a/mail/base/content/tabmail.xml
+++ b/mail/base/content/tabmail.xml
@@ -269,17 +269,17 @@
     </resources>
     <content>
       <xul:tabbox anonid="tabbox" class="tabmail-tabbox" flex="1" eventnode="document">
         <!-- Remember, user of this binding, you need to provide tabpanels!  -->
         <children includes="tabpanels"/>
       </xul:tabbox>
     </content>
 
-    <implementation implements="nsIController, nsIWebProgressListener, nsIWebProgressListener2">
+    <implementation implements="nsIController">
       <constructor>
         window.controllers.insertControllerAt(0, this);
         this._restoringTabState = null;
         ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
       </constructor>
       <destructor>
         window.controllers.removeController(this);
       </destructor>
@@ -314,19 +314,16 @@
         new Array()
       </field>
       <field name="recentlyClosedTabs" readonly="true">
         new Array();
       </field>
       <field name="mLastTabOpener">
         null
       </field>
-      <field name="mTabsProgressListeners">
-        new Set();
-      </field>
       <method name="createTooltip">
         <parameter name="event"/>
         <body><![CDATA[
           event.stopPropagation();
           var tab = document.tooltipNode;
           if (tab.localName != "tab" || this.tabContainer.draggedTab) {
             event.preventDefault();
             return;
@@ -501,17 +498,17 @@
             }
           }
 
           if (!background)
             // we need to save the state before it gets corrupted
             this.saveCurrentTabState();
 
           let tab = {mode: tabMode, busy: false, canClose: true,
-                     thinking: false, beforeTabOpen: true, _ext: {}};
+                     thinking: false, _ext: {}};
           tabMode.tabs.push(tab);
 
           var t = document.createElementNS(
             "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
             "tab");
           tab.tabNode = t;
           t.maxWidth = this.tabContainer.mTabMaxWidth;
           t.minWidth = this.tabContainer.mTabMinWidth;
@@ -599,32 +596,16 @@
           // for styling purposes, apply the type to the tab...
           t.setAttribute('type', tab.mode.type);
 
           if (!background)
             // Update the toolbar status - we don't need to do menus as they
             // do themselves when we open them.
             UpdateMailToolbar("tabmail");
 
-          let moving = restoreState ? restoreState.moving : null;
-
-          // Dispatch tab opening event
-          let evt = new CustomEvent("TabOpen", { bubbles: true, detail: { tabInfo: tab, moving } });
-          t.dispatchEvent(evt);
-          delete tab.beforeTabOpen;
-
-          // Register browser progress listeners
-          let browser = this.getBrowserForTab(tab);
-          if (browser) {
-            // It would probably be better to have the tabs register this listener, since the
-            // browser can change. This wasn't trivial to do while implementing basic WebExtension
-            // support, so let's assume one browser only for now.
-            browser.webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
-          }
-
           return tab;
         } catch (e) {
           logException(e);
           return null;
         }
         ]]></body>
       </method>
       <method name="selectTabByMode">
@@ -730,22 +711,16 @@
             // whether its tabs can be closed or not. For instance, contentTabs
             // and chromeTabs run onbeforeunload event handlers that may
             // exercise their right to prompt the user for confirmation before
             // closing.
             let tryCloseFunc = tab.mode.tryCloseTab || tab.mode.tabType.tryCloseTab;
             if (tryCloseFunc && !tryCloseFunc.call(tab.mode.tabType, tab))
               return;
 
-            let evt = new CustomEvent("TabClose", {
-              bubbles: true,
-              detail: { tabInfo: tab, moving: tab.moving }
-            });
-            tabNode.dispatchEvent(evt);
-
             for (let tabMonitor of this.tabMonitors) {
               if ("onTabClosing" in tabMonitor)
                 tabMonitor.onTabClosing(tab);
             }
 
             if (!aNoUndo) {
               // Allow user to undo accidentally closed tabs
               let session = this.persistTab(tab);
@@ -822,18 +797,16 @@
               if ((tab != thisTab) && tab.canClose)
                 this.closeTab(tab, aNoUndo);
             }
           ]]>
         </body>
       </method>
       <method name="replaceTabWithWindow">
         <parameter name="aTab"/>
-        <parameter name="aTargetWindow"/>
-        <parameter name="aTargetPosition"/>
         <body>
           <![CDATA[
             if (this.tabInfo.length <= 1)
               return null;
 
             let tab = this._getTabContextForTabbyThing(aTab, false)[1];
 
             if (!tab.canClose)
@@ -843,103 +816,82 @@
             tab = this.persistTab(tab);
             if (!tab)
               return null;
 
             // Converting to JSON and back again creates clean javascript
             // object with absolutely no references to our current window.
             tab = JSON.parse(JSON.stringify(tab));
 
-            // Set up an identifier for the move, consumers may want to correlate TabClose and
-            // TabOpen events.
-            let moveSession = Cc["@mozilla.org/uuid-generator;1"]
-              .getService(Ci.nsIUUIDGenerator)
-              .generateUUID().toString();
-
-            tab.moving = moveSession;
-            aTab.moving = moveSession;
-
             this.closeTab(aTab,true);
 
-            if (aTargetWindow && aTargetWindow !== "popup") {
-              let targetTabmail = aTargetWindow.document.getElementById("tabmail");
-              targetTabmail.restoreTab(tab);
-
-              if (aTargetPosition) {
-                let droppedTab = targetTabmail.tabInfo[targetTabmail.tabInfo.length - 1];
-                targetTabmail.moveTabTo(droppedTab, aTargetPosition);
-              }
-              return aTargetWindow;
-            } else {
-              let features = ["chrome"];
-              if (aTargetWindow === "popup") {
-                features.push("dialog", "resizable", "minimizable", "centerscreen", "titlebar", "close");
-              } else {
-                features.push("dialog=no", "all", "status", "toolbar");
-              }
-
-              return window.openDialog("chrome://messenger/content/", "_blank",
-                 features.join(","), null,
-                 { action : "restore", tabs: [tab] } ).focus();
-            }
+            return window.openDialog("chrome://messenger/content/", "_blank",
+               "chrome,dialog=no,all", null,
+               { action : "restore", tabs: [tab] } ).focus();
           ]]>
         </body>
       </method>
       <method name="moveTabTo">
-        <parameter name="aTabIndexNodeOrInfo"/>
+        <parameter name="aTab"/>
         <parameter name="aIndex"/>
         <body><![CDATA[
-          let [oldIdx, tab, tabNode] =
-            this._getTabContextForTabbyThing(aTabIndexNodeOrInfo, false);
-
-          if (!tab || !tabNode || tabNode.tagName != "tab" || oldIdx < 0 || oldIdx == aIndex) {
+
+          if ((!aTab) || (aTab.tagName != "tab"))
+            return -1;
+
+          let oldIdx = this.tabContainer.getIndexOfItem(aTab);
+          if (oldIdx < 0)
             return -1;
-          }
-
-          // remove the entries from tabInfo, tabMode and the tabContainer
+
+          if (oldIdx == aIndex)
+            return -1;
+
+          // Cache the old tabInfo
+          let tab = this.tabInfo[oldIdx]
+
+          if (!tab)
+            return -1;
+
+          // remove the entries form tabInfo, tabMode and the tabContainer
           this.tabInfo.splice(oldIdx, 1);
           tab.mode.tabs.splice(tab.mode.tabs.indexOf(tab), 1);
-          tabNode.remove();
+          aTab.remove();
+
 
           // as we removed items, we might need to update indices
-          if (oldIdx < aIndex) {
-            aIndex--;
-          }
+          if (oldIdx < aIndex)
+            aIndex --;
 
           // Read it into tabInfo and the tabContainer
           this.tabInfo.splice(aIndex, 0, tab);
-          this.tabContainer.insertBefore(tabNode, this.tabContainer.childNodes[aIndex]);
+          this.tabContainer.insertBefore(aTab, this.tabContainer.childNodes[aIndex]);
 
           // Now it's getting a bit ugly, as tabModes stores redundant
           // information we need to get it in sync with tabInfo.
           //
           // As tabModes.tabs is a subset of tabInfo, every tab can be mapped
           // to a tabInfo index. So we check for each tab in tabModes if it is
           // directly in front of our moved tab. We do this by looking up the
           // index in tabInfo and compare it with the moved tab's index. If we
           // found our tab, we insert the moved tab directly behind into tabModes
 
           // In case find no tab we simply append it
-          let modeIdx = tab.mode.tabs.length + 1;
+          let modeIdx = tab.mode.tabs.length+1;
 
           for (let i = 0; i < tab.mode.tabs.length; i++) {
+
             if (this.tabInfo.indexOf(tab.mode.tabs[i]) < aIndex)
               continue;
 
             modeIdx = i;
             break;
           }
 
           tab.mode.tabs.splice(modeIdx, 0, tab);
 
-          let evt = new CustomEvent("TabMove", {
-            bubbles: true, view: window, detail: { idx: oldIdx, tabInfo: tab }
-          });
-          tabNode.dispatchEvent(evt);
-
           return aIndex;
          ]]>
          </body>
        </method>
        <method name="persistTab">
          <parameter name="tab"/>
          <body><![CDATA[
            /* Returns null in case persist fails */
@@ -1099,51 +1051,43 @@
 
               let tabCloseFunc = tab.mode.closeTab || tab.mode.tabType.closeTab;
               tabCloseFunc.call(tab.mode.tabType, tab);
             }
           ]]>
         </body>
       </method>
 
-      <property name="selectedTab">
+      <property name="selectedTab" readonly="true">
         <getter><![CDATA[
           if (!this.currentTabInfo)
             this.currentTabInfo = this.tabInfo[0];
 
           return this.currentTabInfo;
         ]]></getter>
-        <setter><![CDATA[
-          this.switchToTab(val);
-        ]]></setter>
       </property>
 
       <!-- getBrowserForSelectedTab is required as some toolkit functions
            require a getBrowser() function. -->
       <method name="getBrowserForSelectedTab">
         <body><![CDATA[
           if (!this.currentTabInfo)
             this.currentTabInfo = this.tabInfo[0];
 
           let tab = this.currentTabInfo;
           if (!tab)
             return null;
 
-          return this.getBrowserForTab(tab);
+          let browserFunc = tab.mode.getBrowser || tab.mode.tabType.getBrowser;
+          if (browserFunc)
+            return browserFunc.call(tab.mode.tabType, tab);
+
+          return null;
         ]]></body>
       </method>
-
-      <method name="getBrowserForTab">
-        <parameter name="aTab"/>
-        <body><![CDATA[
-          let browserFunc = aTab ? aTab.mode.getBrowser || aTab.mode.tabType.getBrowser : null;
-          return browserFunc ? browserFunc.call(aTab.mode.tabType, aTab) : null;
-        ]]></body>
-      </method>
-
       <!-- getBrowserForDocument is used to find the browser for a specific
            document that's been loaded -->
       <method name="getBrowserForDocument">
         <parameter name="aDocument"/>
         <body><![CDATA[
           for (let i = 0; i < this.tabInfo.length; ++i) {
             let browserFunc = this.tabInfo[i].mode.getBrowser ||
                               this.tabInfo[i].mode.tabType.getBrowser;
@@ -1172,27 +1116,16 @@
               if (possBrowser &&
                   possBrowser.contentDocument.documentElement.id == aDocumentId)
                 return this.tabInfo[i];
             }
           }
           return null;
         ]]></body>
       </method>
-      <method name="getTabForBrowser">
-        <parameter name="aBrowser"/>
-        <body><![CDATA[
-          for (let tabInfo of this.tabInfo) {
-            if (this.getBrowserForTab(tabInfo) == aBrowser) {
-              return tabInfo;
-            }
-          }
-          return null;
-        ]]></body>
-      </method>
       <method name="removeCurrentTab">
         <body><![CDATA[
           this.removeTabByNode(
             this.tabContainer.childNodes[this.tabContainer.selectedIndex]);
         ]]></body>
       </method>
       <method name="switchToTab">
         <parameter name="aTabIndexNodeOrInfo"/>
@@ -1247,20 +1180,16 @@
 
               // Update the toolbar status - we don't need to do menus as they
               // do themselves when we open them.
               UpdateMailToolbar("tabmail");
 
               // We switched tabs, so we don't need to know the last tab
               // opener anymore.
               this.mLastTabOpener = null;
-
-              let evt = new CustomEvent("TabSelect", { bubbles: true, detail: { tabInfo: tab } });
-              this.tabContainer.selectedItem.dispatchEvent(evt);
-
             }
           ]]>
         </body>
       </method>
       <method name="saveCurrentTabState">
         <body>
           <![CDATA[
             if (!this.currentTabInfo)
@@ -1293,50 +1222,34 @@
             let [iTab, tab, tabNode] =
               this._getTabContextForTabbyThing(aTabNodeOrInfo, true);
 
             if (tab)
             {
               let tabNode =
                 this.tabContainer.childNodes[iTab];
 
-              let defaultTabTitle = document.documentElement.getAttribute("defaultTabTitle");
-              let oldLabel = tabNode.getAttribute("label");
-              let newLabel = aTabNodeOrInfo ? tab.title : defaultTabTitle;
-
-              if (oldLabel == newLabel) {
-                return;
-              }
-
               let titleChangeFunc = tab.mode.onTitleChanged ||
                                     tab.mode.tabType.onTitleChanged;
               if (titleChangeFunc)
                 titleChangeFunc.call(tab.mode.tabType, tab, tabNode);
 
               for (let tabMonitor of this.tabMonitors) {
                 tabMonitor.onTabTitleChanged(tab);
               }
 
               // If the displayed tab is the one at the moment of creation
               // (aTabNodeOrInfo is null), set the default title as its title.
-              tabNode.setAttribute("label", newLabel);
+              tabNode.setAttribute("label", aTabNodeOrInfo ?
+                                            tab.title :
+                                            document.documentElement.getAttribute("defaultTabTitle"));
 
               // Update the window title if we're the displayed tab.
               if (iTab == this.tabContainer.selectedIndex)
                 this.setDocumentTitle(tab);
-
-              // Notify tab title change
-              if (!tab.beforeTabOpen) {
-                let evt = new CustomEvent("TabAttrModified", {
-                  bubbles: true,
-                  cancelable: false,
-                  detail: { changed: ["label"], tabInfo: tab }
-                });
-                tabNode.dispatchEvent(evt);
-              }
             }
           ]]>
         </body>
       </method>
       <!--
         - Sets the tab icon to the specified url, or removes the icon if no
         - url is specified. Note that this may override css provided images.
         -->
@@ -1345,26 +1258,16 @@
         <parameter name="aIcon"/>
         <body>
           <![CDATA[
             let [iTab, tab, tabNode] =
               this._getTabContextForTabbyThing(aTabNodeOrInfo, true);
 
             if (tab) {
               let tabNode = this.tabContainer.childNodes[iTab];
-              let oldIcon = tabNode.getAttribute("image");
-
-              if (oldIcon != aIcon && !tab.beforeTabOpen) {
-                let evt = new CustomEvent("TabAttrModified", {
-                  bubbles: true,
-                  cancelable: false,
-                  detail: { changed: ["image"], tabInfo: tab }
-                });
-                tabNode.dispatchEvent(evt);
-              }
 
               if (aIcon)
                 tabNode.setAttribute("image", aIcon);
               else
                 tabNode.removeAttribute("image");
             }
           ]]>
         </body>
@@ -1617,137 +1520,16 @@
               docTitle += docElement.getAttribute("titlemenuseparator") +
                           docElement.getAttribute("titlemodifier");
             }
 
             document.title = docTitle;
           ]]>
         </body>
       </method>
-      <method name="addTabsProgressListener">
-        <parameter name="aListener"/>
-        <body>
-          <![CDATA[
-            this.mTabsProgressListeners.add(aListener);
-           ]]>
-        </body>
-      </method>
-      <method name="removeTabsProgressListener">
-        <parameter name="aListener"/>
-        <body>
-          <![CDATA[
-            this.mTabsProgressListeners.delete(aListener);
-           ]]>
-        </body>
-      </method>
-      <method name="_callTabListeners">
-        <parameter name="aMethod"/>
-        <parameter name="aArgs"/>
-        <body>
-          <![CDATA[
-            for (let listener of  this.mTabsProgressListeners.values()) {
-              if (aMethod in listener) {
-                try {
-                  listener[aMethod](...aArgs);
-                } catch (e) {
-                  Cu.reportError(e);
-                }
-              }
-            }
-           ]]>
-        </body>
-      </method>
-      <method name="onProgressChange">
-        <parameter name="aWebProgress"/>
-        <parameter name="aRequest"/>
-        <parameter name="aCurSelf"/>
-        <parameter name="aMaxSelf"/>
-        <parameter name="aCurTotal"/>
-        <parameter name="aMaxTotal"/>
-        <body><![CDATA[
-          let browser = aWebProgress.QueryInterface(Ci.nsIDocShellTreeItem)
-                                    .sameTypeRootTreeItem
-                                    .chromeEventHandler;
-          this._callTabListeners("onProgressChange", [browser, ...arguments]);
-        ]]></body>
-      </method>
-      <method name="onProgressChange64">
-        <parameter name="aWebProgress"/>
-        <parameter name="aRequest"/>
-        <parameter name="aCurSelf"/>
-        <parameter name="aMaxSelf"/>
-        <parameter name="aCurTotal"/>
-        <parameter name="aMaxTotal"/>
-        <body><![CDATA[
-          let browser = aWebProgress.QueryInterface(Ci.nsIDocShellTreeItem)
-                                    .sameTypeRootTreeItem
-                                    .chromeEventHandler;
-          this._callTabListeners("onProgressChange64", [browser, ...arguments]);
-        ]]></body>
-      </method>
-      <method name="onLocationChange">
-        <parameter name="aWebProgress"/>
-        <parameter name="aRequest"/>
-        <parameter name="aLocationURI"/>
-        <parameter name="aFlags"/>
-        <body><![CDATA[
-          let browser = aWebProgress.QueryInterface(Ci.nsIDocShellTreeItem)
-                                    .sameTypeRootTreeItem
-                                    .chromeEventHandler;
-          this._callTabListeners("onLocationChange", [browser, ...arguments]);
-        ]]></body>
-      </method>
-      <method name="onStateChange">
-        <parameter name="aWebProgress"/>
-        <parameter name="aRequest"/>
-        <parameter name="aStateFlags"/>
-        <parameter name="aStatus"/>
-        <body><![CDATA[
-          let browser = aWebProgress.QueryInterface(Ci.nsIDocShellTreeItem)
-                                    .sameTypeRootTreeItem
-                                    .chromeEventHandler;
-          this._callTabListeners("onStateChange", [browser, ...arguments]);
-        ]]></body>
-      </method>
-      <method name="onStatusChange">
-        <parameter name="aWebProgress"/>
-        <parameter name="aRequest"/>
-        <parameter name="aStatus"/>
-        <parameter name="aMessage"/>
-        <body><![CDATA[
-          let browser = aWebProgress.QueryInterface(Ci.nsIDocShellTreeItem)
-                                    .sameTypeRootTreeItem
-                                    .chromeEventHandler;
-          this._callTabListeners("onStatusChange", [browser, ...arguments]);
-        ]]></body>
-      </method>
-      <method name="onSecurityChange">
-        <parameter name="aWebProgress"/>
-        <parameter name="aRequest"/>
-        <parameter name="aState"/>
-        <body><![CDATA[
-          let browser = aWebProgress.QueryInterface(Ci.nsIDocShellTreeItem)
-                                    .sameTypeRootTreeItem
-                                    .chromeEventHandler;
-          this._callTabListeners("onSecurityChange", [browser, ...arguments]);
-        ]]></body>
-      </method>
-      <method name="onRefreshAttempted">
-        <parameter name="aWebProgress"/>
-        <parameter name="aURI"/>
-        <parameter name="aDelay"/>
-        <parameter name="aSameURI"/>
-        <body><![CDATA[
-          let browser = aWebProgress.QueryInterface(Ci.nsIDocShellTreeItem)
-                                    .sameTypeRootTreeItem
-                                    .chromeEventHandler;
-          this._callTabListeners("onRefreshAttempted", [browser, ...arguments]);
-        ]]></body>
-      </method>
-
     </implementation>
   </binding>
 
   <binding id="tabmail-tab" display="xul:box"
            extends="chrome://global/content/bindings/tabbox.xml#tab">
     <content closetabtext="&closeTab.label;" context="tabContextMenu">
       <xul:stack class="tab-stack" flex="1">
         <xul:vbox xbl:inherits="pinned,selected,titlechanged"
deleted file mode 100644
--- a/mail/components/extensions/child/ext-mail.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/* 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";
-
-extensions.registerModules({
-  tabs: {
-    url: "chrome://messenger/content/child/ext-tabs.js",
-    scopes: ["addon_child"],
-    paths: [
-      ["tabs"],
-    ],
-  }
-});
deleted file mode 100644
--- a/mail/components/extensions/child/ext-tabs.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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";
-
-this.tabs = class extends ExtensionAPI {
-  getAPI(context) {
-    return {
-      tabs: {
-        connect: function(tabId, connectInfo) {
-          let name = "";
-          if (connectInfo && connectInfo.name !== null) {
-            name = connectInfo.name;
-          }
-          let recipient = {
-            extensionId: context.extension.id,
-            tabId,
-          };
-          if (connectInfo && connectInfo.frameId !== null) {
-            recipient.frameId = connectInfo.frameId;
-          }
-          return context.messenger.connect(context.messageManager, name, recipient);
-        },
-
-        sendMessage: function(tabId, message, options, responseCallback) {
-          let recipient = {
-            extensionId: context.extension.id,
-            tabId: tabId,
-          };
-          if (options && options.frameId !== null) {
-            recipient.frameId = options.frameId;
-          }
-          return context.messenger.sendMessage(context.messageManager, message, recipient, responseCallback);
-        },
-      },
-    };
-  }
-};
deleted file mode 100644
--- a/mail/components/extensions/ext-mail.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "tabs": {
-    "url": "chrome://messenger/content/parent/ext-tabs.js",
-    "schema": "chrome://messenger/content/schemas/tabs.json",
-    "scopes": ["addon_parent"],
-    "paths": [
-      ["tabs"]
-    ]
-  },
-  "windows": {
-    "url": "chrome://messenger/content/parent/ext-windows.js",
-    "schema": "chrome://messenger/content/schemas/windows.json",
-    "scopes": ["addon_parent"],
-    "paths": [
-      ["windows"]
-    ]
-  }
-}
deleted file mode 100644
--- a/mail/components/extensions/extensions-mail.manifest
+++ /dev/null
@@ -1,4 +0,0 @@
-category webextension-modules mail chrome://messenger/content/ext-mail.json
-
-category webextension-scripts c-mail chrome://messenger/content/parent/ext-mail.js
-category webextension-scripts-addon mail chrome://messenger/content/child/ext-mail.js
deleted file mode 100644
--- a/mail/components/extensions/jar.mn
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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/.
-
-messenger.jar:
-    content/messenger/ext-mail.json                (ext-mail.json)
-
-    content/messenger/parent/ext-mail.js           (parent/ext-mail.js)
-    content/messenger/parent/ext-tabs.js           (parent/ext-tabs.js)
-    content/messenger/parent/ext-windows.js        (parent/ext-windows.js)
-
-    content/messenger/child/ext-tabs.js            (child/ext-tabs.js)
-    content/messenger/child/ext-mail.js            (child/ext-mail.js)
-
-    content/messenger/schemas/tabs.json     (schemas/tabs.json)
-    content/messenger/schemas/windows.json  (schemas/windows.json)
deleted file mode 100644
--- a/mail/components/extensions/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# 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_COMPONENTS += [
-    'extensions-mail.manifest',
-]
-
-JAR_MANIFESTS += ['jar.mn']
deleted file mode 100644
--- a/mail/components/extensions/parent/ext-mail.js
+++ /dev/null
@@ -1,954 +0,0 @@
-/* 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/. */
-
-ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
-                               "resource://gre/modules/PrivateBrowsingUtils.jsm");
-
-var {
-  ExtensionError,
-  defineLazyGetter,
-} = ExtensionUtils;
-
-let tabTracker;
-let windowTracker;
-
-// This function is pretty tightly tied to Extension.jsm.
-// Its job is to fill in the |tab| property of the sender.
-const getSender = (extension, target, sender) => {
-  let tabId = -1;
-  if ("tabId" in sender) {
-    // The message came from a privileged extension page running in a tab. In
-    // that case, it should include a tabId property (which is filled in by the
-    // page-open listener below).
-    tabId = sender.tabId;
-    delete sender.tabId;
-  } else if (ExtensionUtils.instanceOf(target, "XULElement") ||
-             ExtensionUtils.instanceOf(target, "HTMLIFrameElement")) {
-    tabId = tabTracker.getBrowserData(target).tabId;
-  }
-
-  if (tabId != null && tabId >= 0) {
-    let tab = extension.tabManager.get(tabId, null);
-    if (tab) {
-      sender.tab = tab.convert();
-    }
-  }
-};
-
-// Used by Extension.jsm
-global.tabGetSender = getSender;
-
-global.makeWidgetId = id => {
-  id = id.toLowerCase();
-  // FIXME: This allows for collisions.
-  return id.replace(/[^a-z0-9_-]/g, "_");
-};
-
-
-/**
- * Gets the tab browser for the tabmail tabInfo
- *
- * @param {NativeTabInfo} nativeTabInfo     The tabInfo object to get the browser for
- * @return {?XULElement}                    The browser element for the tab
- */
-function getTabBrowser(nativeTabInfo) {
-  if (!nativeTabInfo) {
-    return null;
-  }
-
-  if (nativeTabInfo.mode.getBrowser) {
-    return nativeTabInfo.mode.getBrowser(nativeTabInfo);
-  }
-
-  if (nativeTabInfo.mode.tabType.getBrowser) {
-    return nativeTabInfo.mode.tabType.getBrowser(nativeTabInfo);
-  }
-
-  return null;
-}
-global.getTabBrowser = getTabBrowser;
-
-/**
- * Thw window tracker tracks opening and closing Thunderbird windows. Each window has an id, which
- * is mapped to native window objects.
- */
-class WindowTracker extends WindowTrackerBase {
-  /**
-   * Adds a tab progress listener to the given mail window
-   *
-   * @param {DOMWindow} window      The mail window to which to add the listener.
-   * @param {Object} listener       The listener to add
-   */
-  addProgressListener(window, listener) {
-    let tabmail = window.document.getElementById("tabmail");
-    tabmail.addTabsProgressListener(listener);
-  }
-
-  /**
-   * Removes a tab progress listener from the given mail window.
-   *
-   * @param {DOMWindow} window      The mail window from which to remove the listener.
-   * @param {Object} listener       The listener to remove
-   */
-  removeProgressListener(window, listener) {
-    let tabmail = window.document.getElementById("tabmail");
-    tabmail.removeTabsProgressListener(listener);
-  }
-
-  /**
-   * Determines if the passed window object is a mail window. The function name is for base class
-   * compatibility with gecko.
-   *
-   * @param {DOMWindow} window      The window to check
-   * @return {Boolean}              True, if the window is a mail window
-   */
-  isBrowserWindow(window) {
-    let { documentElement } = window.document;
-
-    return documentElement.getAttribute("windowtype") === "mail:3pane";
-  }
-
-  /**
-   * The currently active, or topmost, mail window, or null if no mail window is currently open.
-   *
-   * @property {?DOMWindow} topWindow
-   * @readonly
-   */
-  get topWindow() {
-    return Services.wm.getMostRecentWindow("mail:3pane");
-  }
-
-  /**
-   * The currently active, or topmost, mail window, or null if no mail window is currently open.
-   * Will only return the topmost "normal" (i.e., not popup) window.
-   *
-   * @property {?DOMWindow} topNormalWindow
-   * @readonly
-   */
-  get topNormalWindow() {
-    let win = null;
-    if (AppConstants.platform == "win") {
-      let windowList = Services.wm.getZOrderDOMWindowEnumerator("mail:3pane", true);
-      if (!windowList.hasMoreElements()) {
-        return null;
-      }
-
-      win = windowList.getNext();
-      while (win.document.documentElement.getAttribute("chromehidden")) {
-        if (!windowList.hasMoreElements()) {
-          return null;
-        }
-
-        win = windowList.getNext();
-      }
-    } else {
-      // Platforms other than Windows have a broken z-order...
-      win = Services.wm.getMostRecentWindow("mail:3pane", true);
-
-      // If we're lucky, this isn't a popup, and we can just return this.
-      if (win && win.document.documentElement.getAttribute("chromehidden")) {
-        win = null;
-        let windowList = Services.wm.getEnumerator("mail:3pane", true);
-        // This is oldest to newest, so this gets a bit ugly.
-        while (windowList.hasMoreElements()) {
-          let nextWin = windowList.getNext();
-          if (!nextWin.document.documentElement.getAttribute("chromehidden")) {
-            win = nextWin;
-          }
-        }
-      }
-    }
-
-    return win;
-  }
-}
-
-/**
- * An event manager API provider which listens for a DOM event in any mail
- * window, and calls the given listener function whenever an event is received.
- * That listener function receives a `fire` object, which it can use to dispatch
- * events to the extension, and a DOM event object.
- *
- * @param {BaseContext} context
- *        The extension context which the event manager belongs to.
- * @param {string} name
- *        The API name of the event manager, e.g.,"runtime.onMessage".
- * @param {string} event
- *        The name of the DOM event to listen for.
- * @param {function} listener
- *        The listener function to call when a DOM event is received.
- */
-global.WindowEventManager = class extends EventManager {
-  constructor(context, name, event, listener) {
-    super(context, name, fire => {
-      let listener2 = listener.bind(null, fire);
-
-      windowTracker.addListener(event, listener2);
-      return () => {
-        windowTracker.removeListener(event, listener2);
-      };
-    });
-  }
-};
-
-/**
- * Tracks the opening and closing of tabs and maps them between their numeric WebExtension ID and
- * the native tab info objects
- */
-class TabTracker extends TabTrackerBase {
-  constructor() {
-    super();
-
-    this._tabs = new WeakMap();
-    this._browsers = new WeakMap();
-    this._tabIds = new Map();
-    this._nextId = 1;
-    this._movingTabs = new Map();
-
-    this._handleTabDestroyed = this._handleTabDestroyed.bind(this);
-  }
-
-  /**
-   * Initialize tab tracking listeners the first time that an event listener is added
-   */
-  init() {
-    if (this.initialized) {
-      return;
-    }
-    this.initialized = true;
-
-    this._handleWindowOpen = this._handleWindowOpen.bind(this);
-    this._handleWindowClose = this._handleWindowClose.bind(this);
-
-    windowTracker.addListener("TabClose", this);
-    windowTracker.addListener("TabOpen", this);
-    windowTracker.addListener("TabSelect", this);
-    windowTracker.addOpenListener(this._handleWindowOpen);
-    windowTracker.addCloseListener(this._handleWindowClose);
-
-    /* eslint-disable mozilla/balanced-listeners */
-    this.on("tab-detached", this._handleTabDestroyed);
-    this.on("tab-removed", this._handleTabDestroyed);
-    /* eslint-enable mozilla/balanced-listeners */
-  }
-
-  /**
-   * Returns the numeric ID for the given native tab.
-   *
-   * @param {NativeTabInfo} nativeTabInfo       The tabmail tabInfo for which to return an ID
-   * @return {Integer}                          The tab's numeric ID
-   */
-  getId(nativeTabInfo) {
-    let id = this._tabs.get(nativeTabInfo);
-    if (id) {
-      return id;
-    }
-
-    this.init();
-
-    id = this._nextId++;
-    this.setId(nativeTabInfo, id);
-    return id;
-  }
-
-  /**
-   * Returns the tab id corresponding to the given browser element
-   *
-   * @param {XULElement} browser        The <browser> element to retrieve for
-   * @return {Integer}                  The tab's numeric ID
-   */
-  getBrowserTabId(browser) {
-    let id = this._browsers.get(browser);
-    if (id) {
-      return id;
-    }
-
-    let tabmail = browser.ownerDocument.getElementById("tabmail");
-    let tab = tabmail && tabmail.tabInfo.find(info => getTabBrowser(info) == browser);
-
-    if (tab) {
-      id = this.getId(tab);
-      this._browsers.set(browser, id);
-      return id;
-    }
-    return -1;
-  }
-
-  /**
-   * Records the tab information for the given tabInfo object
-   *
-   * @param {NativeTabInfo} nativeTabInfo       The tab info to record for
-   * @param {Integer} id                        The tab id to record
-   */
-  setId(nativeTabInfo, id) {
-    this._tabs.set(nativeTabInfo, id);
-    let browser = getTabBrowser(nativeTabInfo);
-    if (browser) {
-      this._browsers.set(browser, id);
-    }
-    this._tabIds.set(id, nativeTabInfo);
-  }
-
-  /**
-   * Function to call when a tab was close, deletes tab information for the tab
-   *
-   * @param {Event} event                  The event triggering the detroyal
-   * @param {{ nativeTabInfo:NativeTabInfo}}  The object containing tab info
-   */
-  _handleTabDestroyed(event, { nativeTabInfo }) {
-    let id = this._tabs.get(nativeTabInfo);
-    if (id) {
-      this._tabs.delete(nativeTabInfo);
-      if (this._tabIds.get(id) === nativeTabInfo) {
-        this._tabIds.delete(id);
-      }
-    }
-  }
-
-  /**
-   * Returns the native tab with the given numeric ID.
-   *
-   * @param {Integer} tabId     The numeric ID of the tab to return.
-   * @param {*} default_        The value to return if no tab exists with the given ID.
-   * @return {NativeTabInfo}    The tab information for the given id.
-   */
-  getTab(tabId, default_ = undefined) {
-    let nativeTabInfo = this._tabIds.get(tabId);
-    if (nativeTabInfo) {
-      return nativeTabInfo;
-    }
-    if (default_ !== undefined) {
-      return default_;
-    }
-    throw new ExtensionError(`Invalid tab ID: ${tabId}`);
-  }
-
-  /**
-   * Handles load events for recently-opened windows, and adds additional
-   * listeners which may only be safely added when the window is fully loaded.
-   *
-   * @param {Event} event       A DOM event to handle.
-   */
-  handleEvent(event) {
-    let nativeTabInfo = event.detail.tabInfo;
-    if (!getTabBrowser(nativeTabInfo)) {
-      // We don't care about events for tabs that don't have a browser
-      return;
-    }
-
-    switch (event.type) {
-      case "TabOpen": {
-        // Save the current tab, since the newly-created tab will likely be
-        // active by the time the promise below resolves and the event is
-        // dispatched.
-        let tabmail = event.target.ownerDocument.getElementById("tabmail");
-        let currentTab = tabmail.selectedTab;
-
-        // We need to delay sending this event until the next tick, since the
-        // tab does not have its final index when the TabOpen event is dispatched.
-        Promise.resolve().then(() => {
-          if (event.detail.moving) {
-            let srcTabId = this._movingTabs.get(event.detail.moving);
-            this.setId(nativeTabInfo, srcTabId);
-            this._movingTabs.delete(event.detail.moving);
-
-            this.emitAttached(nativeTabInfo);
-          } else {
-            this.emitCreated(nativeTabInfo, currentTab);
-          }
-        });
-        break;
-      }
-
-      case "TabClose": {
-        if (event.detail.moving) {
-          this._movingTabs.set(event.detail.moving, this.getId(nativeTabInfo));
-          this.emitDetached(nativeTabInfo);
-        } else {
-          this.emitRemoved(nativeTabInfo, false);
-        }
-        break;
-      }
-
-      case "TabSelect":
-        // Because we are delaying calling emitCreated above, we also need to
-        // delay sending this event because it shouldn't fire before onCreated.
-        Promise.resolve().then(() => {
-          this.emitActivated(nativeTabInfo);
-        });
-        break;
-    }
-  }
-
-  /**
-   * A private method which is called whenever a new mail window is opened, and dispatches the
-   * necessary events for it.
-   *
-   * @param {DOMWindow} window      The window being opened.
-   */
-  _handleWindowOpen(window) {
-    let tabmail = window.document.getElementById("tabmail");
-    for (let nativeTabInfo of tabmail.tabInfo) {
-      if (!getTabBrowser(nativeTabInfo)) {
-        continue;
-      }
-      this.emitCreated(nativeTabInfo);
-    }
-  }
-
-  /**
-   * A private method which is called whenever a mail window is closed, and dispatches the necessary
-   * events for it.
-   *
-   * @param {DOMWindow} window      The window being closed.
-   */
-  _handleWindowClose(window) {
-    let tabmail = window.document.getElementById("tabmail");
-    for (let nativeTabInfo of tabmail.tabInfo) {
-      if (!getTabBrowser(nativeTabInfo)) {
-        continue;
-      }
-      this.emitRemoved(nativeTabInfo, true);
-    }
-  }
-
-  /**
-   * Emits a "tab-activated" event for the given tab info.
-   *
-   * @param {NativeTabInfo} nativeTabInfo   The tab info which has been activated.
-   */
-  emitActivated(nativeTabInfo) {
-    let browser = getTabBrowser(nativeTabInfo);
-
-    this.emit("tab-activated", {
-      tabId: this.getId(nativeTabInfo),
-      windowId: windowTracker.getId(browser.ownerGlobal)
-    });
-  }
-
-  /**
-   * Emits a "tab-attached" event for the given tab info.
-   *
-   * @param {NativeTabInfo} nativeTabInfo   The tab info which is being attached.
-   */
-  emitAttached(nativeTabInfo) {
-    let tabId = this.getId(nativeTabInfo);
-    let browser = getTabBrowser(nativeTabInfo);
-    let tabmail = browser.ownerDocument.getElementById("tabmail");
-    let tabIndex = tabmail._getTabContextForTabbyThing(nativeTabInfo)[0];
-    let newWindowId = windowTracker.getId(browser.ownerGlobal);
-
-    this.emit("tab-attached", { nativeTabInfo, tabId, newWindowId, newPosition: tabIndex });
-  }
-
-  /**
-   * Emits a "tab-detached" event for the given tab info.
-   *
-   * @param {NativeTabInfo} nativeTabInfo   The tab info which is being detached.
-   */
-  emitDetached(nativeTabInfo) {
-    let tabId = this.getId(nativeTabInfo);
-    let browser = getTabBrowser(nativeTabInfo);
-    let tabmail = browser.ownerDocument.getElementById("tabmail");
-    let tabIndex = tabmail._getTabContextForTabbyThing(nativeTabInfo)[0];
-    let oldWindowId = windowTracker.getId(browser.ownerGlobal);
-
-    this.emit("tab-detached", { nativeTabInfo, tabId, oldWindowId, oldPosition: tabIndex });
-  }
-
-  /**
-   * Emits a "tab-created" event for the given tab info.
-   *
-   * @param {NativeTabInfo} nativeTabInfo   The tab info which is being created.
-   * @param {?NativeTab} currentTab         The tab info for the currently active tab.
-   */
-  emitCreated(nativeTabInfo, currentTab) {
-    this.emit("tab-created", { nativeTabInfo, currentTab });
-  }
-
-  /**
-   * Emits a "tab-removed" event for the given tab info.
-   *
-   * @param {NativeTabInfo} nativeTabInfo   The tab info in the window to which the tab is being
-   *                                          removed
-   * @param {Boolean} isWindowClosing       If true, the window with these tabs is closing
-   */
-  emitRemoved(nativeTabInfo, isWindowClosing) {
-    let browser = getTabBrowser(nativeTabInfo);
-    let windowId = windowTracker.getId(browser.ownerGlobal);
-    let tabId = this.getId(nativeTabInfo);
-
-    this.emit("tab-removed", { nativeTabInfo, tabId, windowId, isWindowClosing });
-  }
-
-  /**
-   * Returns tab id and window id for the given browser element
-   *
-   * @param {Element} browser                       The browser element to check
-   * @return {{ tabId:Integer, windowId:Integer }}  The browsing data for the element
-   */
-  getBrowserData(browser) {
-    return {
-      tabId: this.getBrowserTabId(browser),
-      windowId: windowTracker.getId(browser.ownerGlobal)
-    };
-  }
-
-  /**
-   * Returns the active tab info for the given window
-   *
-   * @property {?NativeTabInfo} activeTab       The active tab
-   * @readonly
-   */
-  get activeTab() {
-    let window = windowTracker.topWindow;
-    let tabmail = window && window.document.getElementById("tabmail");
-    return tabmail ? tabmail.selectedTab : null;
-  }
-}
-
-tabTracker = new TabTracker();
-windowTracker = new WindowTracker();
-Object.assign(global, { tabTracker, windowTracker });
-
-/**
- * Extension-specific wrapper around a Thunderbird tab
- */
-class Tab extends TabBase {
-  /** Returns the XUL browser for the tab. */
-  get browser() {
-    return getTabBrowser(this.nativeTab);
-  }
-
-  /** Returns the tabmail element for the tab. */
-  get tabmail() {
-    return this.browser.ownerDocument.getElementById("tabmail");
-  }
-
-  /** Returns the frame loader for the tab */
-  get frameLoader() {
-    // If we don't have a frameLoader yet, just return a dummy with no width and
-    // height.
-    return super.frameLoader || { lazyWidth: 0, lazyHeight: 0 };
-  }
-
-  /** Returns the favIcon, without permission checks */
-  get _favIconUrl() {
-    return this.browser.mIconURL;
-  }
-
-  /** Returns the last accessed time */
-  get lastAccessed() {
-    return 0;
-  }
-
-  /** Returns the audible state */
-  get audible() {
-    return false;
-  }
-
-  /** Returns the cookie store id */
-  get cookieStoreId() {
-    return 0;
-  }
-
-  /** Returns the discarded state */
-  get discarded() {
-    return false;
-  }
-
-  /** Returns the tab height */
-  get height() {
-    return this.frameLoader.lazyHeight;
-  }
-
-  /** Returns hidden status */
-  get hidden() {
-    return false;
-  }
-
-  /** Returns the tab index */
-  get index() {
-    return this.tabmail.tabInfo.filter(info => getTabBrowser(info)).indexOf(this.nativeTab);
-  }
-
-  /** Returns information about the muted state of the tab */
-  get mutedInfo() {
-    return { muted: false };
-  }
-
-  /** Returns information about the sharing state of the tab */
-  get sharingState() {
-    return { camera: false, microphone: false, screen: false };
-  }
-
-  /** Returns the pinned state of the tab */
-  get pinned() {
-    return false;
-  }
-
-  /** Returns the active state of the tab */
-  get active() {
-    return this.nativeTab == this.tabmail.selectedTab;
-  }
-
-  /** Returns the highlighted state of the tab */
-  get highlighted() {
-    return this.active;
-  }
-
-  /** Returns the selected state of the tab */
-  get selected() {
-    return this.active;
-  }
-
-  /** Returns the loading status of the tab */
-  get status() {
-    return this.browser.webProgress.isLoadingDocument ? "loading" : "complete";
-  }
-
-  /** Returns the title of the tab, without permission checks */
-  get _title() {
-    let tabNode = this.tabmail._getTabContextForTabbyThing(this.nativeTab)[2];
-    return tabNode.getAttribute("label");
-  }
-
-  /** Returns the width of the tab */
-  get width() {
-    return this.frameLoader.lazyWidth;
-  }
-
-  /** Returns the native window object of the tab */
-  get window() {
-    return this.browser.ownerGlobal;
-  }
-
-  /** Returns the window id of the tab */
-  get windowId() {
-    return windowTracker.getId(this.window);
-  }
-
-  /** Returns the article state of the tab */
-  get isArticle() {
-    return false;
-  }
-
-  /** Returns the reader mode state of the tab */
-  get isInReaderMode() {
-    return false;
-  }
-}
-
-/**
- * Extension-specific wrapper around a Thunderbird window
- */
-class Window extends WindowBase {
-  /**
-   * Update the geometry of the mail window.
-   *
-   * @param {Object} options
-   *        An object containing new values for the window's geometry.
-   * @param {integer} [options.left]
-   *        The new pixel distance of the left side of the mail window from
-   *        the left of the screen.
-   * @param {integer} [options.top]
-   *        The new pixel distance of the top side of the mail window from
-   *        the top of the screen.
-   * @param {integer} [options.width]
-   *        The new pixel width of the window.
-   * @param {integer} [options.height]
-   *        The new pixel height of the window.
-   */
-  updateGeometry(options) {
-    let { window } = this;
-
-    if (options.left !== null || options.top !== null) {
-      let left = options.left === null ? window.screenX : options.left;
-      let top = options.top === null ? window.screenY : options.top;
-      window.moveTo(left, top);
-    }
-
-    if (options.width !== null || options.height !== null) {
-      let width = options.width === null ? window.outerWidth : options.width;
-      let height = options.height === null ? window.outerHeight : options.height;
-      window.resizeTo(width, height);
-    }
-  }
-
-  /** Returns the tabmail element for the tab. */
-  get tabmail() {
-    return this.window.document.getElementById("tabmail");
-  }
-
-  /** Returns the title of the tab, without permission checks */
-  get _title() {
-    return this.window.document.title;
-  }
-
-  /** Returns the title of the tab, checking tab permissions */
-  get title() {
-    // Thunderbird can have an empty active tab while a window is loading
-    if (this.activeTab && this.activeTab.hasTabPermission) {
-      return this._title;
-    }
-    return null;
-  }
-
-  /**
-   * Sets the title preface of the window.
-   *
-   * @param {String} titlePreface       The title preface to set
-   */
-  setTitlePreface(titlePreface) {
-    this.window.document.documentElement.setAttribute("titlepreface", titlePreface);
-  }
-
-  /** Gets the foucsed state of the window */
-  get focused() {
-    return this.window.document.hasFocus();
-  }
-
-  /** Gets the top position of the window */
-  get top() {
-    return this.window.screenY;
-  }
-
-  /** Gets the left position of the window */
-  get left() {
-    return this.window.screenX;
-  }
-
-  /** Gets the width of the window */
-  get width() {
-    return this.window.outerWidth;
-  }
-
-  /** Gets the height of the window */
-  get height() {
-    return this.window.outerHeight;
-  }
-
-  /** Gets the private browsing status of the window */
-  get incognito() {
-    return PrivateBrowsingUtils.isWindowPrivate(this.window);
-  }
-
-  /** Checks if the window is considered always on top */
-  get alwaysOnTop() {
-    return this.xulWindow.zLevel >= Ci.nsIXULWindow.raisedZ;
-  }
-
-  /** Checks if the window was the last one focused */
-  get isLastFocused() {
-    return this.window === windowTracker.topWindow;
-  }
-
-  /**
-   * Returns the window state for the given window
-   *
-   * @param {DOMWindow} window      The window to check
-   * @return {String}               "maximized", "minimized", "normal" or "fullscreen"
-   */
-  static getState(window) {
-    const STATES = {
-      [window.STATE_MAXIMIZED]: "maximized",
-      [window.STATE_MINIMIZED]: "minimized",
-      [window.STATE_NORMAL]: "normal",
-    };
-    let state = STATES[window.windowState];
-    if (window.fullScreen) {
-      state = "fullscreen";
-    }
-    return state;
-  }
-
-  /** Returns the window state for this specific window */
-  get state() {
-    return Window.getState(this.window);
-  }
-
-  /**
-   * Sets the window state for this speific window
-   *
-   * @param {String} state          "maximized", "minimized", "normal" or "fullscreen"
-   */
-  set state(state) {
-    let { window } = this;
-    if (state !== "fullscreen" && window.fullScreen) {
-      window.fullScreen = false;
-    }
-
-    switch (state) {
-      case "maximized":
-        window.maximize();
-        break;
-
-      case "minimized":
-      case "docked":
-        window.minimize();
-        break;
-
-      case "normal":
-        // Restore sometimes returns the window to its previous state, rather
-        // than to the "normal" state, so it may need to be called anywhere from
-        // zero to two times.
-        window.restore();
-        if (window.windowState !== window.STATE_NORMAL) {
-          window.restore();
-        }
-        if (window.windowState !== window.STATE_NORMAL) {
-          // And on OS-X, where normal vs. maximized is basically a heuristic,
-          // we need to cheat.
-          window.sizeToContent();
-        }
-        break;
-
-      case "fullscreen":
-        window.fullScreen = true;
-        break;
-
-      default:
-        throw new Error(`Unexpected window state: ${state}`);
-    }
-  }
-
-  /**
-   * Retrieves the (relevant) tabs in this window
-   *
-   * @yields {Tab}      The wrapped Tab in this window
-   */
-  * getTabs() {
-    let { tabManager } = this.extension;
-
-    for (let nativeTabInfo of this.tabmail.tabInfo) {
-      if (getTabBrowser(nativeTabInfo)) {
-        // Only tabs that have a browser element
-        yield tabManager.getWrapper(nativeTabInfo);
-      }
-    }
-  }
-
-  /** Retrieves the active tab in this window */
-  get activeTab() {
-    let { tabManager } = this.extension;
-    let selectedTab = this.tabmail.selectedTab;
-    if (selectedTab) {
-      return tabManager.getWrapper(selectedTab);
-    }
-    return null;
-  }
-
-  /**
-   * Retrieves the tab at the given index
-   *
-   * @param {Number} index      The index to look at
-   * @return {Tab}              The wrapped tab at the index
-   */
-  getTabAtIndex(index) {
-    let nativeTabInfo = this.tabmail.tabInfo.filter(info => getTabBrowser(info))[index];
-    if (nativeTabInfo) {
-      return tabManager.getWrapper(nativeTabInfo);
-    }
-    return null;
-  }
-}
-
-Object.assign(global, { Tab, Window });
-
-/**
- * Manages native tabs, their wrappers, and their dynamic permissions for a particular extension.
- */
-class TabManager extends TabManagerBase {
-  /**
-   * Returns a Tab wrapper for the tab with the given ID.
-   *
-   * @param {integer} tabId     The ID of the tab for which to return a wrapper.
-   * @param {*} default_        The value to return if no tab exists with the given ID.
-   * @return {Tab|*}            The wrapped tab, or the default value
-   */
-  get(tabId, default_ = undefined) {
-    let nativeTabInfo = tabTracker.getTab(tabId, default_);
-
-    if (nativeTabInfo) {
-      return this.getWrapper(nativeTabInfo);
-    }
-    return default_;
-  }
-
-  /**
-   * If the extension has requested activeTab permission, grant it those permissions for the current
-   * inner window in the given native tab.
-   *
-   * @param {NativeTabInfo} nativeTabInfo       The native tab for which to grant permissions.
-   */
-  addActiveTabPermission(nativeTabInfo = tabTracker.activeTab) {
-    super.addActiveTabPermission(nativeTabInfo);
-  }
-
-  /**
-   * Revoke the extension's activeTab permissions for the current inner window of the given native
-   * tab.
-   *
-   * @param {NativeTabInfo} nativeTabInfo       The native tab for which to revoke permissions.
-   */
-  revokeActiveTabPermission(nativeTabInfo = tabTracker.activeTab) {
-    super.revokeActiveTabPermission(nativeTabInfo);
-  }
-
-  /**
-   * Returns a new Tab instance wrapping the given native tab info.
-   *
-   * @param {NativeTabInfo} nativeTabInfo       The native tab for which to return a wrapper.
-   * @return {Tab}                              The wrapped native tab
-   */
-  wrapTab(nativeTabInfo) {
-    return new Tab(this.extension, nativeTabInfo, tabTracker.getId(nativeTabInfo));
-  }
-}
-
-/**
- * Manages native browser windows and their wrappers for a particular extension.
- */
-class WindowManager extends WindowManagerBase {
-  /**
-   * Returns a Window wrapper for the mail window with the given ID.
-   *
-   * @param {Integer} windowId      The ID of the browser window for which to return a wrapper.
-   * @param {BaseContext} context   The extension context for which the matching is being performed.
-   *                                  Used to determine the current window for relevant properties.
-   * @return {Window}               The wrapped window
-   */
-  get(windowId, context) {
-    let window = windowTracker.getWindow(windowId, context);
-    return this.getWrapper(window);
-  }
-
-  /**
-   * Yields an iterator of WindowBase wrappers for each currently existing browser window.
-   *
-   * @yields {Window}
-   */
-  * getAll() {
-    for (let window of windowTracker.browserWindows()) {
-      yield this.getWrapper(window);
-    }
-  }
-
-  /**
-   * Returns a new Window instance wrapping the given mail window.
-   *
-   * @param {DOMWindow} window      The mail window for which to return a wrapper.
-   * @returns {Window}              The wrapped window
-   */
-  wrapWindow(window) {
-    return new Window(this.extension, window, windowTracker.getId(window));
-  }
-}
-
-extensions.on("startup", (type, extension) => { // eslint-disable-line mozilla/balanced-listeners
-  defineLazyGetter(extension, "tabManager",
-                   () => new TabManager(extension));
-  defineLazyGetter(extension, "windowManager",
-                   () => new WindowManager(extension));
-});
deleted file mode 100644
--- a/mail/components/extensions/parent/ext-tabs.js
+++ /dev/null
@@ -1,617 +0,0 @@
-/* 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/. */
-
-ChromeUtils.defineModuleGetter(this, "PromiseUtils",
-                               "resource://gre/modules/PromiseUtils.jsm");
-var { ExtensionError } = ExtensionUtils;
-
-/**
- * A listener that allows waiting until tabs are fully loaded, e.g. off of about:blank
- */
-let tabListener = {
-  tabReadyInitialized: false,
-  tabReadyPromises: new WeakMap(),
-  initializingTabs: new WeakSet(),
-
-  /**
-   * Initialize the progress listener for tab ready changes
-   */
-  initTabReady() {
-    if (!this.tabReadyInitialized) {
-      windowTracker.addListener("progress", this);
-
-      this.tabReadyInitialized = true;
-    }
-  },
-
-  /**
-   * Web Progress listener method for the location change
-   *
-   * @param {Element} browser               The browser element that caused the change
-   * @param {nsIWebProgress} webProgress    The web progress for the location change
-   * @param {nsIRequest} request            The xpcom request for this change
-   * @param {nsIURI} locationURI            The target uri
-   * @param {Integer} flags                 The web progress flags for this change
-   */
-  onLocationChange(browser, webProgress, request, locationURI, flags) {
-    if (webProgress.isTopLevel) {
-      let tabmail = browser.ownerDocument.getElementById("tabmail");
-      let nativeTabInfo = tabmail.getTabForBrowser(browser);
-
-      // Now we are certain that the first page in the tab was loaded.
-      this.initializingTabs.delete(nativeTabInfo);
-
-      // browser.innerWindowID is now set, resolve the promises if any.
-      let deferred = this.tabReadyPromises.get(nativeTabInfo);
-      if (deferred) {
-        deferred.resolve(nativeTabInfo);
-        this.tabReadyPromises.delete(nativeTabInfo);
-      }
-    }
-  },
-
-  /**
-   * Promise that the given tab completes loading
-   *
-   * @param {NativeTabInfo} nativeTabInfo       The tabInfo describing the tab
-   * @return {Promise<NativeTabInfo>}           Resolves when the tab completes loading
-   */
-  awaitTabReady(nativeTabInfo) {
-    let deferred = this.tabReadyPromises.get(nativeTabInfo);
-    if (!deferred) {
-      deferred = PromiseUtils.defer();
-      let browser = getTabBrowser(nativeTabInfo);
-      if (!this.initializingTabs.has(nativeTabInfo) &&
-          (browser.innerWindowID || browser.currentURI.spec === "about:blank")) {
-        deferred.resolve(nativeTabInfo);
-      } else {
-        this.initTabReady();
-        this.tabReadyPromises.set(nativeTabInfo, deferred);
-      }
-    }
-    return deferred.promise;
-  }
-};
-
-// Attributes and properties used in the TabsUpdateFilterManager
-const allAttrs = new Set(["favIconUrl", "title"]);
-const allProperties = new Set([
-  "favIconUrl",
-  "status",
-  "title",
-]);
-const restricted = new Set(["url", "favIconUrl", "title"]);
-
-/**
- * An EventManager for the tabs.onUpdated listener
- */
-class TabsUpdateFilterEventManager extends EventManager {
-  constructor(context) {
-    let { extension } = context;
-    let { tabManager } = extension;
-
-    let register = (fire, filterProps) => {
-      let filter = { ...filterProps };
-      if (filter.urls) {
-        filter.urls = new MatchPatternSet(filter.urls);
-      }
-      let needsModified = true;
-      if (filter.properties) {
-        // Default is to listen for all events.
-        needsModified = filter.properties.some(prop => allAttrs.has(prop));
-        filter.properties = new Set(filter.properties);
-      } else {
-        filter.properties = allProperties;
-      }
-
-      function sanitize(changeInfo) {
-        let result = {};
-        let nonempty = false;
-        let hasTabs = extension.hasPermission("tabs");
-        for (let prop in changeInfo) {
-          if (hasTabs || !restricted.has(prop)) {
-            nonempty = true;
-            result[prop] = changeInfo[prop];
-          }
-        }
-        return nonempty && result;
-      }
-
-      function getWindowID(windowId) {
-        if (windowId === Window.WINDOW_ID_CURRENT) {
-          return windowTracker.getId(windowTracker.topWindow);
-        }
-        return windowId;
-      }
-
-      function matchFilters(tab, changed) {
-        if (!filterProps) {
-          return true;
-        }
-        if (filter.tabId != null && tab.id != filter.tabId) {
-          return false;
-        }
-        if (filter.windowId != null && tab.windowId != getWindowID(filter.windowId)) {
-          return false;
-        }
-        if (filter.urls) {
-          // We check permission first because tab.uri is null if !hasTabPermission.
-          return tab.hasTabPermission && filter.urls.matches(tab.uri);
-        }
-        return true;
-      }
-
-      let fireForTab = (tab, changed) => {
-        if (!matchFilters(tab, changed)) {
-          return;
-        }
-
-        let changeInfo = sanitize(changed);
-        if (changeInfo) {
-          fire.async(tab.id, changeInfo, tab.convert());
-        }
-      };
-
-      let listener = event => {
-        let needed = [];
-        if (event.type == "TabAttrModified") {
-          let changed = event.detail.changed;
-          if (changed.includes("image") && filter.properties.has("favIconUrl")) {
-            needed.push("favIconUrl");
-          }
-          if (changed.includes("label") && filter.properties.has("title")) {
-            needed.push("title");
-          }
-        }
-
-        let tab = tabManager.getWrapper(event.detail.tabInfo);
-
-        let changeInfo = {};
-        for (let prop of needed) {
-          changeInfo[prop] = tab[prop];
-        }
-
-        fireForTab(tab, changeInfo);
-      };
-
-      let statusListener = ({ browser, status, url }) => {
-        let tabmail = browser.ownerDocument.getElementById("tabmail");
-        let nativeTabInfo = tabmail.getTabForBrowser(browser);
-        if (nativeTabInfo) {
-          let changed = { status };
-          if (url) {
-            changed.url = url;
-          }
-
-          fireForTab(tabManager.getWrapper(nativeTabInfo), changed);
-        }
-      };
-
-      if (needsModified) {
-        windowTracker.addListener("TabAttrModified", listener);
-      }
-
-      if (filter.properties.has("status")) {
-        windowTracker.addListener("status", statusListener);
-      }
-
-      return () => {
-        if (needsModified) {
-          windowTracker.removeListener("TabAttrModified", listener);
-        }
-        if (filter.properties.has("status")) {
-          windowTracker.removeListener("status", statusListener);
-        }
-      };
-    };
-
-    super({
-      context,
-      name: "tabs.onUpdated",
-      register,
-    });
-  }
-
-  addListener(callback, filter) {
-    let { extension } = this.context;
-    if (filter && filter.urls &&
-        (!extension.hasPermission("tabs") && !extension.hasPermission("activeTab"))) {
-      Cu.reportError("Url filtering in tabs.onUpdated requires \"tabs\" or \"activeTab\" permission.");
-      return false;
-    }
-    return super.addListener(callback, filter);
-  }
-}
-
-this.tabs = class extends ExtensionAPI {
-  getAPI(context) {
-    let { extension } = context;
-    let { tabManager } = extension;
-
-    /**
-     * Gets the tab for the given tab id, or the active tab if the id is null
-     *
-     * @param {?Integer} tabId          The tab id to get
-     * @return {Tab}                    The matching tab, or the active tab
-     */
-    function getTabOrActive(tabId) {
-      if (tabId !== null) {
-        return tabTracker.getTab(tabId);
-      }
-      return tabTracker.activeTab;
-    }
-
-    /**
-     * Promise that the tab with the given tab id is ready
-     *
-     * @param {Integer} tabId       The tab id to check
-     * @return {Promise<NativeTabInfo>}     Resolved when the loading is complete
-     */
-    async function promiseTabWhenReady(tabId) {
-      let tab;
-      if (tabId === null) {
-        tab = tabManager.getWrapper(tabTracker.activeTab);
-      } else {
-        tab = tabManager.get(tabId);
-      }
-
-      await tabListener.awaitTabReady(tab.nativeTab);
-
-      return tab;
-    }
-
-    return {
-      tabs: {
-        onActivated: new EventManager({
-          context,
-          name: "tabs.onActivated",
-          register: fire => {
-            let listener = (eventName, event) => {
-              fire.async(event);
-            };
-
-            tabTracker.on("tab-activated", listener);
-            return () => {
-              tabTracker.off("tab-activated", listener);
-            };
-          }
-        }).api(),
-
-        onCreated: new EventManager({
-          context,
-          name: "tabs.onCreated",
-          register: fire => {
-            let listener = (eventName, event) => {
-              fire.async(tabManager.convert(event.nativeTabInfo, event.currentTab));
-            };
-
-            tabTracker.on("tab-created", listener);
-            return () => {
-              tabTracker.off("tab-created", listener);
-            };
-          }
-        }).api(),
-
-        onAttached: new EventManager({
-          context,
-          name: "tabs.onAttached",
-          register: fire => {
-            let listener = (eventName, event) => {
-              fire.async(event.tabId, { newWindowId: event.newWindowId, newPosition: event.newPosition });
-            };
-
-            tabTracker.on("tab-attached", listener);
-            return () => {
-              tabTracker.off("tab-attached", listener);
-            };
-          },
-        }).api(),
-
-        onDetached: new EventManager({
-          context,
-          name: "tabs.onDetached",
-          register: fire => {
-            let listener = (eventName, event) => {
-              fire.async(event.tabId, { oldWindowId: event.oldWindowId, oldPosition: event.oldPosition });
-            };
-
-            tabTracker.on("tab-detached", listener);
-            return () => {
-              tabTracker.off("tab-detached", listener);
-            };
-          },
-        }).api(),
-
-        onRemoved: new EventManager({
-          context,
-          name: "tabs.onRemoved",
-          register: fire => {
-            let listener = (eventName, event) => {
-              fire.async(event.tabId, { windowId: event.windowId, isWindowClosing: event.isWindowClosing });
-            };
-
-            tabTracker.on("tab-removed", listener);
-            return () => {
-              tabTracker.off("tab-removed", listener);
-            };
-          }
-        }).api(),
-
-        onMoved: new EventManager({
-          context,
-          name: "tabs.onMoved",
-          register: fire => {
-            let moveListener = event => {
-              let nativeTab = event.originalTarget;
-              let nativeTabInfo = event.detail.tabInfo;
-              let tabmail = nativeTab.ownerDocument.getElementById("tabmail");
-
-              fire.async(tabTracker.getId(nativeTabInfo), {
-                windowId: windowTracker.getId(nativeTab.ownerGlobal),
-                fromIndex: event.detail.idx,
-                toIndex: tabmail.tabInfo.indexOf(nativeTabInfo)
-              });
-            };
-
-            windowTracker.addListener("TabMove", moveListener);
-            return () => {
-              windowTracker.removeListener("TabMove", moveListener);
-            };
-          }
-        }).api(),
-
-        onUpdated: new TabsUpdateFilterEventManager(context).api(),
-
-        async create(createProperties) {
-          let window = createProperties.windowId === null
-              ? windowTracker.topNormalWindow
-              : windowTracker.getWindow(createProperties.windowId, context);
-          let tabmail = window.document.getElementById("tabmail");
-
-          let url;
-          if (createProperties.url !== null) {
-            url = context.uri.resolve(createProperties.url);
-
-            if (!context.checkLoadURL(url, { dontReportErrors: true })) {
-              return Promise.reject({ message: `Illegal URL: ${url}` });
-            }
-          }
-
-          let currentTab = tabmail.selectedTab;
-
-          let active = true;
-          if (createProperties.active !== null) {
-            active = createProperties.active;
-          }
-
-          tabListener.initTabReady();
-
-          let nativeTabInfo = tabmail.openTab("contentTab", {
-            contentPage: url || "about:blank",
-            background: !active
-          });
-
-          if (createProperties.index !== null) {
-            tabmail.moveTabTo(nativeTabInfo, createProperties.index);
-            tabmail.updateCurrentTab();
-          }
-
-          if (createProperties.url && createProperties.url !== "about:blank") {
-            // Mark tabs as initializing, so operations like `executeScript` wait until the
-            // requested URL is loaded
-            tabListener.initializingTabs.add(nativeTabInfo);
-          }
-
-          return tabManager.convert(nativeTabInfo, currentTab);
-        },
-
-        async remove(tabs) {
-          if (!Array.isArray(tabs)) {
-            tabs = [tabs];
-          }
-
-          for (let tabId of tabs) {
-            let nativeTabInfo = tabTracker.getTab(tabId);
-            let browser = getTabBrowser(nativeTabInfo);
-            let tabmail = browser.ownerDocument.getElementById("tabmail");
-            tabmail.closeTab(nativeTabInfo);
-          }
-        },
-
-        async update(tabId, updateProperties) {
-          let nativeTabInfo = getTabOrActive(tabId);
-          let browser = getTabBrowser(nativeTabInfo);
-          let tabmail = browser.ownerDocument.getElementById("tabmail");
-
-          if (updateProperties.url !== null) {
-            let url = context.uri.resolve(updateProperties.url);
-
-            if (!context.checkLoadURL(url, { dontReportErrors: true })) {
-              return Promise.reject({ message: `Illegal URL: ${url}` });
-            }
-
-            let options = {
-              flags: updateProperties.loadReplace
-                      ? Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY
-                      : Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
-              triggeringPrincipal: context.principal,
-            };
-            browser.loadURI(url, options);
-          }
-
-          if (updateProperties.active !== null) {
-            if (updateProperties.active) {
-              tabmail.selectedTab = nativeTabInfo;
-            } else {
-              // Not sure what to do here? Which tab should we select?
-            }
-          }
-
-          return tabManager.convert(nativeTabInfo);
-        },
-
-        async reload(tabId, reloadProperties) {
-          let nativeTabInfo = getTabOrActive(tabId);
-          let browser = getTabBrowser(nativeTabInfo);
-
-          let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
-          if (reloadProperties && reloadProperties.bypassCache) {
-            flags |= Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
-          }
-          browser.reloadWithFlags(flags);
-        },
-
-        async get(tabId) {
-          return tabManager.get(tabId).convert();
-        },
-
-        getCurrent() {
-          let tabData;
-          if (context.tabId) {
-            tabData = tabManager.get(context.tabId).convert();
-          }
-          return Promise.resolve(tabData);
-        },
-
-        async query(queryInfo) {
-          if (!extension.hasPermission("tabs")) {
-            if (queryInfo.url !== null || queryInfo.title !== null) {
-              return Promise.reject({ message: 'The "tabs" permission is required to use the query API with the "url" or "title" parameters' });
-            }
-          }
-
-          queryInfo = Object.assign({}, queryInfo);
-
-          if (queryInfo.url !== null) {
-            queryInfo.url = new MatchPatternSet([].concat(queryInfo.url));
-          }
-          if (queryInfo.title !== null) {
-            queryInfo.title = new MatchGlob(queryInfo.title);
-          }
-
-          // Make ext-tabs-base happy since it does a strict check
-          queryInfo.screen = null;
-
-          return Array.from(tabManager.query(queryInfo, context), tab => tab.convert());
-        },
-
-        async executeScript(tabId, details) {
-          // TODO make this work
-          let tab = await promiseTabWhenReady(tabId);
-
-          return tab.executeScript(context, details);
-        },
-
-        async insertCSS(tabId, details) {
-          // TODO make this work
-          let tab = await promiseTabWhenReady(tabId);
-
-          return tab.insertCSS(context, details);
-        },
-
-        async removeCSS(tabId, details) {
-          // TODO make this work
-          let tab = await promiseTabWhenReady(tabId);
-
-          return tab.removeCSS(context, details);
-        },
-
-        async move(tabIds, moveProperties) {
-          let tabsMoved = [];
-          if (!Array.isArray(tabIds)) {
-            tabIds = [tabIds];
-          }
-
-          let destinationWindow = null;
-          if (moveProperties.windowId !== null) {
-            destinationWindow = windowTracker.getWindow(moveProperties.windowId);
-            // Fail on an invalid window.
-            if (!destinationWindow) {
-              return Promise.reject({ message: `Invalid window ID: ${moveProperties.windowId}` });
-            }
-          }
-
-          /*
-            Indexes are maintained on a per window basis so that a call to
-              move([tabA, tabB], {index: 0})
-                -> tabA to 0, tabB to 1 if tabA and tabB are in the same window
-              move([tabA, tabB], {index: 0})
-                -> tabA to 0, tabB to 0 if tabA and tabB are in different windows
-          */
-          let indexMap = new Map();
-          let lastInsertion = new Map();
-
-          let tabs = tabIds.map(tabId => tabTracker.getTab(tabId));
-          for (let nativeTabInfo of tabs) {
-            // If the window is not specified, use the window from the tab.
-            let browser = getTabBrowser(nativeTabInfo);
-
-            let srcwindow = browser.ownerGlobal;
-            let tgtwindow = destinationWindow || browser.ownerGlobal;
-            let tgttabmail = tgtwindow.document.getElementById("tabmail");
-            let srctabmail = srcwindow.document.getElementById("tabmail");
-
-            // If we are not moving the tab to a different window, and the window
-            // only has one tab, do nothing.
-            if (srcwindow == tgtwindow && srctabmail.tabInfo.length === 1) {
-              continue;
-            }
-
-            let insertionPoint = indexMap.get(tgtwindow) || moveProperties.index;
-            // If the index is -1 it should go to the end of the tabs.
-            if (insertionPoint == -1) {
-              insertionPoint = tgttabmail.tabInfo.length;
-            }
-
-            let tabPosition = srctabmail.tabInfo.indexOf(nativeTabInfo);
-
-            // If this is not the first tab to be inserted into this window and
-            // the insertion point is the same as the last insertion and
-            // the tab is further to the right than the current insertion point
-            // then you need to bump up the insertion point. See bug 1323311.
-            if (lastInsertion.has(tgtwindow) &&
-                lastInsertion.get(tgtwindow) === insertionPoint &&
-                tabPosition > insertionPoint) {
-              insertionPoint++;
-              indexMap.set(tgtwindow, insertionPoint);
-            }
-
-            if (srcwindow == tgtwindow) {
-              // If the window we are moving is the same, just move the tab.
-              tgttabmail.moveTabTo(nativeTabInfo, insertionPoint);
-            } else {
-              // If the window we are moving the tab in is different, then move the tab
-              // to the new window.
-              srctabmail.replaceTabWithWindow(nativeTabInfo, tgtwindow, insertionPoint);
-              nativeTabInfo = tgttabmail.tabInfo[insertionPoint] ||
-                tgttabmail.tabInfo[tgttabmail.tabInfo.length - 1];
-            }
-            lastInsertion.set(tgtwindow, tabPosition);
-            tabsMoved.push(nativeTabInfo);
-          }
-
-          return tabsMoved.map(nativeTabInfo => tabManager.convert(nativeTabInfo));
-        },
-
-        duplicate(tabId) {
-          let nativeTabInfo = tabTracker.getTab(tabId);
-          let browser = getTabBrowser(nativeTabInfo);
-          let tabmail = browser.ownerDocument.getElementById("tabmail");
-
-          // This is our best approximation of duplicating tabs. It might produce unreliable results
-          let state = tabmail.persistTab(nativeTabInfo);
-          let mode = tabmail.tabModes[state.mode];
-          state.state.duplicate = true;
-
-          if (mode.tabs.length && mode.tabs.length == mode.maxTabs) {
-            throw new ExtensionError(`Maximum number of ${state.mode} tabs reached`);
-          } else {
-            tabmail.restoreTab(state);
-            return tabManager.convert(mode.tabs[mode.tabs.length - 1]);
-          }
-        }
-      }
-    };
-  }
-};
deleted file mode 100644
--- a/mail/components/extensions/parent/ext-windows.js
+++ /dev/null
@@ -1,212 +0,0 @@
-/* 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/. */
-
-// The ext-* files are imported into the same scopes.
-/* import-globals-from ext-mail.js */
-this.windows = class extends ExtensionAPI {
-  getAPI(context) {
-    const { extension } = context;
-    const { windowManager } = extension;
-
-    return {
-      windows: {
-        onCreated: new WindowEventManager(context, "windows.onCreated", "domwindowopened", (fire, window) => {
-          fire.async(windowManager.convert(window));
-        }).api(),
-
-        onRemoved: new WindowEventManager(context, "windows.onRemoved", "domwindowclosed", (fire, window) => {
-          fire.async(windowTracker.getId(window));
-        }).api(),
-
-        onFocusChanged: new EventManager({
-          context,
-          name: "windows.onFocusChanged",
-          register: fire => {
-            // Keep track of the last windowId used to fire an onFocusChanged event
-            let lastOnFocusChangedWindowId;
-
-            let listener = event => {
-              // Wait a tick to avoid firing a superfluous WINDOW_ID_NONE
-              // event when switching focus between two Firefox windows.
-              Promise.resolve().then(() => {
-                let window = Services.focus.activeWindow;
-                let windowId = window ? windowTracker.getId(window) : Window.WINDOW_ID_NONE;
-                if (windowId !== lastOnFocusChangedWindowId) {
-                  fire.async(windowId);
-                  lastOnFocusChangedWindowId = windowId;
-                }
-              });
-            };
-            windowTracker.addListener("focus", listener);
-            windowTracker.addListener("blur", listener);
-            return () => {
-              windowTracker.removeListener("focus", listener);
-              windowTracker.removeListener("blur", listener);
-            };
-          }
-        }).api(),
-
-        get: function(windowId, getInfo) {
-          let window = windowTracker.getWindow(windowId, context);
-          if (!window) {
-            return Promise.reject({ message: `Invalid window ID: ${windowId}` });
-          }
-          return Promise.resolve(windowManager.convert(window, getInfo));
-        },
-
-        getCurrent: function(getInfo) {
-          let window = context.currentWindow || windowTracker.topWindow;
-          return Promise.resolve(windowManager.convert(window, getInfo));
-        },
-
-        getLastFocused: function(getInfo) {
-          let window = windowTracker.topWindow;
-          return Promise.resolve(windowManager.convert(window, getInfo));
-        },
-
-        getAll: function(getInfo) {
-          let doNotCheckTypes = getInfo === null || getInfo.windowTypes === null;
-
-          function typeFilter(win) {
-            return doNotCheckTypes || getInfo.windowTypes.includes(win.type);
-          }
-
-          let windows = Array.from(windowManager.getAll(), win => win.convert(getInfo)).filter(typeFilter);
-          return Promise.resolve(windows);
-        },
-
-        create: function(createData) {
-          let needResize = (createData.left !== null || createData.top !== null ||
-                            createData.width !== null || createData.height !== null);
-
-          if (needResize) {
-            if (createData.state !== null && createData.state != "normal") {
-              return Promise.reject({ message: `"state": "${createData.state}" may not be combined with "left", "top", "width", or "height"` });
-            }
-            createData.state = "normal";
-          }
-
-          let createWindowArgs = (urls) => {
-            let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-            let actionData = {
-              action: "open",
-              tabs: urls.map(url => ({ tabType: "contentTab", tabParams: { contentPage: url } }))
-            };
-            actionData.wrappedJSObject = actionData;
-            args.appendElement(null);
-            args.appendElement(actionData);
-            return args;
-          };
-
-          let window;
-          let wantNormalWindow = createData.type === null || createData.type == "normal";
-          let features = ["chrome"];
-          if (wantNormalWindow) {
-            features.push("dialog=no", "all", "status", "toolbar");
-
-            if (createData.incognito) {
-              // A private mode mail window isn't useful for Thunderbird
-              return Promise.reject({ message: "`incognito` is currently not supported for normal windows" });
-            }
-          } else {
-            // All other types create "popup"-type windows by default.
-            features.push("dialog", "resizable", "minimizable", "centerscreen", "titlebar", "close");
-
-            if (createData.incognito) {
-              features.push("private");
-            }
-          }
-
-          if (createData.tabId !== null) {
-            if (createData.url !== null) {
-              return Promise.reject({ message: "`tabId` may not be used in conjunction with `url`" });
-            }
-
-            if (createData.allowScriptsToClose) {
-              return Promise.reject({ message: "`tabId` may not be used in conjunction with `allowScriptsToClose`" });
-            }
-
-            let nativeTabInfo = tabTracker.getTab(createData.tabId);
-            let tabmail = getTabBrowser(nativeTabInfo).ownerDocument.getElementById("tabmail");
-            let targetType = wantNormalWindow ? null : "popup";
-            window = tabmail.replaceTabWithWindow(nativeTabInfo, targetType)[0];
-          } else if (createData.url !== null) { // eslint-disable-line no-negated-condition
-            let uris = Array.isArray(createData.url) ? createData.url : [createData.url];
-            let args = createWindowArgs(uris);
-            window = Services.ww.openWindow(null, "chrome://messenger/content/", "_blank", features.join(","), args);
-          } else {
-            let args = null;
-            if (!wantNormalWindow) {
-              args = createWindowArgs(["about:blank"]);
-            }
-            window = Services.ww.openWindow(null, "chrome://messenger/content/", "_blank", features.join(","), args);
-          }
-
-          let win = windowManager.getWrapper(window);
-          win.updateGeometry(createData);
-
-          // TODO: focused, type
-
-          return new Promise(resolve => {
-            window.addEventListener("load", () => {
-              resolve();
-            }, { once: true });
-          }).then(() => {
-            if (["minimized", "fullscreen", "docked", "normal", "maximized"].includes(createData.state)) {
-              win.state = createData.state;
-            }
-            return win.convert({ populate: true });
-          });
-        },
-
-        update: function(windowId, updateInfo) {
-          if (updateInfo.state !== null && updateInfo.state != "normal") {
-            if (updateInfo.left !== null || updateInfo.top !== null ||
-                updateInfo.width !== null || updateInfo.height !== null) {
-              return Promise.reject({ message: `"state": "${updateInfo.state}" may not be combined with "left", "top", "width", or "height"` });
-            }
-          }
-
-          let win = windowManager.get(windowId, context);
-          if (updateInfo.focused) {
-            Services.focus.activeWindow = win.window;
-          }
-
-          if (updateInfo.state !== null) {
-            win.state = updateInfo.state;
-          }
-
-          if (updateInfo.drawAttention) {
-            // Bug 1257497 - Firefox can't cancel attention actions.
-            win.window.getAttention();
-          }
-
-          win.updateGeometry(updateInfo);
-
-          if (updateInfo.titlePreface !== null) {
-            win.setTitlePreface(updateInfo.titlePreface);
-            win.window.gBrowser.updateTitlebar();
-          }
-
-          // TODO: All the other properties, focused=false...
-
-          return Promise.resolve(win.convert());
-        },
-
-        remove: function(windowId) {
-          let window = windowTracker.getWindow(windowId, context);
-          window.close();
-
-          return new Promise(resolve => {
-            let listener = () => {
-              windowTracker.removeListener("domwindowclosed", listener);
-              resolve();
-            };
-            windowTracker.addListener("domwindowclosed", listener);
-          });
-        },
-      },
-    };
-  }
-};
deleted file mode 100644
--- a/mail/components/extensions/schemas/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//    * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//    * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//    * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
deleted file mode 100644
--- a/mail/components/extensions/schemas/tabs.json
+++ /dev/null
@@ -1,685 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-[
-  {
-    "namespace": "manifest",
-    "types": [
-      {
-        "$extend": "OptionalPermission",
-        "choices": [{
-          "type": "string",
-          "enum": [
-            "activeTab",
-            "tabs",
-            "tabHide"
-          ]
-        }]
-      }
-    ]
-  },
-  {
-    "namespace": "tabs",
-    "description": "Use the <code>browser.tabs</code> API to interact with the browser's tab system. You can use this API to create, modify, and rearrange tabs in the browser.",
-    "types": [
-      {
-        "id": "Tab",
-        "type": "object",
-        "properties": {
-          "id": {"type": "integer", "minimum": -1, "optional": true, "description": "The ID of the tab. Tab IDs are unique within a browser session. Under some circumstances a Tab may not be assigned an ID, for example when querying foreign tabs using the $(ref:sessions) API, in which case a session ID may be present. Tab ID can also be set to $(ref:tabs.TAB_ID_NONE) for apps and devtools windows."},
-          "index": {"type": "integer", "minimum": -1, "description": "The zero-based index of the tab within its window."},
-          "windowId": {"type": "integer", "optional": true, "minimum": 0, "description": "The ID of the window the tab is contained within."},
-          "selected": {"type": "boolean", "description": "Whether the tab is selected.", "deprecated": "Please use $(ref:tabs.Tab.highlighted).", "unsupported": true},
-          "highlighted": {"type": "boolean", "description": "Whether the tab is highlighted. Works as an alias of active"},
-          "active": {"type": "boolean", "description": "Whether the tab is active in its window. (Does not necessarily mean the window is focused.)"},
-          "lastAccessed": {"type": "integer", "optional": true, "description": "The last time the tab was accessed as the number of milliseconds since epoch."},
-          "url": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The URL the tab is displaying. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission."},
-          "title": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The title of the tab. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission."},
-          "favIconUrl": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The URL of the tab's favicon. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission. It may also be an empty string if the tab is loading."},
-          "status": {"type": "string", "optional": true, "description": "Either <em>loading</em> or <em>complete</em>."},
-          "width": {"type": "integer", "optional": true, "description": "The width of the tab in pixels."},
-          "height": {"type": "integer", "optional": true, "description": "The height of the tab in pixels."}
-        }
-      },
-      {
-        "id": "TabStatus",
-        "type": "string",
-        "enum": ["loading", "complete"],
-        "description": "Whether the tabs have completed loading."
-      },
-      {
-        "id": "WindowType",
-        "type": "string",
-        "enum": ["normal", "popup", "panel", "app", "devtools"],
-        "description": "The type of window."
-      },
-      {
-        "id": "UpdatePropertyName",
-        "type": "string",
-        "enum": [
-          "favIconUrl",
-          "status",
-          "title"
-        ],
-        "description": "Event names supported in onUpdated."
-      },
-      {
-        "id": "UpdateFilter",
-        "type": "object",
-        "description": "An object describing filters to apply to tabs.onUpdated events.",
-        "properties": {
-          "urls": {
-            "type": "array",
-            "description": "A list of URLs or URL patterns. Events that cannot match any of the URLs will be filtered out.  Filtering with urls requires the <code>\"tabs\"</code> or  <code>\"activeTab\"</code> permission.",
-            "optional": true,
-            "items": { "type": "string" },
-            "minItems": 1
-          },
-          "properties": {
-            "type": "array",
-            "optional": true,
-            "description": "A list of property names. Events that do not match any of the names will be filtered out.",
-            "items": { "$ref": "UpdatePropertyName" },
-            "minItems": 1
-          },
-          "tabId": { "type": "integer", "optional": true },
-          "windowId": { "type": "integer", "optional": true }
-        }
-      }
-    ],
-    "properties": {
-      "TAB_ID_NONE": {
-        "value": -1,
-        "description": "An ID which represents the absence of a browser tab."
-      }
-    },
-    "functions": [
-      {
-        "name": "get",
-        "type": "function",
-        "description": "Retrieves details about the specified tab.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "tabId",
-            "minimum": 0
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "parameters": [
-              {"name": "tab", "$ref": "Tab"}
-            ]
-          }
-        ]
-      },
-      {
-        "name": "getCurrent",
-        "type": "function",
-        "description": "Gets the tab that this script call is being made from. May be undefined if called from a non-tab context (for example: a background page or popup view).",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "function",
-            "name": "callback",
-            "parameters": [
-              {
-                "name": "tab",
-                "$ref": "Tab",
-                "optional": true
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "create",
-        "type": "function",
-        "description": "Creates a new tab.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "object",
-            "name": "createProperties",
-            "properties": {
-              "windowId": {
-                "type": "integer",
-                "minimum": -2,
-                "optional": true,
-                "description": "The window to create the new tab in. Defaults to the $(topic:current-window)[current window]."
-              },
-              "index": {
-                "type": "integer",
-                "minimum": 0,
-                "optional": true,
-                "description": "The position the tab should take in the window. The provided value will be clamped to between zero and the number of tabs in the window."
-              },
-              "url": {
-                "type": "string",
-                "optional": true,
-                "description": "The URL to navigate the tab to initially. Fully-qualified URLs must include a scheme (i.e. 'http://www.google.com', not 'www.google.com'). Relative URLs will be relative to the current page within the extension. Defaults to the New Tab Page."
-              },
-              "active": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether the tab should become the active tab in the window. Does not affect whether the window is focused (see $(ref:windows.update)). Defaults to <var>true</var>."
-              },
-              "selected": {
-                "deprecated": "Please use <em>active</em>.",
-                "unsupported": true,
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether the tab should become the selected tab in the window. Defaults to <var>true</var>"
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "parameters": [
-              {
-                "name": "tab",
-                "$ref": "Tab",
-                "optional": true,
-                "description": "Details about the created tab. Will contain the ID of the new tab."
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "duplicate",
-        "type": "function",
-        "description": "Duplicates a tab.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "tabId",
-            "minimum": 0,
-            "description": "The ID of the tab which is to be duplicated."
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "parameters": [
-              {
-                "name": "tab",
-                "optional": true,
-                "description": "Details about the duplicated tab. The $(ref:tabs.Tab) object doesn't contain <code>url</code>, <code>title</code> and <code>favIconUrl</code> if the <code>\"tabs\"</code> permission has not been requested.",
-                "$ref": "Tab"
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "query",
-        "type": "function",
-        "description": "Gets all tabs that have the specified properties, or all tabs if no properties are specified.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "object",
-            "name": "queryInfo",
-            "properties": {
-              "active": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether the tabs are active in their windows."
-              },
-              "highlighted": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether the tabs are highlighted.  Works as an alias of active."
-              },
-              "currentWindow": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether the tabs are in the $(topic:current-window)[current window]."
-              },
-              "lastFocusedWindow": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether the tabs are in the last focused window."
-              },
-              "status": {
-                "$ref": "TabStatus",
-                "optional": true,
-                "description": "Whether the tabs have completed loading."
-              },
-              "title": {
-                "type": "string",
-                "optional": true,
-                "description": "Match page titles against a pattern."
-              },
-              "url": {
-                "choices": [
-                  {"type": "string"},
-                  {"type": "array", "items": {"type": "string"}}
-                ],
-                "optional": true,
-                "description": "Match tabs against one or more $(topic:match_patterns)[URL patterns]. Note that fragment identifiers are not matched."
-              },
-              "windowId": {
-                "type": "integer",
-                "optional": true,
-                "minimum": -2,
-                "description": "The ID of the parent window, or $(ref:windows.WINDOW_ID_CURRENT) for the $(topic:current-window)[current window]."
-              },
-              "windowType": {
-                "$ref": "WindowType",
-                "optional": true,
-                "description": "The type of window the tabs are in."
-              },
-              "index": {
-                "type": "integer",
-                "optional": true,
-                "minimum": 0,
-                "description": "The position of the tabs within their windows."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "parameters": [
-              {
-                "name": "result",
-                "type": "array",
-                "items": {
-                  "$ref": "Tab"
-                }
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "update",
-        "type": "function",
-        "description": "Modifies the properties of a tab. Properties that are not specified in <var>updateProperties</var> are not modified.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "tabId",
-            "minimum": 0,
-            "optional": true,
-            "description": "Defaults to the selected tab of the $(topic:current-window)[current window]."
-          },
-          {
-            "type": "object",
-            "name": "updateProperties",
-            "properties": {
-              "url": {
-                "type": "string",
-                "optional": true,
-                "description": "A URL to navigate the tab to."
-              },
-              "active": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether the tab should be active. Does not affect whether the window is focused (see $(ref:windows.update))."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "parameters": [
-              {
-                "name": "tab",
-                "$ref": "Tab",
-                "optional": true,
-                "description": "Details about the updated tab. The $(ref:tabs.Tab) object doesn't contain <code>url</code>, <code>title</code> and <code>favIconUrl</code> if the <code>\"tabs\"</code> permission has not been requested."
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "move",
-        "type": "function",
-        "description": "Moves one or more tabs to a new position within its window, or to a new window. Note that tabs can only be moved to and from normal (window.type === \"normal\") windows.",
-        "async": "callback",
-        "parameters": [
-          {
-            "name": "tabIds",
-            "description": "The tab or list of tabs to move.",
-            "choices": [
-              {"type": "integer", "minimum": 0},
-              {"type": "array", "items": {"type": "integer", "minimum": 0}}
-            ]
-          },
-          {
-            "type": "object",
-            "name": "moveProperties",
-            "properties": {
-              "windowId": {
-                "type": "integer",
-                "minimum": -2,
-                "optional": true,
-                "description": "Defaults to the window the tab is currently in."
-              },
-              "index": {
-                "type": "integer",
-                "minimum": -1,
-                "description": "The position to move the window to. -1 will place the tab at the end of the window."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "parameters": [
-              {
-                "name": "tabs",
-                "description": "Details about the moved tabs.",
-                "choices": [
-                  {"$ref": "Tab"},
-                  {"type": "array", "items": {"$ref": "Tab"}}
-                ]
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "reload",
-        "type": "function",
-        "description": "Reload a tab.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "tabId",
-            "minimum": 0,
-            "optional": true,
-            "description": "The ID of the tab to reload; defaults to the selected tab of the current window."
-          },
-          {
-            "type": "object",
-            "name": "reloadProperties",
-            "optional": true,
-            "properties": {
-              "bypassCache": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether using any local cache. Default is false."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "parameters": []
-          }
-        ]
-      },
-      {
-        "name": "remove",
-        "type": "function",
-        "description": "Closes one or more tabs.",
-        "async": "callback",
-        "parameters": [
-          {
-            "name": "tabIds",
-            "description": "The tab or list of tabs to close.",
-            "choices": [
-              {"type": "integer", "minimum": 0},
-              {"type": "array", "items": {"type": "integer", "minimum": 0}}
-            ]
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "parameters": []
-          }
-        ]
-      },
-      {
-        "name": "executeScript",
-        "type": "function",
-        "description": "Injects JavaScript code into a page. For details, see the $(topic:content_scripts)[programmatic injection] section of the content scripts doc.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "tabId",
-            "minimum": 0,
-            "optional": true,
-            "description": "The ID of the tab in which to run the script; defaults to the active tab of the current window."
-          },
-          {
-            "$ref": "extensionTypes.InjectDetails",
-            "name": "details",
-            "description": "Details of the script to run."
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "description": "Called after all the JavaScript has been executed.",
-            "parameters": [
-              {
-                "name": "result",
-                "optional": true,
-                "type": "array",
-                "items": {"type": "any"},
-                "description": "The result of the script in every injected frame."
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "insertCSS",
-        "type": "function",
-        "description": "Injects CSS into a page. For details, see the $(topic:content_scripts)[programmatic injection] section of the content scripts doc.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "tabId",
-            "minimum": 0,
-            "optional": true,
-            "description": "The ID of the tab in which to insert the CSS; defaults to the active tab of the current window."
-          },
-          {
-            "$ref": "extensionTypes.InjectDetails",
-            "name": "details",
-            "description": "Details of the CSS text to insert."
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "description": "Called when all the CSS has been inserted.",
-            "parameters": []
-          }
-        ]
-      },
-      {
-        "name": "removeCSS",
-        "type": "function",
-        "description": "Removes injected CSS from a page. For details, see the $(topic:content_scripts)[programmatic injection] section of the content scripts doc.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "tabId",
-            "minimum": 0,
-            "optional": true,
-            "description": "The ID of the tab from which to remove the injected CSS; defaults to the active tab of the current window."
-          },
-          {
-            "$ref": "extensionTypes.InjectDetails",
-            "name": "details",
-            "description": "Details of the CSS text to remove."
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "description": "Called when all the CSS has been removed.",
-            "parameters": []
-          }
-        ]
-      }
-    ],
-    "events": [
-      {
-        "name": "onCreated",
-        "type": "function",
-        "description": "Fired when a tab is created. Note that the tab's URL may not be set at the time this event fired, but you can listen to onUpdated events to be notified when a URL is set.",
-        "parameters": [
-          {
-            "$ref": "Tab",
-            "name": "tab",
-            "description": "Details of the tab that was created."
-          }
-        ]
-      },
-      {
-        "name": "onUpdated",
-        "type": "function",
-        "description": "Fired when a tab is updated.",
-        "parameters": [
-          {"type": "integer", "name": "tabId", "minimum": 0},
-          {
-            "type": "object",
-            "name": "changeInfo",
-            "description": "Lists the changes to the state of the tab that was updated.",
-            "properties": {
-              "status": {
-                "type": "string",
-                "optional": true,
-                "description": "The status of the tab. Can be either <em>loading</em> or <em>complete</em>."
-              },
-              "url": {
-                "type": "string",
-                "optional": true,
-                "description": "The tab's URL if it has changed."
-              },
-              "favIconUrl": {
-                "type": "string",
-                "optional": true,
-                "description": "The tab's new favicon URL."
-              }
-            }
-          },
-          {
-            "$ref": "Tab",
-            "name": "tab",
-            "description": "Gives the state of the tab that was updated."
-          }
-        ],
-        "extraParameters": [
-          {
-            "$ref": "UpdateFilter",
-            "name": "filter",
-            "optional": true,
-            "description": "A set of filters that restricts the events that will be sent to this listener."
-          }
-        ]
-      },
-      {
-        "name": "onMoved",
-        "type": "function",
-        "description": "Fired when a tab is moved within a window. Only one move event is fired, representing the tab the user directly moved. Move events are not fired for the other tabs that must move in response. This event is not fired when a tab is moved between windows. For that, see $(ref:tabs.onDetached).",
-        "parameters": [
-          {"type": "integer", "name": "tabId", "minimum": 0},
-          {
-            "type": "object",
-            "name": "moveInfo",
-            "properties": {
-              "windowId": {"type": "integer", "minimum": 0},
-              "fromIndex": {"type": "integer", "minimum": 0},
-              "toIndex": {"type": "integer", "minimum": 0}
-            }
-          }
-        ]
-      },
-      {
-        "name": "onActivated",
-        "type": "function",
-        "description": "Fires when the active tab in a window changes. Note that the tab's URL may not be set at the time this event fired, but you can listen to onUpdated events to be notified when a URL is set.",
-        "parameters": [
-          {
-            "type": "object",
-            "name": "activeInfo",
-            "properties": {
-              "tabId": {
-                "type": "integer",
-                "minimum": 0,
-                "description": "The ID of the tab that has become active."
-              },
-              "windowId": {
-                "type": "integer",
-                "minimum": 0,
-                "description": "The ID of the window the active tab changed inside of."
-              }
-            }
-          }
-        ]
-      },
-      {
-        "name": "onDetached",
-        "type": "function",
-        "description": "Fired when a tab is detached from a window, for example because it is being moved between windows.",
-        "parameters": [
-          {"type": "integer", "name": "tabId", "minimum": 0},
-          {
-            "type": "object",
-            "name": "detachInfo",
-            "properties": {
-              "oldWindowId": {"type": "integer", "minimum": 0},
-              "oldPosition": {"type": "integer", "minimum": 0}
-            }
-          }
-        ]
-      },
-      {
-        "name": "onAttached",
-        "type": "function",
-        "description": "Fired when a tab is attached to a window, for example because it was moved between windows.",
-        "parameters": [
-          {"type": "integer", "name": "tabId", "minimum": 0},
-          {
-            "type": "object",
-            "name": "attachInfo",
-            "properties": {
-              "newWindowId": {"type": "integer", "minimum": 0},
-              "newPosition": {"type": "integer", "minimum": 0}
-            }
-          }
-        ]
-      },
-      {
-        "name": "onRemoved",
-        "type": "function",
-        "description": "Fired when a tab is closed.",
-        "parameters": [
-          {"type": "integer", "name": "tabId", "minimum": 0},
-          {
-            "type": "object",
-            "name": "removeInfo",
-            "properties": {
-              "windowId": {"type": "integer", "minimum": 0, "description": "The window whose tab is closed." },
-              "isWindowClosing": {"type": "boolean", "description": "True when the tab is being closed because its window is being closed." }
-            }
-          }
-        ]
-      }
-    ]
-  }
-]
deleted file mode 100644
--- a/mail/components/extensions/schemas/windows.json
+++ /dev/null
@@ -1,523 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-[
-  {
-    "namespace": "windows",
-    "description": "Use the <code>browser.windows</code> API to interact with browser windows. You can use this API to create, modify, and rearrange windows in the browser.",
-    "types": [
-      {
-        "id": "WindowType",
-        "type": "string",
-        "description": "The type of browser window this is. Under some circumstances a Window may not be assigned type property, for example when querying closed windows from the $(ref:sessions) API.",
-        "enum": ["normal", "popup", "panel", "app", "devtools"]
-      },
-      {
-        "id": "WindowState",
-        "type": "string",
-        "description": "The state of this browser window. Under some circumstances a Window may not be assigned state property, for example when querying closed windows from the $(ref:sessions) API.",
-        "enum": ["normal", "minimized", "maximized", "fullscreen", "docked"]
-      },
-      {
-        "id": "Window",
-        "type": "object",
-        "properties": {
-          "id": {
-            "type": "integer",
-            "optional": true,
-            "minimum": 0,
-            "description": "The ID of the window. Window IDs are unique within a browser session. Under some circumstances a Window may not be assigned an ID, for example when querying windows using the $(ref:sessions) API, in which case a session ID may be present."
-          },
-          "focused": {
-            "type": "boolean",
-            "description": "Whether the window is currently the focused window."
-          },
-          "top": {
-            "type": "integer",
-            "optional": true,
-            "description": "The offset of the window from the top edge of the screen in pixels. Under some circumstances a Window may not be assigned top property, for example when querying closed windows from the $(ref:sessions) API."
-          },
-          "left": {
-            "type": "integer",
-            "optional": true,
-            "description": "The offset of the window from the left edge of the screen in pixels. Under some circumstances a Window may not be assigned left property, for example when querying closed windows from the $(ref:sessions) API."
-          },
-          "width": {
-            "type": "integer",
-            "optional": true,
-            "description": "The width of the window, including the frame, in pixels. Under some circumstances a Window may not be assigned width property, for example when querying closed windows from the $(ref:sessions) API."
-          },
-          "height": {
-            "type": "integer",
-            "optional": true,
-            "description": "The height of the window, including the frame, in pixels. Under some circumstances a Window may not be assigned height property, for example when querying closed windows from the $(ref:sessions) API."
-          },
-          "tabs": {
-            "type": "array",
-            "items": { "$ref": "tabs.Tab" },
-            "optional": true,
-            "description": "Array of $(ref:tabs.Tab) objects representing the current tabs in the window."
-          },
-          "incognito": {
-            "type": "boolean",
-            "description": "Whether the window is incognito."
-          },
-          "type": {
-            "$ref": "WindowType",
-            "optional": true,
-            "description": "The type of browser window this is."
-          },
-          "state": {
-            "$ref": "WindowState",
-            "optional": true,
-            "description": "The state of this browser window."
-          },
-          "alwaysOnTop": {
-            "type": "boolean",
-            "description": "Whether the window is set to be always on top."
-          },
-          "sessionId": {
-            "type": "string",
-            "optional": true,
-            "description": "The session ID used to uniquely identify a Window obtained from the $(ref:sessions) API."
-          },
-          "title": {
-            "type": "string",
-            "optional": true,
-            "description": "The title of the window. Read-only."
-          }
-        }
-      },
-      {
-        "id": "CreateType",
-        "type": "string",
-        "description": "Specifies what type of browser window to create. The 'panel' and 'detached_panel' types create a popup unless the '--enable-panels' flag is set.",
-        "enum": ["normal", "popup", "panel", "detached_panel"]
-      }
-    ],
-    "properties": {
-      "WINDOW_ID_NONE": {
-        "value": -1,
-        "description": "The windowId value that represents the absence of a browser window."
-      },
-      "WINDOW_ID_CURRENT": {
-        "value": -2,
-        "description": "The windowId value that represents the $(topic:current-window)[current window]."
-      }
-    },
-    "functions": [
-      {
-        "name": "get",
-        "type": "function",
-        "description": "Gets details about a window.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "windowId",
-            "minimum": -2
-          },
-          {
-            "type": "object",
-            "name": "getInfo",
-            "optional": true,
-            "description": "",
-            "properties": {
-              "populate": {
-                "type": "boolean",
-                "optional": true,
-                "description": "If true, the $(ref:windows.Window) object will have a <var>tabs</var> property that contains a list of the $(ref:tabs.Tab) objects. The <code>Tab</code> objects only contain the <code>url</code>, <code>title</code> and <code>favIconUrl</code> properties if the extension's manifest file includes the <code>\"tabs\"</code> permission."
-              },
-              "windowTypes": {
-                "type": "array",
-                "items": {
-                  "$ref": "WindowType"
-                },
-                "optional": true,
-                "description": "If set, the $(ref:windows.Window) returned will be filtered based on its type. If unset the default filter is set to <code>['app', 'normal', 'panel', 'popup']</code>, with <code>'app'</code> and <code>'panel'</code> window types limited to the extension's own windows."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "parameters": [
-              {
-                "name": "window",
-                "$ref": "Window"
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "getCurrent",
-        "type": "function",
-        "description": "Gets the $(topic:current-window)[current window].",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "object",
-            "name": "getInfo",
-            "optional": true,
-            "description": "",
-            "properties": {
-              "populate": {
-                "type": "boolean",
-                "optional": true,
-                "description": "If true, the $(ref:windows.Window) object will have a <var>tabs</var> property that contains a list of the $(ref:tabs.Tab) objects. The <code>Tab</code> objects only contain the <code>url</code>, <code>title</code> and <code>favIconUrl</code> properties if the extension's manifest file includes the <code>\"tabs\"</code> permission."
-              },
-              "windowTypes": {
-                "type": "array",
-                "items": { "$ref": "WindowType" },
-                "optional": true,
-                "description": "If set, the $(ref:windows.Window) returned will be filtered based on its type. If unset the default filter is set to <code>['app', 'normal', 'panel', 'popup']</code>, with <code>'app'</code> and <code>'panel'</code> window types limited to the extension's own windows."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "parameters": [
-              {
-                "name": "window",
-                "$ref": "Window"
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "getLastFocused",
-        "type": "function",
-        "description": "Gets the window that was most recently focused &mdash; typically the window 'on top'.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "object",
-            "name": "getInfo",
-            "optional": true,
-            "description": "",
-            "properties": {
-              "populate": {
-                "type": "boolean",
-                "optional": true,
-                "description": "If true, the $(ref:windows.Window) object will have a <var>tabs</var> property that contains a list of the $(ref:tabs.Tab) objects. The <code>Tab</code> objects only contain the <code>url</code>, <code>title</code> and <code>favIconUrl</code> properties if the extension's manifest file includes the <code>\"tabs\"</code> permission."
-              },
-              "windowTypes": {
-                "type": "array",
-                "items": { "$ref": "WindowType" },
-                "optional": true,
-                "description": "If set, the $(ref:windows.Window) returned will be filtered based on its type. If unset the default filter is set to <code>['app', 'normal', 'panel', 'popup']</code>, with <code>'app'</code> and <code>'panel'</code> window types limited to the extension's own windows."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "parameters": [
-              {
-                "name": "window",
-                "$ref": "Window"
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "getAll",
-        "type": "function",
-        "description": "Gets all windows.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "object",
-            "name": "getInfo",
-            "optional": true,
-            "description": "",
-            "properties": {
-              "populate": {
-                "type": "boolean",
-                "optional": true,
-                "description": "If true, each $(ref:windows.Window) object will have a <var>tabs</var> property that contains a list of the $(ref:tabs.Tab) objects for that window. The <code>Tab</code> objects only contain the <code>url</code>, <code>title</code> and <code>favIconUrl</code> properties if the extension's manifest file includes the <code>\"tabs\"</code> permission."
-              },
-              "windowTypes": {
-                "type": "array",
-                "items": { "$ref": "WindowType" },
-                "optional": true,
-                "description": "If set, the $(ref:windows.Window) returned will be filtered based on its type. If unset the default filter is set to <code>['app', 'normal', 'panel', 'popup']</code>, with <code>'app'</code> and <code>'panel'</code> window types limited to the extension's own windows."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "parameters": [
-              {
-                "name": "windows",
-                "type": "array",
-                "items": { "$ref": "Window" }
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "create",
-        "type": "function",
-        "description": "Creates (opens) a new browser with any optional sizing, position or default URL provided.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "object",
-            "name": "createData",
-            "optional": true,
-            "default": {},
-            "properties": {
-              "url": {
-                "description": "A URL or array of URLs to open as tabs in the window. Fully-qualified URLs must include a scheme (i.e. 'http://www.google.com', not 'www.google.com'). Relative URLs will be relative to the current page within the extension. Defaults to the New Tab Page.",
-                "optional": true,
-                "choices": [
-                  { "type": "string", "format": "relativeUrl" },
-                  {
-                    "type": "array",
-                    "items": { "type": "string", "format": "relativeUrl" }
-                  }
-                ]
-              },
-              "tabId": {
-                "type": "integer",
-                "minimum": 0,
-                "optional": true,
-                "description": "The id of the tab for which you want to adopt to the new window."
-              },
-              "left": {
-                "type": "integer",
-                "optional": true,
-                "description": "The number of pixels to position the new window from the left edge of the screen. If not specified, the new window is offset naturally from the last focused window. This value is ignored for panels."
-              },
-              "top": {
-                "type": "integer",
-                "optional": true,
-                "description": "The number of pixels to position the new window from the top edge of the screen. If not specified, the new window is offset naturally from the last focused window. This value is ignored for panels."
-              },
-              "width": {
-                "type": "integer",
-                "minimum": 0,
-                "optional": true,
-                "description": "The width in pixels of the new window, including the frame. If not specified defaults to a natural width."
-              },
-              "height": {
-                "type": "integer",
-                "minimum": 0,
-                "optional": true,
-                "description": "The height in pixels of the new window, including the frame. If not specified defaults to a natural height."
-              },
-              "focused": {
-                "unsupported": true,
-                "type": "boolean",
-                "optional": true,
-                "description": "If true, opens an active window. If false, opens an inactive window."
-              },
-              "incognito": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Whether the new window should be an incognito window."
-              },
-              "type": {
-                "$ref": "CreateType",
-                "optional": true,
-                "description": "Specifies what type of browser window to create. The 'panel' and 'detached_panel' types create a popup unless the '--enable-panels' flag is set."
-              },
-              "state": {
-                "$ref": "WindowState",
-                "optional": true,
-                "description": "The initial state of the window. The 'minimized', 'maximized' and 'fullscreen' states cannot be combined with 'left', 'top', 'width' or 'height'."
-              },
-              "allowScriptsToClose": {
-                "type": "boolean",
-                "optional": true,
-                "description": "Allow scripts to close the window."
-              },
-              "titlePreface": {
-                "type": "string",
-                "optional": true,
-                "description": "A string to add to the beginning of the window title."
-              }
-            },
-            "optional": true
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "parameters": [
-              {
-                "name": "window",
-                "$ref": "Window",
-                "description": "Contains details about the created window.",
-                "optional": true
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "update",
-        "type": "function",
-        "description": "Updates the properties of a window. Specify only the properties that you want to change; unspecified properties will be left unchanged.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "windowId",
-            "minimum": -2
-          },
-          {
-            "type": "object",
-            "name": "updateInfo",
-            "properties": {
-              "left": {
-                "type": "integer",
-                "optional": true,
-                "description": "The offset from the left edge of the screen to move the window to in pixels. This value is ignored for panels."
-              },
-              "top": {
-                "type": "integer",
-                "optional": true,
-                "description": "The offset from the top edge of the screen to move the window to in pixels. This value is ignored for panels."
-              },
-              "width": {
-                "type": "integer",
-                "minimum": 0,
-                "optional": true,
-                "description": "The width to resize the window to in pixels. This value is ignored for panels."
-              },
-              "height": {
-                "type": "integer",
-                "minimum": 0,
-                "optional": true,
-                "description": "The height to resize the window to in pixels. This value is ignored for panels."
-              },
-              "focused": {
-                "type": "boolean",
-                "optional": true,
-                "description": "If true, brings the window to the front. If false, brings the next window in the z-order to the front."
-              },
-              "drawAttention": {
-                "type": "boolean",
-                "optional": true,
-                "description": "If true, causes the window to be displayed in a manner that draws the user's attention to the window, without changing the focused window. The effect lasts until the user changes focus to the window. This option has no effect if the window already has focus. Set to false to cancel a previous draw attention request."
-              },
-              "state": {
-                "$ref": "WindowState",
-                "optional": true,
-                "description": "The new state of the window. The 'minimized', 'maximized' and 'fullscreen' states cannot be combined with 'left', 'top', 'width' or 'height'."
-              },
-              "titlePreface": {
-                "type": "string",
-                "optional": true,
-                "description": "A string to add to the beginning of the window title."
-              }
-            }
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "parameters": [
-              {
-                "name": "window",
-                "$ref": "Window"
-              }
-            ]
-          }
-        ]
-      },
-      {
-        "name": "remove",
-        "type": "function",
-        "description": "Removes (closes) a window, and all the tabs inside it.",
-        "async": "callback",
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "windowId",
-            "minimum": 0
-          },
-          {
-            "type": "function",
-            "name": "callback",
-            "optional": true,
-            "parameters": []
-          }
-        ]
-      }
-    ],
-    "events": [
-      {
-        "name": "onCreated",
-        "type": "function",
-        "description": "Fired when a window is created.",
-        "filters": [
-          {
-            "name": "windowTypes",
-            "type": "array",
-            "items": { "$ref": "WindowType" },
-            "description": "Conditions that the window's type being created must satisfy. By default it will satisfy <code>['app', 'normal', 'panel', 'popup']</code>, with <code>'app'</code> and <code>'panel'</code> window types limited to the extension's own windows."
-          }
-        ],
-        "parameters": [
-          {
-            "$ref": "Window",
-            "name": "window",
-            "description": "Details of the window that was created."
-          }
-        ]
-      },
-      {
-        "name": "onRemoved",
-        "type": "function",
-        "description": "Fired when a window is removed (closed).",
-        "filters": [
-          {
-            "name": "windowTypes",
-            "type": "array",
-            "items": { "$ref": "WindowType" },
-            "description": "Conditions that the window's type being removed must satisfy. By default it will satisfy <code>['app', 'normal', 'panel', 'popup']</code>, with <code>'app'</code> and <code>'panel'</code> window types limited to the extension's own windows."
-          }
-        ],
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "windowId",
-            "minimum": 0,
-            "description": "ID of the removed window."
-          }
-        ]
-      },
-      {
-        "name": "onFocusChanged",
-        "type": "function",
-        "description": "Fired when the currently focused window changes. Will be $(ref:windows.WINDOW_ID_NONE) if all browser windows have lost focus. Note: On some Linux window managers, WINDOW_ID_NONE will always be sent immediately preceding a switch from one browser window to another.",
-        "filters": [
-          {
-            "name": "windowTypes",
-            "type": "array",
-            "items": { "$ref": "WindowType" },
-            "description": "Conditions that the window's type being removed must satisfy. By default it will satisfy <code>['app', 'normal', 'panel', 'popup']</code>, with <code>'app'</code> and <code>'panel'</code> window types limited to the extension's own windows."
-          }
-        ],
-        "parameters": [
-          {
-            "type": "integer",
-            "name": "windowId",
-            "minimum": -1,
-            "description": "ID of the newly focused window."
-          }
-        ]
-      }
-    ]
-  }
-]
--- a/mail/components/moz.build
+++ b/mail/components/moz.build
@@ -5,17 +5,16 @@
 
 # Only Mac and Windows have search integration components, but we include at
 # least one module from search/ on all platforms
 DIRS += [
     'compose',
     'cloudfile',
     'devtools',
     'downloads',
-    'extensions',
     'preferences',
     'addrbook',
     'migration',
     'activity',
     'search',
     'about-support',
     'accountcreation',
     'wintaskbar',
--- a/mail/installer/package-manifest.in
+++ b/mail/installer/package-manifest.in
@@ -570,17 +570,16 @@
 @RESPATH@/contentaccessible/*
 
 ; svg
 @RESPATH@/res/svg.css
 
 ; [Extensions]
 @RESPATH@/components/extensions-toolkit.manifest
 @RESPATH@/components/extension-process-script.js
-@RESPATH@/components/extensions-mail.manifest
 
 ; [Personal Security Manager]
 ;
 ; NSS libraries are signed in the staging directory,
 ; meaning their .chk files are created there directly.
 ;
 #ifndef MOZ_SYSTEM_NSS
 #if defined(XP_LINUX) && !defined(ANDROID)