Bug 1772390 - imServices.jsm should not export Services. r=freaktechnik
authorMagnus Melin <mkmelin+mozilla@iki.fi>
Fri, 03 Jun 2022 14:52:15 +0300
changeset 35926 4bbe7e059e02d5a56233e3e46ef2d62175a57ead
parent 35925 7046afea472079e7ec8ef5c399d6c51ba35859b6
child 35927 bb1203b11cbd38c4f760b5705786d2cd6fd2d759
push id19987
push usermkmelin@iki.fi
push dateFri, 03 Jun 2022 19:50:20 +0000
treeherdercomm-central@4bbe7e059e02 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfreaktechnik
bugs1772390
Bug 1772390 - imServices.jsm should not export Services. r=freaktechnik * Make imServices.jsm export IMServices * hg mv ./chat/modules/imServices.jsm ./chat/modules/IMServices.js * global rewrite grep --exclude-dir=.hg --exclude-dir=suite -rl '{ Services } = ChromeUtils.import("resource:///modules/imServices.jsm");' | xargs sed -i -E 's#(var|const) \{ Services \} = ChromeUtils.import\("resource:///modules/imServices.jsm"\);#\1 { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");\1 { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");#g' * Fix stray cases of imServices.jsm imported as something else * rewrite callers grep --exclude-dir=.hg --exclude-dir=suite -rEl "\b(Services.accounts.|Services.core.|Services.cmd.|Services.contacts|Services.conversations|Services.tags.|Services.logs.)" | xargs sed -i -E 's/\b(Services.accounts.|Services.core.|Services.cmd.|Services.contacts|Services.conversations|Services.tags.|Services.logs.)/IM\1/g' * linting Differential Revision: https://phabricator.services.mozilla.com/D148258
chat/components/public/imILogger.idl
chat/components/src/imAccounts.jsm
chat/components/src/imCommands.jsm
chat/components/src/imContacts.jsm
chat/components/src/imConversations.jsm
chat/components/src/imCore.jsm
chat/components/src/logger.jsm
chat/components/src/test/test_accounts.js
chat/components/src/test/test_commands.js
chat/components/src/test/test_conversations.js
chat/components/src/test/test_logger.js
chat/content/chat-tooltip.js
chat/content/otr-auth.js
chat/content/otr-finger.js
chat/modules/CLib.jsm
chat/modules/IMServices.jsm
chat/modules/InteractiveBrowser.jsm
chat/modules/OTR.jsm
chat/modules/OTRUI.jsm
chat/modules/imContentSink.jsm
chat/modules/imServices.jsm
chat/modules/imSmileys.jsm
chat/modules/imTextboxUtils.jsm
chat/modules/imThemes.jsm
chat/modules/imXPCOMUtils.jsm
chat/modules/jsProtoHelper.jsm
chat/modules/moz.build
chat/modules/test/test_filtering.js
chat/protocols/irc/irc.jsm
chat/protocols/irc/ircCTCP.jsm
chat/protocols/irc/ircCommands.jsm
chat/protocols/irc/test/test_ircCommands.js
chat/protocols/irc/test/test_sendBufferedCommand.js
chat/protocols/irc/test/test_setMode.js
chat/protocols/matrix/matrix.jsm
chat/protocols/matrix/test/head.js
chat/protocols/matrix/test/test_matrixAccount.js
chat/protocols/matrix/test/test_matrixRoom.js
chat/protocols/xmpp/xmpp-base.jsm
chat/protocols/xmpp/xmpp-session.jsm
mail/components/about-support/content/chat.js
mail/components/im/IMIncomingServer.jsm
mail/components/im/content/addbuddy.js
mail/components/im/content/chat-contact.js
mail/components/im/content/chat-conversation-info.js
mail/components/im/content/chat-conversation.js
mail/components/im/content/chat-messenger.js
mail/components/im/content/imAccountWizard.js
mail/components/im/content/imAccounts.js
mail/components/im/content/imStatusSelector.js
mail/components/im/content/joinchat.js
mail/components/im/modules/chatHandler.jsm
mail/components/im/modules/chatNotifications.jsm
mail/components/im/modules/index_im.jsm
mail/components/im/test/TestProtocol.jsm
mail/components/im/test/browser/browser_chatTelemetry.js
mail/components/im/test/browser/browser_contextMenu.js
mail/components/im/test/browser/browser_logs.js
mail/components/im/test/browser/browser_messagesMail.js
mail/components/im/test/browser/browser_readMessage.js
mail/components/im/test/browser/browser_removeMessage.js
mail/components/im/test/browser/browser_requestNotifications.js
mail/components/im/test/browser/browser_spacesToolbarChat.js
mail/components/im/test/browser/browser_tooltips.js
mail/components/im/test/browser/browser_updateMessage.js
mail/components/im/test/browser/head.js
mail/components/preferences/messagestyle.js
mail/test/browser/account/browser_accountTelemetry.js
mail/test/browser/im/browser_toolbarButtons.js
--- a/chat/components/public/imILogger.idl
+++ b/chat/components/public/imILogger.idl
@@ -17,17 +17,17 @@ interface imILogConversation: nsISupport
   readonly attribute AUTF8String title;
   readonly attribute AUTF8String name;
   // Value in microseconds.
   readonly attribute PRTime startDate;
 
   // Simplified account implementation:
   //  - alias will always be empty
   //  - name (always the normalizedName)
-  //  - statusInfo will return Services.core.globalUserStatus
+  //  - statusInfo will return IMServices.core.globalUserStatus
   //  - protocol will only contain a "name" attribute, with the prpl's normalized name.
   // Other methods/attributes aren't implemented.
   readonly attribute imIAccount account;
 
   readonly attribute boolean isChat; // always false (compatibility with prplIConversation).
   readonly attribute prplIAccountBuddy buddy; // always null (compatibility with prplIConvIM).
 
   Array<imIMessage> getMessages();
--- a/chat/components/src/imAccounts.jsm
+++ b/chat/components/src/imAccounts.jsm
@@ -5,17 +5,18 @@
 var EXPORTED_SYMBOLS = ["AccountsService"];
 
 const { clearTimeout, setTimeout } = ChromeUtils.import(
   "resource://gre/modules/Timer.jsm"
 );
 var { ClassInfo, XPCOMUtils, executeSoon, l10nHelper } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var {
   GenericAccountPrototype,
   GenericAccountBuddyPrototype,
 } = ChromeUtils.import("resource:///modules/jsProtoHelper.jsm");
 ChromeUtils.defineModuleGetter(
   this,
   "MailServices",
   "resource:///modules/MailServices.jsm"
@@ -187,25 +188,25 @@ function imAccount(aKey, aName, aPrplId)
   let prplId = aPrplId;
   if (prplId) {
     this.prefBranch.setCharPref(kPrefAccountPrpl, prplId);
   } else {
     prplId = this.prefBranch.getCharPref(kPrefAccountPrpl);
   }
 
   // Get the protocol plugin, or fallback to an UnknownProtocol instance.
-  this.protocol = Services.core.getProtocolById(prplId);
+  this.protocol = IMServices.core.getProtocolById(prplId);
   if (!this.protocol) {
     this.protocol = new UnknownProtocol(prplId);
     this._connectionErrorReason = Ci.imIAccount.ERROR_UNKNOWN_PRPL;
     return;
   }
 
   // Ensure the account is correctly stored in blist.sqlite.
-  Services.contacts.storeAccount(this.numericId, this.name, prplId);
+  IMServices.contacts.storeAccount(this.numericId, this.name, prplId);
 
   // Get the prplIAccount from the protocol plugin.
   this.prplAccount = this.protocol.getAccount(this);
 
   // Send status change notifications to the account.
   this.observedStatusInfo = null; // (To execute the setter).
 
   // If we have never finished the first connection attempt for this account,
@@ -431,17 +432,17 @@ imAccount.prototype = {
   },
   _removeStatusObserver() {
     if (this._statusObserver) {
       this.statusInfo.removeObserver(this._statusObserver);
       delete this._statusObserver;
     }
   },
   get statusInfo() {
-    return this._observedStatusInfo || Services.core.globalUserStatus;
+    return this._observedStatusInfo || IMServices.core.globalUserStatus;
   },
 
   reconnectAttempt: 0,
   timeOfLastConnect: 0,
   timeOfNextReconnect: 0,
   _reconnectTimer: null,
   _startReconnectTimer() {
     if (Services.io.offline) {
@@ -744,17 +745,17 @@ imAccount.prototype = {
     }
     if (this.connected || this.connecting) {
       this.disconnect();
     }
     if (this.prplAccount) {
       this.prplAccount.remove();
     }
     this.unInit();
-    Services.contacts.forgetAccount(this.numericId);
+    IMServices.contacts.forgetAccount(this.numericId);
     for (let prefName of this.prefBranch.getChildList("")) {
       this.prefBranch.clearUserPref(prefName);
     }
   },
   unInit() {
     // remove any pending reconnection timer.
     this._cancelReconnection();
 
@@ -1176,17 +1177,17 @@ AccountsService.prototype = {
     return this._accountsById[aAccountId];
   },
   getAccounts() {
     return this._accounts;
   },
 
   createAccount(aName, aPrpl) {
     // Ensure an account with the same name and protocol doesn't already exist.
-    let prpl = Services.core.getProtocolById(aPrpl);
+    let prpl = IMServices.core.getProtocolById(aPrpl);
     if (!prpl) {
       throw Components.Exception("", Cr.NS_ERROR_UNEXPECTED);
     }
     if (prpl.accountExists(aName)) {
       Cu.reportError("Attempted to create a duplicate account!");
       throw Components.Exception("", Cr.NS_ERROR_ALREADY_INITIALIZED);
     }
 
@@ -1195,17 +1196,17 @@ AccountsService.prototype = {
     for (id = 1; ; ++id) {
       if (this._accountsById.hasOwnProperty(id)) {
         continue;
       }
 
       /* id isn't used by a known account, double check it isn't
        already used in the sqlite database. This should never
        happen, except if we have a corrupted profile. */
-      if (!Services.contacts.accountIdExists(id)) {
+      if (!IMServices.contacts.accountIdExists(id)) {
         break;
       }
       Services.console.logStringMessage(
         "No account " +
           id +
           " but there is some data in the buddy list for an account with this number. Your profile may be corrupted."
       );
     }
--- a/chat/components/src/imCommands.jsm
+++ b/chat/components/src/imCommands.jsm
@@ -1,15 +1,15 @@
 /* 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/. */
 
 var EXPORTED_SYMBOLS = ["CommandsService"];
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { XPCOMUtils, l10nHelper } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
 
 XPCOMUtils.defineLazyGetter(this, "_", () =>
   l10nHelper("chrome://chat/locale/commands.properties")
 );
 
@@ -35,17 +35,17 @@ CommandsService.prototype = {
     this.registerCommand({
       name: "raw",
       get helpString() {
         return _("rawHelpString");
       },
       usageContext: Ci.imICommand.CMD_CONTEXT_ALL,
       priority: Ci.imICommand.CMD_PRIORITY_DEFAULT,
       run(aMsg, aConv) {
-        let conv = Services.conversations.getUIConversation(aConv);
+        let conv = IMServices.conversations.getUIConversation(aConv);
         if (!conv) {
           return false;
         }
         conv.sendMsg(aMsg);
         return true;
       },
     });
 
@@ -57,17 +57,17 @@ CommandsService.prototype = {
       name: "help",
       get helpString() {
         return _("helpHelpString");
       },
       usageContext: Ci.imICommand.CMD_CONTEXT_ALL,
       priority: Ci.imICommand.CMD_PRIORITY_DEFAULT,
       run(aMsg, aConv) {
         aMsg = aMsg.trim();
-        let conv = Services.conversations.getUIConversation(aConv);
+        let conv = IMServices.conversations.getUIConversation(aConv);
         if (!conv) {
           return false;
         }
 
         // Handle when no command is given, list all possible commands that are
         // available for this conversation (alphabetically).
         if (!aMsg) {
           let commands = this.cmdSrv.listCommandsForConversation(aConv);
@@ -124,17 +124,17 @@ CommandsService.prototype = {
       this.registerCommand({
         name: cmd,
         get helpString() {
           return _("statusCommand", this.name, _(this.name));
         },
         usageContext: Ci.imICommand.CMD_CONTEXT_ALL,
         priority: Ci.imICommand.CMD_PRIORITY_HIGH,
         run(aMsg) {
-          Services.core.globalUserStatus.setStatus(statusValue, aMsg);
+          IMServices.core.globalUserStatus.setStatus(statusValue, aMsg);
           return true;
         },
       });
     }
   },
   unInitCommands() {
     delete this._commands;
   },
--- a/chat/components/src/imContacts.jsm
+++ b/chat/components/src/imContacts.jsm
@@ -1,15 +1,16 @@
 /* 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/. */
 
 var EXPORTED_SYMBOLS = ["TagsService", "ContactsService"];
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { XPCOMUtils, executeSoon, ClassInfo, l10nHelper } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
 
 XPCOMUtils.defineLazyGetter(this, "_", () =>
   l10nHelper("chrome://chat/locale/contacts.properties")
 );
 
@@ -973,17 +974,17 @@ Contact.prototype = {
   get canSendMessage() {
     return this.preferredBuddy.canSendMessage;
   },
   // XXX should we list the buddies in the tooltip?
   getTooltipInfo() {
     return this.preferredBuddy.getTooltipInfo();
   },
   createConversation() {
-    let uiConv = Services.conversations.getUIConversationByContactId(this.id);
+    let uiConv = IMServices.conversations.getUIConversationByContactId(this.id);
     if (uiConv) {
       return uiConv.target;
     }
     return this.preferredBuddy.createConversation();
   },
 
   addObserver(aObserver) {
     if (!this._observers.includes(aObserver)) {
@@ -1535,17 +1536,17 @@ ContactsService.prototype = {
               ", buddy_id = " +
               buddyId +
               ", tag_id = " +
               tagId
           );
           continue;
         }
 
-        let account = Services.accounts.getAccountByNumericId(accountId);
+        let account = IMServices.accounts.getAccountByNumericId(accountId);
         let tag = TagsById[tagId];
         try {
           buddy._addAccount(account.loadBuddy(buddy, tag), tag);
         } catch (e) {
           Cu.reportError(e);
           dump(e + "\n");
         }
       }
--- a/chat/components/src/imConversations.jsm
+++ b/chat/components/src/imConversations.jsm
@@ -1,15 +1,15 @@
 /* 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/. */
 
 var EXPORTED_SYMBOLS = ["ConversationsService", "imMessage", "UIConversation"];
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 var { Status } = ChromeUtils.import("resource:///modules/imStatusUtils.jsm");
 var { XPCOMUtils, ClassInfo } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
 var { Message } = ChromeUtils.import("resource:///modules/jsProtoHelper.jsm");
 
 var gLastUIConvId = 0;
 var gLastPrplConvId = 0;
--- a/chat/components/src/imCore.jsm
+++ b/chat/components/src/imCore.jsm
@@ -1,15 +1,16 @@
 /* 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/. */
 
 var EXPORTED_SYMBOLS = ["CoreService"];
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { ClassInfo, initLogModule } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
 
 var kQuitApplicationGranted = "quit-application-granted";
 var kProtocolPluginCategory = "im-protocol-plugin";
 
 var kPrefReportIdle = "messenger.status.reportIdle";
@@ -278,57 +279,57 @@ CoreService.prototype = {
       return;
     }
 
     initLogModule("core", this);
 
     Services.obs.addObserver(this, kQuitApplicationGranted);
     this._initialized = true;
 
-    Services.cmd.initCommands();
+    IMServices.cmd.initCommands();
     this._protos = {};
 
     this.globalUserStatus = new UserStatus();
     this.globalUserStatus.addObserver({
       observe(aSubject, aTopic, aData) {
         Services.obs.notifyObservers(aSubject, aTopic, aData);
       },
     });
 
-    let accounts = Services.accounts;
+    let accounts = IMServices.accounts;
     accounts.initAccounts();
-    Services.contacts.initContacts();
-    Services.conversations.initConversations();
+    IMServices.contacts.initContacts();
+    IMServices.conversations.initConversations();
     Services.obs.notifyObservers(this, "prpl-init");
 
     // Wait with automatic connections until the password service
     // is available.
     if (accounts.autoLoginStatus == Ci.imIAccountsService.AUTOLOGIN_ENABLED) {
       Services.logins.initializationPromise.then(() => {
-        Services.accounts.processAutoLogin();
+        IMServices.accounts.processAutoLogin();
       });
     }
   },
   observe(aObject, aTopic, aData) {
     if (aTopic == kQuitApplicationGranted) {
       this.quit();
     }
   },
   quit() {
     if (!this._initialized) {
       throw Components.Exception("", Cr.NS_ERROR_NOT_INITIALIZED);
     }
 
     Services.obs.removeObserver(this, kQuitApplicationGranted);
     Services.obs.notifyObservers(this, "prpl-quit");
 
-    Services.conversations.unInitConversations();
-    Services.accounts.unInitAccounts();
-    Services.contacts.unInitContacts();
-    Services.cmd.unInitCommands();
+    IMServices.conversations.unInitConversations();
+    IMServices.accounts.unInitAccounts();
+    IMServices.contacts.unInitContacts();
+    IMServices.cmd.unInitCommands();
 
     this.globalUserStatus.unInit();
     delete this.globalUserStatus;
     delete this._protos;
     delete this._initialized;
   },
 
   getProtocols() {
--- a/chat/components/src/logger.jsm
+++ b/chat/components/src/logger.jsm
@@ -1,15 +1,16 @@
 /* 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/. */
 
 var EXPORTED_SYMBOLS = ["Logger"];
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   ClassInfo: "resource:///modules/imXPCOMUtils.jsm",
   GenericMessagePrototype: "resource:///modules/jsProtoHelper.jsm",
   l10nHelper: "resource:///modules/imXPCOMUtils.jsm",
@@ -501,17 +502,17 @@ LogConversation.prototype = {
     return null;
   },
   get account() {
     return {
       alias: "",
       name: this._accountName,
       normalizedName: this._accountName,
       protocol: { name: this._protocolName },
-      statusInfo: Services.core.globalUserStatus,
+      statusInfo: IMServices.core.globalUserStatus,
     };
   },
   getMessages() {
     // Start with the newest message to filter out older versions of the same
     // message. Also filter out deleted messages.
     return this._messages.map(m => new LogMessage(m, this));
   },
 };
--- a/chat/components/src/test/test_accounts.js
+++ b/chat/components/src/test/test_accounts.js
@@ -1,13 +1,14 @@
 /* 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/. */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { updateAppInfo } = ChromeUtils.import(
   "resource://testing-common/AppInfo.jsm"
 );
 
 function run_test() {
   do_get_profile();
 
   // Test the handling of accounts for unknown protocols.
@@ -20,27 +21,27 @@ function run_test() {
   prefs.setCharPref("mail.accountmanager.accounts", "account1");
   prefs.setCharPref("mail.account.account1.server", "server1");
   prefs.setCharPref("mail.server.server1.imAccount", "account1");
   prefs.setCharPref("mail.server.server1.type", "im");
   prefs.setCharPref("mail.server.server1.userName", kAccountName);
   prefs.setCharPref("mail.server.server1.hostname", kPrplId);
   try {
     // Having an implementation of nsIXULAppInfo is required for
-    // Services.core.init to work.
+    // IMServices.core.init to work.
     updateAppInfo();
-    Services.core.init();
+    IMServices.core.init();
 
-    let account = Services.accounts.getAccountByNumericId(1);
+    let account = IMServices.accounts.getAccountByNumericId(1);
     Assert.ok(account instanceof Ci.imIAccount);
     Assert.equal(account.name, kAccountName);
     Assert.equal(account.normalizedName, kAccountName);
     Assert.equal(account.protocol.id, kPrplId);
     Assert.equal(
       account.connectionErrorReason,
       Ci.imIAccount.ERROR_UNKNOWN_PRPL
     );
   } finally {
-    Services.core.quit();
+    IMServices.core.quit();
 
     prefs.deleteBranch("messenger");
   }
 }
--- a/chat/components/src/test/test_commands.js
+++ b/chat/components/src/test/test_commands.js
@@ -1,13 +1,14 @@
 /* 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/. */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 // We don't load the command service via Services as we want to access
 // _findCommands in order to avoid having to intercept command execution.
 var { CommandsService } = ChromeUtils.import(
   "resource:///modules/imCommands.jsm"
 );
 
 var kPrplId = "green";
 var kPrplId2 = "red";
--- a/chat/components/src/test/test_conversations.js
+++ b/chat/components/src/test/test_conversations.js
@@ -1,12 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { GenericConvIMPrototype, Message } = ChromeUtils.import(
   "resource:///modules/jsProtoHelper.jsm"
 );
 var { imMessage, UIConversation } = ChromeUtils.import(
   "resource:///modules/imConversations.jsm"
 );
 
 // Fake prplConversation
--- a/chat/components/src/test/test_logger.js
+++ b/chat/components/src/test/test_logger.js
@@ -1,15 +1,16 @@
 /* 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/. */
 
 do_get_profile();
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 
 var gLogger = {};
 Services.scriptloader.loadSubScript("resource:///modules/logger.jsm", gLogger);
 
 var logDirPath = PathUtils.join(
   Services.dirsvc.get("ProfD", Ci.nsIFile).path,
   "logs"
 );
--- a/chat/content/chat-tooltip.js
+++ b/chat/content/chat-tooltip.js
@@ -6,16 +6,17 @@
 
 /* global MozElements */
 /* global MozXULElement */
 /* global getBrowser */
 
 // Wrap in a block to prevent leaking to window scope.
 {
   let { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+  var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
   let { ChatIcons } = ChromeUtils.import("resource:///modules/chatIcons.jsm");
   const LazyModules = {};
 
   ChromeUtils.defineModuleGetter(
     LazyModules,
     "Status",
     "resource:///modules/imStatusUtils.jsm"
   );
@@ -555,17 +556,17 @@
       }
 
       let account = aConv.account;
       let normalizedNick = aConv.target.getNormalizedChatBuddyName(aNick);
       // To try to ensure that we aren't misidentifying a nick with a
       // contact, we require at least that the normalizedChatBuddyName of
       // the nick is normalized like a normalizedName for contacts.
       if (normalizedNick == account.normalize(normalizedNick)) {
-        let accountBuddy = Services.contacts.getAccountBuddyByNameAndAccount(
+        let accountBuddy = IMServices.contacts.getAccountBuddyByNameAndAccount(
           normalizedNick,
           account
         );
         if (accountBuddy) {
           return this.updateTooltipFromBuddy(
             accountBuddy,
             aConv,
             overrideAvatar
--- a/chat/content/otr-auth.js
+++ b/chat/content/otr-auth.js
@@ -1,13 +1,14 @@
 /* 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/. */
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { XPCOMUtils, l10nHelper } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
 const { OTR } = ChromeUtils.import("resource:///modules/OTR.jsm");
 
 window.addEventListener("DOMContentLoaded", event => {
   otrAuth.onload();
 });
--- a/chat/content/otr-finger.js
+++ b/chat/content/otr-finger.js
@@ -1,13 +1,14 @@
 /* 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/. */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { OTR } = ChromeUtils.import("resource:///modules/OTR.jsm");
 
 var l10n = new Localization(["messenger/otr/finger-sync.ftl"], true);
 
 window.addEventListener("DOMContentLoaded", event => {
   otrFinger.onload();
 });
 
--- a/chat/modules/CLib.jsm
+++ b/chat/modules/CLib.jsm
@@ -1,14 +1,16 @@
 /* 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/. */
 
+const EXPORTED_SYMBOLS = ["CLib"];
+
 const { ctypes } = ChromeUtils.import("resource://gre/modules/ctypes.jsm");
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 var OS = Services.appinfo.OS.toLowerCase();
 
 // type defs
 
 var FILE = ctypes.StructType("FILE");
 var fname_t = ctypes.char.ptr;
 var wchar_t = ctypes.char16_t;
@@ -58,12 +60,8 @@ var CLib = {
     ctypes.void_t.ptr,
     ctypes.size_t
   ),
   free: libc.declare("free", libcAbi, ctypes.void_t, ctypes.void_t.ptr),
   strdup: libc.declare(strdup, libcAbi, ctypes.char.ptr, ctypes.char.ptr),
   fclose: libc.declare("fclose", libcAbi, ctypes.int, FILE.ptr),
   fopen: libc.declare(fopen, libcAbi, FILE.ptr, fname_t, fname_t),
 };
-
-// exports
-
-const EXPORTED_SYMBOLS = ["CLib"];
rename from chat/modules/imServices.jsm
rename to chat/modules/IMServices.jsm
--- a/chat/modules/imServices.jsm
+++ b/chat/modules/IMServices.jsm
@@ -1,53 +1,54 @@
 /* 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/. */
 
-const EXPORTED_SYMBOLS = ["Services"];
+const EXPORTED_SYMBOLS = ["IMServices"];
 
-const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
+const IMServices = {};
+
 XPCOMUtils.defineLazyServiceGetter(
-  Services,
+  IMServices,
   "accounts",
   "@mozilla.org/chat/accounts-service;1",
   "imIAccountsService"
 );
 XPCOMUtils.defineLazyServiceGetter(
-  Services,
+  IMServices,
   "core",
   "@mozilla.org/chat/core-service;1",
   "imICoreService"
 );
 XPCOMUtils.defineLazyServiceGetter(
-  Services,
+  IMServices,
   "cmd",
   "@mozilla.org/chat/commands-service;1",
   "imICommandsService"
 );
 XPCOMUtils.defineLazyServiceGetter(
-  Services,
+  IMServices,
   "contacts",
   "@mozilla.org/chat/contacts-service;1",
   "imIContactsService"
 );
 XPCOMUtils.defineLazyServiceGetter(
-  Services,
+  IMServices,
   "conversations",
   "@mozilla.org/chat/conversations-service;1",
   "imIConversationsService"
 );
 XPCOMUtils.defineLazyServiceGetter(
-  Services,
+  IMServices,
   "tags",
   "@mozilla.org/chat/tags-service;1",
   "imITagsService"
 );
 XPCOMUtils.defineLazyServiceGetter(
-  Services,
+  IMServices,
   "logs",
   "@mozilla.org/chat/logger;1",
   "imILogger"
 );
--- a/chat/modules/InteractiveBrowser.jsm
+++ b/chat/modules/InteractiveBrowser.jsm
@@ -1,15 +1,15 @@
 /* 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/. */
 
 const EXPORTED_SYMBOLS = ["InteractiveBrowser", "CancelledError"];
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 class CancelledError extends Error {
   constructor() {
     super("Interactive browser request was cancelled");
   }
 }
 
 var InteractiveBrowser = {
--- a/chat/modules/OTR.jsm
+++ b/chat/modules/OTR.jsm
@@ -1,17 +1,18 @@
 /* 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/. */
 
 const { BasePromiseWorker } = ChromeUtils.import(
   "resource://gre/modules/PromiseWorker.jsm"
 );
 const { ctypes } = ChromeUtils.import("resource://gre/modules/ctypes.jsm");
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { CLib } = ChromeUtils.import("resource:///modules/CLib.jsm");
 const { OTRLibLoader } = ChromeUtils.import("resource:///modules/OTRLib.jsm");
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
 XPCOMUtils.defineLazyGetter(
   this,
@@ -580,17 +581,17 @@ var OTR = {
       }
       uiConv = uiConvs.next();
     }
     throw new Error("Couldn't find conversation.");
   },
 
   getUIConvFromConv(conv) {
     // return this._convos.get(conv.id);
-    return Services.conversations.getUIConversation(conv);
+    return IMServices.conversations.getUIConversation(conv);
   },
 
   disconnect(conv, remove) {
     OTRLib.otrl_message_disconnect(
       this.userstate,
       this.uiOps.address(),
       null,
       conv.account.normalizedName,
--- a/chat/modules/OTRUI.jsm
+++ b/chat/modules/OTRUI.jsm
@@ -1,15 +1,16 @@
 /* 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/. */
 
 const EXPORTED_SYMBOLS = ["OTRUI"];
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { OTR } = ChromeUtils.import("resource:///modules/OTR.jsm");
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
 XPCOMUtils.defineLazyGetter(
   this,
   "l10n",
@@ -218,17 +219,17 @@ var OTRUI = {
         OTRUI.loopKeyGenFailure
       );
     } else {
       ChromeUtils.idleDispatch(OTRUI.genNextMissingKey);
     }
   },
 
   genMissingKeys() {
-    for (let acc of Services.accounts.getAccounts()) {
+    for (let acc of IMServices.accounts.getAccounts()) {
       OTRUI.accountsToGenKey.push({
         name: acc.normalizedName,
         prot: acc.protocol.normalizedName,
       });
     }
     ChromeUtils.idleDispatch(OTRUI.genNextMissingKey);
   },
 
@@ -268,17 +269,17 @@ var OTRUI = {
         // Disabled until #76 is resolved.
         // Services.obs.addObserver(OTRUI, "contact-added", false);
         Services.obs.addObserver(OTRUI, "account-added");
         // Services.obs.addObserver(OTRUI, "contact-signed-off", false);
         Services.obs.addObserver(OTRUI, "conversation-loaded");
         Services.obs.addObserver(OTRUI, "conversation-closed");
         Services.obs.addObserver(OTRUI, "prpl-quit");
 
-        for (let conv of Services.conversations.getConversations()) {
+        for (let conv of IMServices.conversations.getConversations()) {
           OTRUI.initConv(conv);
         }
         OTRUI.addMenuObserver();
 
         ChromeUtils.idleDispatch(OTRUI.genMissingKeys);
       })
       .catch(function(err) {
         // console.log("===> " + err + "\n");
@@ -286,17 +287,17 @@ var OTRUI = {
       });
   },
 
   disconnect(aConv) {
     if (aConv) {
       return OTR.disconnect(aConv, true);
     }
     let allGood = true;
-    for (let conv of Services.conversations.getConversations()) {
+    for (let conv of IMServices.conversations.getConversations()) {
       if (conv.isChat) {
         continue;
       }
       if (!OTR.disconnect(conv, true)) {
         allGood = false;
       }
     }
     return allGood;
@@ -985,16 +986,16 @@ var OTRUI = {
     Services.obs.removeObserver(OTR, "conversation-update-type");
     // Services.obs.removeObserver(OTRUI, "contact-added");
     // Services.obs.removeObserver(OTRUI, "contact-signed-off");
     Services.obs.removeObserver(OTRUI, "account-added");
     Services.obs.removeObserver(OTRUI, "conversation-loaded");
     Services.obs.removeObserver(OTRUI, "conversation-closed");
     Services.obs.removeObserver(OTRUI, "prpl-quit");
 
-    for (let conv of Services.conversations.getConversations()) {
+    for (let conv of IMServices.conversations.getConversations()) {
       OTRUI.resetConv(conv);
     }
     OTR.removeObserver(OTRUI);
     OTR.close();
     OTRUI.removeMenuObserver();
   },
 };
--- a/chat/modules/imContentSink.jsm
+++ b/chat/modules/imContentSink.jsm
@@ -1,14 +1,12 @@
 /* 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/. */
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
-
 const EXPORTED_SYMBOLS = [
   // cleanupImMarkup is used to clean up incoming IMs. It will use the global
   // ruleset of acceptable stuff except if another (custom one) is provided.
   "cleanupImMarkup",
   // createDerivedRuleset is used to create a ruleset that inherits from the
   // default one. Useful if you want to allow or forbid an additional thing in
   // a specific conversation but take into account all the other global
   // settings.
@@ -16,16 +14,18 @@ const EXPORTED_SYMBOLS = [
   "addGlobalAllowedTag",
   "removeGlobalAllowedTag",
   "addGlobalAllowedAttribute",
   "removeGlobalAllowedAttribute",
   "addGlobalAllowedStyleRule",
   "removeGlobalAllowedStyleRule",
 ];
 
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
 var kAllowedURLs = aValue => /^(https?|ftp|mailto|magnet):/.test(aValue);
 var kAllowedMozClasses = aClassName =>
   aClassName == "moz-txt-underscore" ||
   aClassName == "moz-txt-tag" ||
   aClassName == "ib-person";
 var kAllowedAnchorClasses = aClassName => aClassName == "ib-person";
 
 /* Tags whose content should be fully removed, and reported in the Error Console. */
--- a/chat/modules/imSmileys.jsm
+++ b/chat/modules/imSmileys.jsm
@@ -1,31 +1,31 @@
 /* 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/. */
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+/** Used to add smileys to the content of a textnode. */
+
+const EXPORTED_SYMBOLS = ["smileTextNode"];
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
 XPCOMUtils.defineLazyGetter(this, "gTextDecoder", () => {
   return new TextDecoder();
 });
 
 ChromeUtils.defineModuleGetter(
   this,
   "NetUtil",
   "resource://gre/modules/NetUtil.jsm"
 );
 
-const EXPORTED_SYMBOLS = [
-  "smileTextNode", // used to add smileys to the content of a textnode
-];
-
 var kEmoticonsThemePref = "messenger.options.emoticonsTheme";
 var kThemeFile = "theme.json";
 
 Object.defineProperty(this, "gTheme", {
   configurable: true,
   enumerable: true,
 
   get() {
--- a/chat/modules/imTextboxUtils.jsm
+++ b/chat/modules/imTextboxUtils.jsm
@@ -1,15 +1,15 @@
 /* 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/. */
 
 const EXPORTED_SYMBOLS = ["TextboxSize"];
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 var TextboxSize = {
   _textboxAutoResizePrefName: "messenger.conversations.textbox.autoResize",
   get autoResize() {
     delete this.autoResize;
     Services.prefs.addObserver(this._textboxAutoResizePrefName, this);
     return (this.autoResize = Services.prefs.getBoolPref(
       this._textboxAutoResizePrefName
--- a/chat/modules/imThemes.jsm
+++ b/chat/modules/imThemes.jsm
@@ -13,17 +13,17 @@ const EXPORTED_SYMBOLS = [
   "getMessagesForRange",
   "serializeSelection",
   "getDocumentFragmentFromHTML",
   "replaceHTMLForMessage",
   "wasNextMessage",
   "removeMessage",
 ];
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
 ChromeUtils.defineModuleGetter(
   this,
   "DownloadUtils",
   "resource://gre/modules/DownloadUtils.jsm"
--- a/chat/modules/imXPCOMUtils.jsm
+++ b/chat/modules/imXPCOMUtils.jsm
@@ -11,17 +11,17 @@ const EXPORTED_SYMBOLS = [
   "l10nHelper",
   "initLogModule",
   "scriptError",
 ];
 
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 var kLogLevelPref = "purple.debug.loglevel";
 
 /**
  * Creates an nsIScriptError instance and logs it.
  *
  * @param aModule
  *        string identifying the module within which the error occurred.
--- a/chat/modules/jsProtoHelper.jsm
+++ b/chat/modules/jsProtoHelper.jsm
@@ -17,17 +17,18 @@ const EXPORTED_SYMBOLS = [
 ];
 
 const {
   initLogModule,
   XPCOMUtils,
   nsSimpleEnumerator,
   l10nHelper,
 } = ChromeUtils.import("resource:///modules/imXPCOMUtils.jsm");
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { ClassInfo } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
 
 XPCOMUtils.defineLazyGetter(this, "_", () =>
   l10nHelper("chrome://chat/locale/conversations.properties")
 );
 
@@ -182,17 +183,17 @@ var GenericAccountPrototype = {
     );
     this.cancelPendingBuddyRequests();
     this.cancelPendingChatRequests();
     this.cancelPendingVerificationRequests();
   },
 
   // Called when the user adds a new buddy from the UI.
   addBuddy(aTag, aName) {
-    Services.contacts.accountBuddyAdded(
+    IMServices.contacts.accountBuddyAdded(
       new AccountBuddy(this, null, aTag, aName)
     );
   },
   // Called during startup for each of the buddies in the local buddy list.
   loadBuddy(aBuddy, aTag) {
     try {
       return new AccountBuddy(this, aBuddy, aTag);
     } catch (x) {
@@ -641,17 +642,17 @@ var GenericAccountBuddyPrototype = {
     return this._buddy;
   },
   get tag() {
     return this._tag;
   },
   set tag(aNewTag) {
     let oldTag = this._tag;
     this._tag = aNewTag;
-    Services.contacts.accountBuddyMoved(this, oldTag, aNewTag);
+    IMServices.contacts.accountBuddyMoved(this, oldTag, aNewTag);
   },
 
   _notifyObservers(aTopic, aData) {
     try {
       this._buddy.observe(this, "account-buddy-" + aTopic, aData);
     } catch (e) {
       this.ERROR(e);
     }
@@ -717,17 +718,17 @@ var GenericAccountBuddyPrototype = {
         );
         cancelPromise.then(() => verifier.cancel());
         return verifier;
       }
     );
   },
 
   remove() {
-    Services.contacts.accountBuddyRemoved(this);
+    IMServices.contacts.accountBuddyRemoved(this);
   },
 
   // imIStatusInfo implementation
   get displayName() {
     return this.serverAlias || this.userName;
   },
   _buddyIconFilename: "",
   get buddyIconFilename() {
@@ -916,17 +917,17 @@ var GenericConversationPrototype = {
     return this._account.ERROR;
   },
 
   _init(aAccount, aName) {
     this._account = aAccount;
     this._name = aName;
     this._observers = [];
     this._date = new Date() * 1000;
-    Services.conversations.addConversation(this);
+    IMServices.conversations.addConversation(this);
   },
 
   _id: 0,
   get id() {
     return this._id;
   },
   set id(aId) {
     if (this._id) {
@@ -999,17 +1000,17 @@ var GenericConversationPrototype = {
   },
   dispatchMessage(message, action, notification) {
     throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
   },
   sendTyping: aString => Ci.prplIConversation.NO_TYPING_LIMIT,
 
   close() {
     Services.obs.notifyObservers(this, "closing-conversation");
-    Services.conversations.removeConversation(this);
+    IMServices.conversations.removeConversation(this);
   },
   unInit() {
     delete this._account;
     delete this._observers;
   },
 
   /**
    * Create a prplIMessage instance from params.
@@ -1631,17 +1632,17 @@ var GenericProtocolPrototype = {
         command.QueryInterface = ChromeUtils.generateQI(["imICommand"]);
       }
       if (!command.hasOwnProperty("usageContext")) {
         command.usageContext = Ci.imICommand.CMD_CONTEXT_ALL;
       }
       if (!command.hasOwnProperty("priority")) {
         command.priority = Ci.imICommand.CMD_PRIORITY_PRPL;
       }
-      Services.cmd.registerCommand(command, this.id);
+      IMServices.cmd.registerCommand(command, this.id);
     }, this);
   },
 
   // NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED errors are too noisy
   get usernameEmptyText() {
     return "";
   },
   accountExists: () => false, // FIXME
--- a/chat/modules/moz.build
+++ b/chat/modules/moz.build
@@ -3,17 +3,17 @@
 # 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/.
 
 XPCSHELL_TESTS_MANIFESTS += ["test/xpcshell.ini"]
 
 EXTRA_JS_MODULES += [
     "CLib.jsm",
     "imContentSink.jsm",
-    "imServices.jsm",
+    "IMServices.jsm",
     "imSmileys.jsm",
     "imStatusUtils.jsm",
     "imTextboxUtils.jsm",
     "imThemes.jsm",
     "imXPCOMUtils.jsm",
     "InteractiveBrowser.jsm",
     "jsProtoHelper.jsm",
     "NormalizedMap.jsm",
--- a/chat/modules/test/test_filtering.js
+++ b/chat/modules/test/test_filtering.js
@@ -1,15 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // These tests run into issues if there isn't a profile directory, see bug 1542397.
 do_get_profile();
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var {
   cleanupImMarkup,
   createDerivedRuleset,
   addGlobalAllowedTag,
   removeGlobalAllowedTag,
   addGlobalAllowedAttribute,
   removeGlobalAllowedAttribute,
   addGlobalAllowedStyleRule,
--- a/chat/protocols/irc/irc.jsm
+++ b/chat/protocols/irc/irc.jsm
@@ -15,17 +15,18 @@ var { clearTimeout, setTimeout } = Chrom
 );
 var {
   ClassInfo,
   executeSoon,
   l10nHelper,
   XPCOMUtils,
   nsSimpleEnumerator,
 } = ChromeUtils.import("resource:///modules/imXPCOMUtils.jsm");
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { _, ctcpFormatToHTML, kListRefreshInterval } = ChromeUtils.import(
   "resource:///modules/ircUtils.jsm"
 );
 var { ircHandlers } = ChromeUtils.import("resource:///modules/ircHandlers.jsm");
 var {
   GenericAccountPrototype,
   GenericAccountBuddyPrototype,
   GenericConvIMPrototype,
@@ -1552,17 +1553,17 @@ ircAccount.prototype = {
     }
     this.trackQueue.splice(index, 1);
   },
   addBuddy(aTag, aName) {
     let buddy = new ircAccountBuddy(this, null, aTag, aName);
     this.buddies.set(buddy.normalizedName, buddy);
     this.trackBuddy(buddy.userName);
 
-    Services.contacts.accountBuddyAdded(buddy);
+    IMServices.contacts.accountBuddyAdded(buddy);
   },
   removeBuddy(aBuddy) {
     this.buddies.delete(aBuddy.normalizedName);
     this.untrackBuddy(aBuddy.userName);
   },
   // Loads a buddy from the local storage. Called for each buddy locally stored
   // before connecting to the server.
   loadBuddy(aBuddy, aTag) {
--- a/chat/protocols/irc/ircCTCP.jsm
+++ b/chat/protocols/irc/ircCTCP.jsm
@@ -1,21 +1,21 @@
 /* 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/. */
 
-/*
+/**
  * This implements the Client-to-Client Protocol (CTCP), a subprotocol of IRC.
  *   REVISED AND UPDATED CTCP SPECIFICATION
  *     http://www.alien.net.au/irc/ctcp.txt
  */
 
 const EXPORTED_SYMBOLS = ["ircCTCP", "ctcpBase", "CTCPMessage"];
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const { ircHandlers } = ChromeUtils.import(
   "resource:///modules/ircHandlers.jsm"
 );
 var { _, displayMessage } = ChromeUtils.import(
   "resource:///modules/ircUtils.jsm"
 );
 
 // Split into a CTCP message which is a single command and a single parameter:
--- a/chat/protocols/irc/ircCommands.jsm
+++ b/chat/protocols/irc/ircCommands.jsm
@@ -1,17 +1,17 @@
 /* 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/. */
 
 // This is to be exported directly onto the IRC prplIProtocol object, directly
 // implementing the commands field before we register them.
 const EXPORTED_SYMBOLS = ["commands"];
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 var { _ } = ChromeUtils.import("resource:///modules/ircUtils.jsm");
 
 // Shortcut to get the JavaScript conversation object.
 function getConv(aConv) {
   return aConv.wrappedJSObject;
 }
 
 // Shortcut to get the JavaScript account object.
--- a/chat/protocols/irc/test/test_ircCommands.js
+++ b/chat/protocols/irc/test/test_ircCommands.js
@@ -1,19 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { commands } = ChromeUtils.import("resource:///modules/ircCommands.jsm");
 var { ircProtocol, ircAccount, ircConversation } = ChromeUtils.import(
   "resource:///modules/irc.jsm"
 );
 
 // Ensure the commands have been initialized.
-Services.conversations.initConversations();
+IMServices.conversations.initConversations();
 
 var fakeProto = {
   id: "fake-proto",
   usernameSplits: ircProtocol.prototype.usernameSplits,
   splitUsername: ircProtocol.prototype.splitUsername,
 };
 
 function run_test() {
--- a/chat/protocols/irc/test/test_sendBufferedCommand.js
+++ b/chat/protocols/irc/test/test_sendBufferedCommand.js
@@ -1,13 +1,14 @@
 /* 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/. */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { ircAccount } = ChromeUtils.import("resource:///modules/irc.jsm");
 var { clearTimeout, setTimeout } = ChromeUtils.import(
   "resource://gre/modules/Timer.jsm"
 );
 
 function FakeAccount() {
   this._commandBuffers = new Map();
   this.callbacks = [];
--- a/chat/protocols/irc/test/test_setMode.js
+++ b/chat/protocols/irc/test/test_setMode.js
@@ -1,17 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { ircAccount, ircChannel } = ChromeUtils.import(
   "resource:///modules/irc.jsm"
 );
 
-Services.conversations.initConversations();
+IMServices.conversations.initConversations();
 
 function FakeAccount() {
   this.normalizeNick = ircAccount.prototype.normalizeNick.bind(this);
 }
 FakeAccount.prototype = {
   __proto__: ircAccount.prototype,
   setWhois: (n, f) => true,
   ERROR: do_throw,
--- a/chat/protocols/matrix/matrix.jsm
+++ b/chat/protocols/matrix/matrix.jsm
@@ -10,17 +10,18 @@ var EXPORTED_SYMBOLS = [
 ];
 
 const { clearTimeout, setTimeout } = ChromeUtils.import(
   "resource://gre/modules/Timer.jsm"
 );
 var { XPCOMUtils, nsSimpleEnumerator, l10nHelper } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var {
   GenericAccountPrototype,
   GenericConvChatPrototype,
   GenericConvChatBuddyPrototype,
   GenericProtocolPrototype,
   GenericConversationPrototype,
   GenericConvIMPrototype,
   GenericAccountBuddyPrototype,
@@ -1204,21 +1205,21 @@ MatrixRoom.prototype = {
         this.buddy.setUser(user);
       }
       return;
     }
     const user = this._account._client.getUser(dmUserId);
     this.buddy = new MatrixBuddy(
       this._account,
       null,
-      Services.tags.defaultTag,
+      IMServices.tags.defaultTag,
       user.userId
     );
     this.buddy.setUser(user);
-    Services.contacts.accountBuddyAdded(this.buddy);
+    IMServices.contacts.accountBuddyAdded(this.buddy);
     this._account.buddies.set(dmUserId, this.buddy);
   },
 
   /**
    * Searches for recent verification requests in the room history.
    * Optimally we would instead handle verification requests with natural event
    * backfill for the room. Until then, we search the last three days of events
    * for verification requests.
@@ -1315,17 +1316,17 @@ MatrixRoom.prototype = {
    */
   closeDm() {
     if (this.buddy) {
       const dmUserId = this.buddy.userName;
       const otherDMRooms = Array.from(this._account.roomList.values()).filter(
         conv => conv.buddy && conv.buddy === this.buddy && conv !== this
       );
       if (otherDMRooms.length == 0) {
-        Services.contacts.accountBuddyRemoved(this.buddy);
+        IMServices.contacts.accountBuddyRemoved(this.buddy);
         this._account.buddies.delete(dmUserId);
         delete this.buddy;
       }
     }
   },
 
   updateTyping: GenericConvIMPrototype.updateTyping,
   typingState: Ci.prplIConvIM.NOT_TYPING,
@@ -3262,17 +3263,17 @@ MatrixAccount.prototype = {
     if (aName == this.userId) {
       return;
     }
     if (this.buddies.has(aName)) {
       return;
     }
     // Prepare buddy for use with the conversation while preserving the tag.
     const buddy = new MatrixBuddy(this, null, aTag, aName);
-    Services.contacts.accountBuddyAdded(buddy);
+    IMServices.contacts.accountBuddyAdded(buddy);
     this.buddies.set(aName, buddy);
 
     this.getDirectConversation(aName);
   },
   loadBuddy(aBuddy, aTag) {
     const buddy = new MatrixBuddy(this, aBuddy, aTag);
     this.buddies.set(buddy.userName, buddy);
     return buddy;
--- a/chat/protocols/matrix/test/head.js
+++ b/chat/protocols/matrix/test/head.js
@@ -1,21 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const {
   MatrixProtocol,
   MatrixRoom,
   MatrixAccount,
   MatrixMessage,
 } = ChromeUtils.import("resource:///modules/matrix.jsm");
 var { MatrixSDK } = ChromeUtils.import("resource:///modules/matrix-sdk.jsm");
 function loadMatrix() {
-  Services.conversations.initConversations();
+  IMServices.conversations.initConversations();
 }
 
 /**
  * Get a MatrixRoom instance with a mocked client.
  * @param {boolean} isMUC
  * @param {string} [name="#test:example.com"]
  * @param {(any, string) => any?|object} [clientHandler]
  * @returns {MatrixRoom}
--- a/chat/protocols/matrix/test/test_matrixAccount.js
+++ b/chat/protocols/matrix/test/test_matrixAccount.js
@@ -68,17 +68,17 @@ add_task(function test_getConversationBy
   equal(
     MatrixAccount.prototype.getConversationByIdOrAlias.call(mockAccount, "baz"),
     null
   );
 });
 
 add_task(async function test_getGroupConversation() {
   registerCleanupFunction(() => {
-    const conversations = Services.conversations.getConversations();
+    const conversations = IMServices.conversations.getConversations();
     for (const conversation of conversations) {
       try {
         conversation.forget();
       } catch {}
     }
   });
 
   let allowedGetRoomIds = new Set(["baz"]);
@@ -376,14 +376,17 @@ add_task(async function test_deleteAccou
       verificationRequestCancelled = true;
       return Promise.reject(new Error("test"));
     },
   });
   account.remove();
   account.unInit();
   await storesPromise;
   ok(!clientLoggedIn, "logged out");
-  ok(!Services.conversations.getConversations().includes(conv), "room closed");
+  ok(
+    !IMServices.conversations.getConversations().includes(conv),
+    "room closed"
+  );
   ok(verificationRequestCancelled, "verification request cancelled");
   ok(stopped);
   equal(removedListeners, MatrixSDK.ClientEvent.Sync);
   equal(account._verificationRequestTimeouts.size, 0);
 });
--- a/chat/protocols/matrix/test/test_matrixRoom.js
+++ b/chat/protocols/matrix/test/test_matrixRoom.js
@@ -298,17 +298,17 @@ add_task(function test_forgetWith_close(
     _account: {
       roomList,
     },
     // stubs for jsProtoHelper implementations
     addObserver() {},
     unInit() {},
   };
   roomList.set(roomStub._roomId, roomStub);
-  Services.conversations.addConversation(roomStub);
+  IMServices.conversations.addConversation(roomStub);
 
   MatrixRoom.prototype.forget.call(roomStub);
   ok(!roomList.has(roomStub._roomId));
   ok(roomStub.closeCalled);
 });
 
 add_task(function test_forgetWithout_close() {
   const roomList = new Map();
@@ -318,17 +318,17 @@ add_task(function test_forgetWithout_clo
     _account: {
       roomList,
     },
     // stubs for jsProtoHelper implementations
     addObserver() {},
     unInit() {},
   };
   roomList.set(roomStub._roomId, roomStub);
-  Services.conversations.addConversation(roomStub);
+  IMServices.conversations.addConversation(roomStub);
 
   MatrixRoom.prototype.forget.call(roomStub);
   ok(!roomList.has(roomStub._roomId));
 });
 
 add_task(function test_close() {
   const roomStub = {
     forget() {
--- a/chat/protocols/xmpp/xmpp-base.jsm
+++ b/chat/protocols/xmpp/xmpp-base.jsm
@@ -7,17 +7,18 @@ const EXPORTED_SYMBOLS = [
   "XMPPMUCConversationPrototype",
   "XMPPAccountBuddyPrototype",
   "XMPPAccountPrototype",
 ];
 
 const { clearTimeout, setTimeout } = ChromeUtils.import(
   "resource://gre/modules/Timer.jsm"
 );
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { Status } = ChromeUtils.import("resource:///modules/imStatusUtils.jsm");
 const {
   XPCOMUtils,
   executeSoon,
   nsSimpleEnumerator,
   EmptyEnumerator,
   ClassInfo,
   l10nHelper,
@@ -1199,17 +1200,17 @@ var XMPPAccountBuddyPrototype = {
   set tag(aNewTag) {
     let oldTag = this._tag;
     if (oldTag.name == aNewTag.name) {
       this.ERROR("attempting to set the tag to the same value");
       return;
     }
 
     this._tag = aNewTag;
-    Services.contacts.accountBuddyMoved(this, oldTag, aNewTag);
+    IMServices.contacts.accountBuddyMoved(this, oldTag, aNewTag);
 
     if (!this._rosterItem) {
       this.ERROR(
         "attempting to change the tag of an account buddy without roster item"
       );
       return;
     }
 
@@ -2947,35 +2948,35 @@ var XMPPAccountPrototype = {
         // as the account buddy's tag is still a group on the server...
         let tagName = buddy.tag.name;
         if (!groups.some(g => g.innerText == tagName)) {
           // ... otherwise we need to move our account buddy to a new group.
           tagName = groups[0].innerText;
           if (tagName) {
             // Should always be true, but check just in case...
             let oldTag = buddy.tag;
-            buddy._tag = Services.tags.createTag(tagName);
-            Services.contacts.accountBuddyMoved(buddy, oldTag, buddy._tag);
+            buddy._tag = IMServices.tags.createTag(tagName);
+            IMServices.contacts.accountBuddyMoved(buddy, oldTag, buddy._tag);
           }
         }
       }
     } else {
       let tag;
       for (let group of aItem.getChildren("group")) {
         let name = group.innerText;
         if (name) {
-          tag = Services.tags.createTag(name);
+          tag = IMServices.tags.createTag(name);
           break; // TODO we should create an accountBuddy per group,
           // but this._buddies would probably not like that...
         }
       }
       buddy = new this._accountBuddyConstructor(
         this,
         null,
-        tag || Services.tags.defaultTag,
+        tag || IMServices.tags.defaultTag,
         jid
       );
     }
 
     // We request the vCard only if we haven't received it yet and are
     // subscribed to presence for that contact.
     if (
       (subscription == "both" || subscription == "to") &&
@@ -2995,29 +2996,29 @@ var XMPPAccountPrototype = {
       buddy.rosterAlias = "";
     }
 
     if (subscription) {
       buddy.subscription = subscription;
     }
     if (!this._buddies.has(jid)) {
       this._buddies.set(jid, buddy);
-      Services.contacts.accountBuddyAdded(buddy);
+      IMServices.contacts.accountBuddyAdded(buddy);
     } else if (aNotifyOfUpdates) {
       buddy._notifyObservers("status-detail-changed");
     }
 
     // Keep the xml nodes of the item so that we don't have to
     // recreate them when changing something (eg. the alias) in it.
     buddy._rosterItem = aItem;
 
     return jid;
   },
   _forgetRosterItem(aJID) {
-    Services.contacts.accountBuddyRemoved(this._buddies.get(aJID));
+    IMServices.contacts.accountBuddyRemoved(this._buddies.get(aJID));
     this._buddies.delete(aJID);
   },
 
   /* When the roster is received */
   onRoster(aStanza) {
     // For the first element that is a roster stanza.
     for (let qe of aStanza.getChildren("query")) {
       if (qe.uri != Stanza.NS.roster) {
--- a/chat/protocols/xmpp/xmpp-session.jsm
+++ b/chat/protocols/xmpp/xmpp-session.jsm
@@ -1,16 +1,16 @@
 /* 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/. */
 
 const EXPORTED_SYMBOLS = ["XMPPSession"];
 
 const { DNS } = ChromeUtils.import("resource:///modules/DNS.jsm");
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 var { XPCOMUtils, l10nHelper } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
 var { Socket } = ChromeUtils.import("resource:///modules/socket.jsm");
 var { Stanza, XMPPParser } = ChromeUtils.import(
   "resource:///modules/xmpp-xml.jsm"
 );
 var { XMPPAuthMechanisms } = ChromeUtils.import(
--- a/mail/components/about-support/content/chat.js
+++ b/mail/components/about-support/content/chat.js
@@ -1,17 +1,14 @@
 /* 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/. */
 
-/* globals Services */
-
-var { Services: imServices } = ChromeUtils.import(
-  "resource:///modules/imServices.jsm"
-);
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 
 /**
  * Populates the "Chat" section of the troubleshooting information page with
  * the chat accounts.
  */
 function populateChatSection() {
   let table = document.getElementById("chat-table");
   let rowTmpl = document.getElementById("chat-table-row-template");
@@ -47,17 +44,17 @@ function populateChatSection() {
       m.sourceName +
       ":" +
       m.lineNumber +
       ")\n" +
       m.errorMessage
     );
   };
 
-  let chatAccounts = imServices.accounts.getAccounts();
+  let chatAccounts = IMServices.accounts.getAccounts();
   if (!chatAccounts.length) {
     return;
   }
   table.querySelector("tbody").append(
     ...chatAccounts.map(account => {
       const row = rowTmpl.content.cloneNode(true).querySelector("tr");
       row.cells[0].textContent = account.id;
       row.cells[1].textContent = account.protocol.id;
--- a/mail/components/im/IMIncomingServer.jsm
+++ b/mail/components/im/IMIncomingServer.jsm
@@ -1,15 +1,16 @@
 /* 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/. */
 
 var EXPORTED_SYMBOLS = ["IMIncomingServer"];
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 
 function IMIncomingServer() {}
 
 IMIncomingServer.prototype = {
   get wrappedJSObject() {
     return this;
   },
   _imAccount: null,
@@ -17,18 +18,18 @@ IMIncomingServer.prototype = {
     if (this._imAccount) {
       return this._imAccount;
     }
 
     let id = this.getCharValue("imAccount");
     if (!id) {
       return null;
     }
-    Services.core.init();
-    return (this._imAccount = Services.accounts.getAccountById(id));
+    IMServices.core.init();
+    return (this._imAccount = IMServices.accounts.getAccountById(id));
   },
   set imAccount(aImAccount) {
     this._imAccount = aImAccount;
     this.setCharValue("imAccount", aImAccount.id);
   },
   _prefBranch: null,
   valid: true,
   hidden: false,
@@ -46,39 +47,39 @@ IMIncomingServer.prototype = {
     this._key = aKey;
     this._prefBranch = Services.prefs.getBranch("mail.server." + aKey + ".");
   },
   equals(aServer) {
     return "wrappedJSObject" in aServer && aServer.wrappedJSObject == this;
   },
 
   clearAllValues() {
-    Services.accounts.deleteAccount(this.imAccount.id);
+    IMServices.accounts.deleteAccount(this.imAccount.id);
     for (let prefName of this._prefBranch.getChildList("")) {
       this._prefBranch.clearUserPref(prefName);
     }
     delete this._prefBranch;
     delete this._imAccount;
   },
 
   // Returns the directory where the account would have its data stored.
   // There are currently conversation logs only.
   // It may not exist yet.
   // This is used in account removal dialog and should return the same path
   // that the removeFiles() function deletes.
   get localPath() {
-    let logPath = Services.logs.getLogFolderPathForAccount(this.imAccount);
+    let logPath = IMServices.logs.getLogFolderPathForAccount(this.imAccount);
     let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
     file.initWithPath(logPath);
     return file;
   },
 
   // Removes files created by this account.
   removeFiles() {
-    Services.logs.deleteLogFolderForAccount(this.imAccount);
+    IMServices.logs.deleteLogFolderForAccount(this.imAccount);
   },
 
   // called by nsMsgAccountManager while deleting an account:
   forgetSessionPassword() {},
 
   forgetPassword() {
     // Password is cleared in imAccount.remove()
     // TODO: this may need to be implemented here as a separate function
--- a/mail/components/im/content/addbuddy.js
+++ b/mail/components/im/content/addbuddy.js
@@ -1,19 +1,20 @@
 /* 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/. */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { ChatIcons } = ChromeUtils.import("resource:///modules/chatIcons.jsm");
 
 var addBuddy = {
   onload() {
     let accountList = document.getElementById("accountlist");
-    for (let acc of Services.accounts.getAccounts()) {
+    for (let acc of IMServices.accounts.getAccounts()) {
       if (!acc.connected) {
         continue;
       }
       let proto = acc.protocol;
       let item = accountList.appendItem(acc.name, acc.id, proto.name);
       item.setAttribute("image", ChatIcons.getProtocolIconURI(proto));
       item.setAttribute("class", "menuitem-iconic");
     }
@@ -33,23 +34,23 @@ var addBuddy = {
       .getButton("accept").disabled = !addBuddy.getValue("name");
   },
 
   getValue(aId) {
     return document.getElementById(aId).value;
   },
 
   create() {
-    let account = Services.accounts.getAccountById(
+    let account = IMServices.accounts.getAccountById(
       this.getValue("accountlist")
     );
     let group = Services.strings
       .createBundle("chrome://messenger/locale/chat.properties")
       .GetStringFromName("defaultGroup");
-    account.addBuddy(Services.tags.createTag(group), this.getValue("name"));
+    account.addBuddy(IMServices.tags.createTag(group), this.getValue("name"));
   },
 };
 
 document.addEventListener("dialogaccept", addBuddy.create.bind(addBuddy));
 
 window.addEventListener("load", event => {
   addBuddy.onload();
 });
--- a/mail/components/im/content/chat-contact.js
+++ b/mail/components/im/content/chat-contact.js
@@ -6,16 +6,19 @@
 
 /* global MozXULElement, MozElements, Status, chatHandler */
 
 // Wrap in a block to prevent leaking to window scope.
 {
   const { Services } = ChromeUtils.import(
     "resource://gre/modules/Services.jsm"
   );
+  const { IMServices } = ChromeUtils.import(
+    "resource:///modules/IMServices.jsm"
+  );
   const { ChatIcons } = ChromeUtils.import("resource:///modules/chatIcons.jsm");
 
   /**
    * The MozChatContactRichlistitem widget displays contact information about user under
    * chat-groups, online contacts and offline contacts: i.e. icon and username.
    * On double clicking the element, it gets moved into the conversations.
    *
    * @extends {MozElements.MozRichlistitem}
@@ -222,17 +225,17 @@
     }
 
     canOpenConversation() {
       return this.contact.canSendMessage;
     }
 
     openConversation() {
       let prplConv = this.contact.createConversation();
-      let uiConv = Services.conversations.getUIConversation(prplConv);
+      let uiConv = IMServices.conversations.getUIConversation(prplConv);
       chatHandler.focusConversation(uiConv);
     }
 
     keyPress(event) {
       switch (event.keyCode) {
         // If Enter or Return is pressed, open a new conversation
         case event.DOM_VK_RETURN:
           if (this.hasAttribute("aliasing")) {
--- a/mail/components/im/content/chat-conversation-info.js
+++ b/mail/components/im/content/chat-conversation-info.js
@@ -3,17 +3,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 /* globals MozElements MozXULElement chatHandler */
 
 // Wrap in a block to prevent leaking to window scope.
 {
-  const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+  const { Services } = ChromeUtils.import(
+    "resource://gre/modules/Services.jsm"
+  );
   const { ChatIcons } = ChromeUtils.import("resource:///modules/chatIcons.jsm");
 
   ChromeUtils.defineModuleGetter(this, "OTR", "resource:///modules/OTR.jsm");
   ChromeUtils.defineModuleGetter(
     this,
     "OTRUI",
     "resource:///modules/OTRUI.jsm"
   );
--- a/mail/components/im/content/chat-conversation.js
+++ b/mail/components/im/content/chat-conversation.js
@@ -3,17 +3,22 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 /* globals MozElements, MozXULElement, chatHandler */
 
 // Wrap in a block to prevent leaking to window scope.
 {
-  const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+  const { Services } = ChromeUtils.import(
+    "resource://gre/modules/Services.jsm"
+  );
+  const { IMServices } = ChromeUtils.import(
+    "resource:///modules/IMServices.jsm"
+  );
   const { Status } = ChromeUtils.import(
     "resource:///modules/imStatusUtils.jsm"
   );
   const { TextboxSize } = ChromeUtils.import(
     "resource:///modules/imTextboxUtils.jsm"
   );
   const { AppConstants } = ChromeUtils.import(
     "resource://gre/modules/AppConstants.jsm"
@@ -524,17 +529,17 @@
         if (aMsg.match(/^\/(?:say)? ?$/)) {
           this.resetInput();
           return;
         }
 
         if (aMsg.match(/^\/(?:say)? .*/)) {
           aMsg = aMsg.slice(aMsg.indexOf(" ") + 1);
         } else if (
-          Services.cmd.executeCommand(aMsg, this._conv.target, convToFocus)
+          IMServices.cmd.executeCommand(aMsg, this._conv.target, convToFocus)
         ) {
           this._conv.sendTyping("");
           this.resetInput();
           if (convToFocus.value) {
             chatHandler.focusConversation(convToFocus.value);
           }
           return;
         }
@@ -784,17 +789,17 @@
         if (!word) {
           return;
         }
         let isFirstWord = this.inputBox.selectionStart == word.length;
 
         // Check if we are completing a command.
         let completingCommand = isFirstWord && word[0] == "/";
         if (completingCommand) {
-          for (let cmd of Services.cmd.listCommandsForConversation(
+          for (let cmd of IMServices.cmd.listCommandsForConversation(
             this._conv
           )) {
             // It's possible to have a global and a protocol specific command
             // with the same name. Avoid duplicates in the |completions| array.
             let name = "/" + cmd.name;
             if (!completions.includes(name)) {
               completions.push(name);
             }
--- a/mail/components/im/content/chat-messenger.js
+++ b/mail/components/im/content/chat-messenger.js
@@ -8,19 +8,17 @@
 // This file is loaded in messenger.xhtml.
 /* globals MailToolboxCustomizeDone, openIMAccountMgr,
    PROTO_TREE_VIEW, Status, statusSelector, ZoomManager, gSpacesToolbar */
 
 var { Notifications } = ChromeUtils.import(
   "resource:///modules/chatNotifications.jsm"
 );
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-var { Services: imServices } = ChromeUtils.import(
-  "resource:///modules/imServices.jsm"
-);
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { AppConstants } = ChromeUtils.import(
   "resource://gre/modules/AppConstants.jsm"
 );
 var { InlineSpellChecker } = ChromeUtils.import(
   "resource://gre/modules/InlineSpellChecker.jsm"
 );
 
 ChromeUtils.defineModuleGetter(this, "OTRUI", "resource:///modules/OTRUI.jsm");
@@ -338,17 +336,17 @@ var chatTabType = {
     if (tabmail.currentTabInfo.mode.name == "chat") {
       chatHandler._onTabDeactivated(false);
     }
   },
   openTab(aTab, aArgs) {
     aTab.tabNode.setIcon("chrome://messenger/skin/icons/new/compact/chat.svg");
     if (!this.hasBeenOpened) {
       if (chatHandler.ChatCore && chatHandler.ChatCore.initialized) {
-        let convs = imServices.conversations.getUIConversations();
+        let convs = IMServices.conversations.getUIConversations();
         if (convs.length != 0) {
           convs.sort((a, b) =>
             a.title.toLowerCase().localeCompare(b.title.toLowerCase())
           );
           for (let conv of convs) {
             chatHandler._addConversation(conv);
           }
         }
@@ -589,17 +587,17 @@ var chatHandler = {
         "unread-im-count-changed",
         unreadCount
       );
       this._notifiedUnreadCount = unreadCount;
     }
   },
 
   countUnreadMessages() {
-    let convs = imServices.conversations.getUIConversations();
+    let convs = IMServices.conversations.getUIConversations();
     let unreadTargetedCount = 0;
     let unreadTotalCount = 0;
     let unreadOTRNotificationCount = 0;
     for (let conv of convs) {
       unreadTargetedCount += conv.unreadTargetedMessageCount;
       unreadTotalCount += conv.unreadIncomingMessageCount;
       unreadOTRNotificationCount += conv.unreadOTRNotificationCount;
     }
@@ -648,17 +646,17 @@ var chatHandler = {
     }
 
     let status = target.getAttribute("status");
     if (!status) {
       // Can status really be null? Maybe because of an add-on...
       return;
     }
 
-    let us = imServices.core.globalUserStatus;
+    let us = IMServices.core.globalUserStatus;
     us.setStatus(Status.toFlag(status), us.statusText);
   },
 
   _pendingLogBrowserLoad: false,
   _showLogPanel() {
     hideConversationsBoxPanels();
     document.getElementById("logDisplay").hidden = false;
     document.getElementById("logDisplayBrowserBox").hidden = false;
@@ -682,29 +680,29 @@ var chatHandler = {
     }
     Services.obs.addObserver(this, "conversation-loaded");
 
     // Conversation title may not be set yet if this is a search result.
     let cti = document.getElementById("conv-top-info");
     cti.setAttribute("displayName", aConversation.title);
 
     // Find and display the contact for this log.
-    for (let account of imServices.accounts.getAccounts()) {
+    for (let account of IMServices.accounts.getAccounts()) {
       if (
         account.normalizedName == aConversation.account.normalizedName &&
         account.protocol.normalizedName == aConversation.account.protocol.name
       ) {
         if (aConversation.isChat) {
           // Display information for MUCs.
           cti.setAsChat("", false, false);
           cti.setProtocol(account.protocol);
           return;
         }
         // Display information for contacts.
-        let accountBuddy = imServices.contacts.getAccountBuddyByNameAndAccount(
+        let accountBuddy = IMServices.contacts.getAccountBuddyByNameAndAccount(
           aConversation.normalizedName,
           account
         );
         if (!accountBuddy) {
           return;
         }
         let contact = accountBuddy.buddy.contact;
         if (!contact) {
@@ -938,18 +936,18 @@ var chatHandler = {
       // Always hide encryption options for search conv
       ChatEncryption.hideEncryptionButton(document);
 
       let path = "logs/" + item.log.path;
       path = PathUtils.join(
         Services.dirsvc.get("ProfD", Ci.nsIFile).path,
         ...path.split("/")
       );
-      imServices.logs.getLogFromFile(path, true).then(aLog => {
-        imServices.logs.getSimilarLogs(aLog).then(aSimilarLogs => {
+      IMServices.logs.getLogFromFile(path, true).then(aLog => {
+        IMServices.logs.getSimilarLogs(aLog).then(aSimilarLogs => {
           if (contactlistbox.selectedItem != item) {
             return;
           }
           this._pendingSearchTerm = item.searchTerm || undefined;
           this._showLogList(aSimilarLogs, aLog);
         });
       });
     } else if (
@@ -1008,17 +1006,17 @@ var chatHandler = {
       hideConversationsBoxPanels();
       item.convView.hidden = false;
       item.convView.querySelector(".conv-bottom").setAttribute("height", 90);
       item.convView.updateConvStatus();
       item.update();
 
       ChatEncryption.updateEncryptionButton(document, item.conv);
 
-      imServices.logs.getLogsForConversation(item.conv).then(aLogs => {
+      IMServices.logs.getLogsForConversation(item.conv).then(aLogs => {
         if (contactlistbox.selectedItem != item) {
           return;
         }
         this._showLogList(aLogs);
       });
 
       document
         .querySelectorAll("#contextPaneFlexibleBox .conv-chat")
@@ -1055,17 +1053,17 @@ var chatHandler = {
       this.observedContact = contact;
 
       document
         .querySelectorAll("#contextPaneFlexibleBox .conv-chat")
         .forEach(e => {
           e.setAttribute("hidden", "true");
         });
 
-      imServices.logs.getLogsForContact(contact).then(aLogs => {
+      IMServices.logs.getLogsForContact(contact).then(aLogs => {
         if (contactlistbox.selectedItem != item) {
           return;
         }
         if (!this._showLogList(aLogs, true)) {
           hideConversationsBoxPanels();
           document.getElementById("logDisplay").hidden = false;
           document.getElementById("logDisplayBrowserBox").hidden = false;
           document.getElementById("noPreviousConvScreen").hidden = true;
@@ -1162,17 +1160,17 @@ var chatHandler = {
     return (this._colorCache[aName] = Math.round(res) % 360);
   },
 
   _placeHolderButtonId: "",
   _updateNoConvPlaceHolder() {
     let connected = false;
     let hasAccount = false;
     let canJoinChat = false;
-    for (let account of imServices.accounts.getAccounts()) {
+    for (let account of IMServices.accounts.getAccounts()) {
       hasAccount = true;
       if (account.connected) {
         connected = true;
         if (account.canJoinChat) {
           canJoinChat = true;
           break;
         }
       }
@@ -1699,22 +1697,22 @@ var chatHandler = {
       "conversation-update-type",
     ].forEach(chatHandler._addObserver);
 
     chatHandler._updateNoConvPlaceHolder();
     statusSelector.init();
   },
   _observedTopics: [],
   _addObserver(aTopic) {
-    imServices.obs.addObserver(chatHandler, aTopic);
+    Services.obs.addObserver(chatHandler, aTopic);
     chatHandler._observedTopics.push(aTopic);
   },
   _removeObservers() {
     for (let topic of this._observedTopics) {
-      imServices.obs.removeObserver(this, topic);
+      Services.obs.removeObserver(this, topic);
     }
   },
   // TODO move this function away from here and test it.
   _getNextUnreadConversation(aConversations, aCurrent, aReverse) {
     let convCount = aConversations.length;
     if (!convCount) {
       return -1;
     }
@@ -1873,17 +1871,17 @@ var chatHandler = {
       this.initAfterChatCore();
     } else {
       this.ChatCore.init();
       this._addObserver("chat-core-initialized");
     }
 
     if (ChatEncryption.otrEnabled) {
       new Promise(resolve => {
-        if (Services.core.initialized) {
+        if (IMServices.core.initialized) {
           resolve();
           return;
         }
         function initObserver() {
           Services.obs.removeObserver(initObserver, "prpl-init");
           resolve();
         }
         Services.obs.addObserver(initObserver, "prpl-init");
--- a/mail/components/im/content/imAccountWizard.js
+++ b/mail/components/im/content/imAccountWizard.js
@@ -1,16 +1,17 @@
 /* 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/. */
 
 // chat/content/imAccountOptionsHelper.js
 /* globals accountOptionsHelper */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { MailServices } = ChromeUtils.import(
   "resource:///modules/MailServices.jsm"
 );
 var { ChatIcons } = ChromeUtils.import("resource:///modules/chatIcons.jsm");
 
 var PREF_EXTENSIONS_GETMOREPROTOCOLSURL = "extensions.getMoreProtocolsURL";
 
 var accountWizard = {
@@ -39,22 +40,22 @@ var accountWizard = {
     );
     let accountSummaryPage = document.getElementById("accountsummary");
     accountSummaryPage.addEventListener(
       "pageshow",
       this.showSummary.bind(this)
     );
 
     // Ensure the im core is initialized before we get a list of protocols.
-    Services.core.init();
+    IMServices.core.init();
 
     accountWizard.setGetMoreProtocols();
 
     var protoList = document.getElementById("protolist");
-    var protos = Services.core.getProtocols();
+    var protos = IMServices.core.getProtocols();
     protos.sort((a, b) => {
       if (a.name < b.name) {
         return -1;
       }
       return a.name > b.name ? 1 : 0;
     });
     protos.forEach(function(proto) {
       let image = document.createElement("img");
@@ -149,17 +150,17 @@ var accountWizard = {
       }
     }
     this.checkUsername();
   },
 
   selectProtocol() {
     var protoList = document.getElementById("protolist");
     var id = protoList.selectedItem.value;
-    this.proto = Services.core.getProtocolById(id);
+    this.proto = IMServices.core.getProtocolById(id);
   },
 
   /**
    * Create a new input field for receiving a username.
    *
    * @param {string} aName - The id for the input.
    * @param {string} aLabel - The text for the username label.
    * @param {Element} grid - A container with a two column grid display to
@@ -396,17 +397,17 @@ var accountWizard = {
     for (let i = 0; i < this.prefs.length; ++i) {
       let opt = this.prefs[i];
       let label = bundle.getFormattedString("accountColon", [opt.opt.label]);
       this.createSummaryRow(label, opt.value, rows);
     }
   },
 
   createAccount() {
-    var acc = Services.accounts.createAccount(this.username, this.proto.id);
+    var acc = IMServices.accounts.createAccount(this.username, this.proto.id);
     if (!this.proto.noPassword && this.password) {
       acc.password = this.password;
     }
     if (this.alias) {
       acc.alias = this.alias;
     }
 
     for (let i = 0; i < this.prefs.length; ++i) {
--- a/mail/components/im/content/imAccounts.js
+++ b/mail/components/im/content/imAccounts.js
@@ -1,17 +1,18 @@
 /* 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/. */
 
 /* globals MozElements */
 /* globals statusSelector */
 /* globals MsgAccountManager */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { MailServices } = ChromeUtils.import(
   "resource:///modules/MailServices.jsm"
 );
 var { DownloadUtils } = ChromeUtils.import(
   "resource://gre/modules/DownloadUtils.jsm"
 );
 ChromeUtils.defineModuleGetter(
   this,
@@ -54,17 +55,17 @@ var gAccountManager = {
   },
 
   load() {
     // Wait until the password service is ready before offering anything.
     Services.logins.initializationPromise.then(
       () => {
         this.accountList = document.getElementById("accountlist");
         let defaultID;
-        Services.core.init(); // ensure the imCore is initialized.
+        IMServices.core.init(); // ensure the imCore is initialized.
         for (let acc of this.getAccounts()) {
           let elt = document.createXULElement("richlistitem", {
             is: "chat-account-richlistitem",
           });
           this.accountList.appendChild(elt);
           elt.build(acc);
           if (
             !defaultID &&
@@ -515,43 +516,43 @@ var gAccountManager = {
           /^(dis)?connect$/.test(target.getAttribute("anonid")))
       ) {
         this.selectedItem.buttons.proceedDefaultAction();
       }
     }
   },
 
   *getAccounts() {
-    for (let account of Services.accounts.getAccounts()) {
+    for (let account of IMServices.accounts.getAccounts()) {
       yield account;
     }
   },
 
   openDialog(aUrl, aArgs) {
     this.modalDialog = true;
     window.openDialog(aUrl, "", "chrome,modal,titlebar,centerscreen", aArgs);
     this.modalDialog = false;
   },
 
   setAutoLoginNotification() {
-    var as = Services.accounts;
+    var as = IMServices.accounts;
     var autoLoginStatus = as.autoLoginStatus;
     let isOffline = false;
     let crashCount = 0;
     for (let acc of this.getAccounts()) {
       if (
         acc.autoLogin &&
         acc.firstConnectionState == acc.FIRST_CONNECTION_CRASHED
       ) {
         ++crashCount;
       }
     }
 
     if (autoLoginStatus == as.AUTOLOGIN_ENABLED && crashCount == 0) {
-      let status = Services.core.globalUserStatus.statusType;
+      let status = IMServices.core.globalUserStatus.statusType;
       this.setOffline(isOffline || status == Ci.imIStatusInfo.STATUS_OFFLINE);
       return;
     }
 
     var bundle = document.getElementById("accountsBundle");
     let box = this.msgNotificationBar;
     var prio = box.PRIORITY_INFO_HIGH;
     var connectNowButton = {
@@ -600,17 +601,17 @@ var gAccountManager = {
         );
         prio = box.PRIORITY_WARNING_MEDIUM;
         connectNowButton.callback = this.processCrashedAccountsLogin;
         break;
 
       default:
         barLabel = bundle.getString("accountsManager.notification.other.label");
     }
-    let status = Services.core.globalUserStatus.statusType;
+    let status = IMServices.core.globalUserStatus.statusType;
     this.setOffline(isOffline || status == Ci.imIStatusInfo.STATUS_OFFLINE);
 
     box.appendNotification(
       "autologinStatus",
       {
         label: barLabel,
         priority: prio,
       },
@@ -619,17 +620,17 @@ var gAccountManager = {
   },
   processAutoLogin() {
     var ioService = Services.io;
     if (ioService.offline) {
       ioService.manageOfflineStatus = false;
       ioService.offline = false;
     }
 
-    Services.accounts.processAutoLogin();
+    IMServices.accounts.processAutoLogin();
 
     gAccountManager.accountList.selectedItem.setFocus();
   },
   processCrashedAccountsLogin() {
     for (let acc in gAccountManager.getAccounts()) {
       if (
         acc.disconnected &&
         acc.autoLogin &&
--- a/mail/components/im/content/imStatusSelector.js
+++ b/mail/components/im/content/imStatusSelector.js
@@ -1,38 +1,39 @@
 /* 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/. */
 
 var { Status } = ChromeUtils.import("resource:///modules/imStatusUtils.jsm");
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { ChatIcons } = ChromeUtils.import("resource:///modules/chatIcons.jsm");
 
 var statusSelector = {
   observe(aSubject, aTopic, aMsg) {
     if (aTopic == "status-changed") {
       this.displayCurrentStatus();
     } else if (aTopic == "user-icon-changed") {
       this.displayUserIcon();
     } else if (aTopic == "user-display-name-changed") {
       this.displayUserDisplayName();
     }
   },
 
   displayUserIcon() {
-    let icon = Services.core.globalUserStatus.getUserIcon();
+    let icon = IMServices.core.globalUserStatus.getUserIcon();
     ChatIcons.setUserIconSrc(
       document.getElementById("userIcon"),
       icon?.spec,
       true
     );
   },
 
   displayUserDisplayName() {
-    let displayName = Services.core.globalUserStatus.displayName;
+    let displayName = IMServices.core.globalUserStatus.displayName;
     let elt = document.getElementById("displayName");
     if (displayName) {
       elt.removeAttribute("usingDefault");
     } else {
       let bundle = Services.strings.createBundle(
         "chrome://messenger/locale/chat.properties"
       );
       displayName = bundle.GetStringFromName("displayNameEmptyText");
@@ -48,17 +49,17 @@ var statusSelector = {
     let statusString = Status.toLabel(aStatusType);
     let statusTypeIcon = document.getElementById("statusTypeIcon");
     statusTypeIcon.setAttribute("status", aStatusType);
     statusTypeIcon.setAttribute("tooltiptext", statusString);
     return statusString;
   },
 
   displayCurrentStatus() {
-    let us = Services.core.globalUserStatus;
+    let us = IMServices.core.globalUserStatus;
     let status = Status.toAttribute(us.statusType);
     let message = status == "offline" ? "" : us.statusText;
     let statusMessage = document.getElementById("statusMessageLabel");
     if (!statusMessage) {
       // Chat toolbar not in the DOM yet
       return;
     }
     if (message) {
@@ -70,17 +71,17 @@ var statusSelector = {
     }
     statusMessage.setAttribute("value", message);
     statusMessage.setAttribute("tooltiptext", message);
   },
 
   editStatus(aEvent) {
     let status = aEvent.target.getAttribute("status");
     if (status == "offline") {
-      Services.core.globalUserStatus.setStatus(
+      IMServices.core.globalUserStatus.setStatus(
         Ci.imIStatusInfo.STATUS_OFFLINE,
         ""
       );
     } else if (status) {
       this.startEditStatus(status);
     }
   },
 
@@ -115,17 +116,17 @@ var statusSelector = {
       });
       if (statusMessage.hasAttribute("usingDefault")) {
         if (
           "_statusTypeBeforeEditing" in this &&
           this._statusTypeBeforeEditing == "offline"
         ) {
           statusMessageInput.setAttribute(
             "value",
-            Services.core.globalUserStatus.statusText
+            IMServices.core.globalUserStatus.statusText
           );
         } else {
           statusMessageInput.removeAttribute("value");
         }
       } else {
         statusMessageInput.setAttribute(
           "value",
           statusMessage.getAttribute("value")
@@ -202,17 +203,17 @@ var statusSelector = {
         delete this._statusTypeBeforeEditing;
         delete this._statusTypeEditing;
       }
       // apply the new status only if it is different from the current one
       if (
         newStatus != Ci.imIStatusInfo.STATUS_UNKNOWN ||
         statusMessageInput.value != statusMessageInput.getAttribute("value")
       ) {
-        Services.core.globalUserStatus.setStatus(
+        IMServices.core.globalUserStatus.setStatus(
           newStatus,
           statusMessageInput.value
         );
       }
     } else if ("_statusTypeBeforeEditing" in this) {
       this.displayStatusType(this._statusTypeBeforeEditing);
       delete this._statusTypeBeforeEditing;
       delete this._statusTypeEditing;
@@ -249,17 +250,17 @@ var statusSelector = {
       bundle.GetStringFromName("userIconFilePickerTitle"),
       nsIFilePicker.modeOpen
     );
     fp.appendFilters(nsIFilePicker.filterImages);
     fp.open(rv => {
       if (rv != nsIFilePicker.returnOK || !fp.file) {
         return;
       }
-      Services.core.globalUserStatus.setUserIcon(fp.file);
+      IMServices.core.globalUserStatus.setUserIcon(fp.file);
     });
   },
 
   displayNameClick() {
     let displayName = document.getElementById("displayName");
     let displayNameInput = document.getElementById("displayNameInput");
     displayName.setAttribute("hidden", "true");
     displayNameInput.removeAttribute("hidden");
@@ -317,17 +318,17 @@ var statusSelector = {
     let displayNameInput = document.getElementById("displayNameInput");
     displayName.removeAttribute("hidden");
     displayNameInput.toggleAttribute("hidden", "true");
     // Apply the new display name only if it is different from the current one.
     if (
       aSave &&
       displayNameInput.value != displayNameInput.getAttribute("value")
     ) {
-      Services.core.globalUserStatus.displayName = displayNameInput.value;
+      IMServices.core.globalUserStatus.displayName = displayNameInput.value;
     } else if (displayName.hasAttribute("usingDefault")) {
       displayName.setAttribute(
         "value",
         displayName.getAttribute("usingDefault")
       );
     }
 
     displayNameInput.removeAttribute("editing");
--- a/mail/components/im/content/joinchat.js
+++ b/mail/components/im/content/joinchat.js
@@ -1,21 +1,22 @@
 /* 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/. */
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 var { ChatIcons } = ChromeUtils.import("resource:///modules/chatIcons.jsm");
 
 var autoJoinPref = "autoJoin";
 
 var joinChat = {
   onload() {
     var accountList = document.getElementById("accountlist");
-    for (let acc of Services.accounts.getAccounts()) {
+    for (let acc of IMServices.accounts.getAccounts()) {
       if (!acc.connected || !acc.canJoinChat) {
         continue;
       }
       var proto = acc.protocol;
       var item = accountList.appendItem(acc.name, acc.id, proto.name);
       item.setAttribute("image", ChatIcons.getProtocolIconURI(proto));
       item.setAttribute("class", "menuitem-iconic");
       item.account = acc;
@@ -136,17 +137,17 @@ var joinChat = {
 
     let name;
     if (protoId == "prpl-irc") {
       name = values.getValue("channel");
     } else {
       name = values.getValue("room") + "@" + values.getValue("server");
     }
 
-    let conv = Services.conversations.getConversationByNameAndAccount(
+    let conv = IMServices.conversations.getConversationByNameAndAccount(
       name,
       account,
       true
     );
     if (conv) {
       let mailWindow = Services.wm.getMostRecentWindow("mail:3pane");
       if (mailWindow) {
         mailWindow.focus();
--- a/mail/components/im/modules/chatHandler.jsm
+++ b/mail/components/im/modules/chatHandler.jsm
@@ -1,15 +1,16 @@
 /* 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/. */
 
 const EXPORTED_SYMBOLS = ["allContacts", "onlineContacts", "ChatCore"];
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { MailServices } = ChromeUtils.import(
   "resource:///modules/MailServices.jsm"
 );
 
 var allContacts = {};
 var onlineContacts = {};
 
 var ChatCore = {
@@ -34,24 +35,24 @@ var ChatCore = {
     // waits for the asynchronous initialization of the password service.
     Cc["@mozilla.org/messenger/msgAsyncPrompter;1"]
       .getService(Ci.nsIMsgAsyncPrompter)
       .queueAsyncAuthPrompt("im", false, {
         onPromptStartAsync(callback) {
           callback.onAuthResult(this.onPromptStart());
         },
         onPromptStart() {
-          Services.core.init();
+          IMServices.core.init();
 
           // Find the accounts that exist in the im account service but
           // not in nsMsgAccountManager. They have probably been lost if
           // the user has used an older version of Thunderbird on a
           // profile with IM accounts. See bug 736035.
           let accountsById = {};
-          for (let account of Services.accounts.getAccounts()) {
+          for (let account of IMServices.accounts.getAccounts()) {
             accountsById[account.numericId] = account;
           }
           let mgr = MailServices.accounts;
           for (let account of mgr.accounts) {
             let incomingServer = account.incomingServer;
             if (!incomingServer || incomingServer.type != "im") {
               continue;
             }
@@ -71,17 +72,17 @@ var ChatCore = {
             let acc = mgr.createAccount();
             // Avoid new folder notifications.
             inServer.valid = false;
             acc.incomingServer = inServer;
             inServer.valid = true;
             mgr.notifyServerLoaded(inServer);
           }
 
-          Services.tags.getTags().forEach(function(aTag) {
+          IMServices.tags.getTags().forEach(function(aTag) {
             aTag.getContacts().forEach(function(aContact) {
               let name = aContact.preferredBuddy.normalizedName;
               allContacts[name] = aContact;
             });
           });
 
           ChatCore.initialized = true;
           Services.obs.notifyObservers(null, "chat-core-initialized");
--- a/mail/components/im/modules/chatNotifications.jsm
+++ b/mail/components/im/modules/chatNotifications.jsm
@@ -1,15 +1,16 @@
 /* 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/. */
 
 const EXPORTED_SYMBOLS = ["Notifications"];
 
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { AppConstants } = ChromeUtils.import(
   "resource://gre/modules/AppConstants.jsm"
 );
 const { PluralForm } = ChromeUtils.import(
   "resource://gre/modules/PluralForm.jsm"
 );
 const { clearTimeout, setTimeout } = ChromeUtils.import(
   "resource://gre/modules/Timer.jsm"
@@ -152,17 +153,17 @@ var Notifications = {
 
         // If there is a timeout set, clear it.
         clearTimeout(this._timeoutId);
         this._heldMessage = null;
         this._msgCounter = 0;
         this._lastMessageTime = 0;
         this._lastMessageSender = null;
         // Focus the conversation if the notification is clicked.
-        let uiConv = Services.conversations.getUIConversation(
+        let uiConv = IMServices.conversations.getUIConversation(
           aMessage.conversation
         );
         let mainWindow = Services.wm.getMostRecentWindow("mail:3pane");
         if (mainWindow) {
           mainWindow.focus();
           mainWindow.showChatTab();
           mainWindow.chatHandler.focusConversation(uiConv);
         } else {
--- a/mail/components/im/modules/index_im.jsm
+++ b/mail/components/im/modules/index_im.jsm
@@ -10,17 +10,18 @@ const { Gloda } = ChromeUtils.import(
   "resource:///modules/gloda/GlodaPublic.jsm"
 );
 const { GlodaAccount } = ChromeUtils.import(
   "resource:///modules/gloda/GlodaDataModel.jsm"
 );
 const { GlodaIndexer, IndexingJob } = ChromeUtils.import(
   "resource:///modules/gloda/GlodaIndexer.jsm"
 );
-const { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 const { MailServices } = ChromeUtils.import(
   "resource:///modules/MailServices.jsm"
 );
 const { FileUtils } = ChromeUtils.import(
   "resource://gre/modules/FileUtils.jsm"
 );
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
@@ -470,17 +471,17 @@ var GlodaIMIndexer = {
         convObj: {},
       };
     }
 
     let conv = this._knownConversations[convId];
     (async () => {
       // We need to get the log files every time, because a new log file might
       // have been started since we last got them.
-      let logFiles = await Services.logs.getLogPathsForConversation(
+      let logFiles = await IMServices.logs.getLogPathsForConversation(
         aConversation
       );
       if (!logFiles || !logFiles.length) {
         // No log files exist yet, nothing to do!
         return;
       }
 
       if (conv.logFileCount == undefined) {
@@ -601,17 +602,17 @@ var GlodaIMIndexer = {
       delete this._knownConversations[convId];
       return;
     }
 
     if (aTopic == "new-text" && !aSubject.noLog) {
       // Ok, some new text is about to be put into a conversation. For this
       // notification, aSubject is a prplIMessage.
       let conv = aSubject.conversation;
-      let uiConv = Services.conversations.getUIConversation(conv);
+      let uiConv = IMServices.conversations.getUIConversation(conv);
 
       // We only want to schedule an indexing job if this message is
       // immediately visible to the user. We figure this out by finding
       // the unread message count on the associated UIConversation for this
       // message. If the unread count is 0, we know that the message has been
       // displayed to the user.
       if (uiConv.unreadIncomingMessageCount == 0) {
         this._scheduleIndexingJob(conv);
@@ -675,17 +676,17 @@ var GlodaIMIndexer = {
    */
   async indexIMConversation(
     aCallbackHandle,
     aLogPath,
     aLastModifiedTime,
     aCache,
     aGlodaConv
   ) {
-    let log = await Services.logs.getLogFromFile(aLogPath);
+    let log = await IMServices.logs.getLogFromFile(aLogPath);
     let logConv = await log.getConversation();
 
     // Ignore corrupted log files.
     if (!logConv) {
       return Gloda.kWorkDone;
     }
 
     let fileName = PathUtils.filename(aLogPath);
--- a/mail/components/im/test/TestProtocol.jsm
+++ b/mail/components/im/test/TestProtocol.jsm
@@ -12,17 +12,17 @@ var {
   GenericProtocolPrototype,
   GenericConvChatBuddyPrototype,
   GenericMessagePrototype,
   TooltipInfo,
 } = ChromeUtils.import("resource:///modules/jsProtoHelper.jsm");
 var { ComponentUtils } = ChromeUtils.import(
   "resource://gre/modules/ComponentUtils.jsm"
 );
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 var { nsSimpleEnumerator } = ChromeUtils.import(
   "resource:///modules/imXPCOMUtils.jsm"
 );
 
 function Message(who, text, properties, conversation) {
   this._init(who, text, properties, conversation);
   this.displayed = new Promise(resolve => {
     this._onDisplayed = resolve;
--- a/mail/components/im/test/browser/browser_chatTelemetry.js
+++ b/mail/components/im/test/browser/browser_chatTelemetry.js
@@ -4,17 +4,20 @@
 
 let { TelemetryTestUtils } = ChromeUtils.import(
   "resource://testing-common/TelemetryTestUtils.jsm"
 );
 
 add_task(async function testMessageThemeTelemetry() {
   Services.telemetry.clearScalars();
 
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   let scalars = TelemetryTestUtils.getProcessScalars("parent");
   ok(
     !scalars["tb.chat.active_message_theme"],
     "Active chat theme not reported without open conversation."
   );
@@ -39,10 +42,10 @@ add_task(async function testMessageTheme
   is(
     scalars["tb.chat.active_message_theme"],
     "mail:default",
     "Active chat message theme and variant reported after opening conversation."
   );
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
--- a/mail/components/im/test/browser/browser_contextMenu.js
+++ b/mail/components/im/test/browser/browser_contextMenu.js
@@ -1,14 +1,17 @@
 /* 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/. */
 
 add_task(async function testContextMenu() {
-  const account = Services.accounts.createAccount("context", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "context",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const conversation = account.prplAccount.wrappedJSObject.makeDM("context");
   const convNode = getConversationItem(conversation);
@@ -41,21 +44,24 @@ add_task(async function testContextMenu(
 
   const popupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
   // Assume normal context menu semantics work and just close it directly.
   contextMenu.hidePopup();
   await popupHidden;
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testMessageContextMenuOnLink() {
-  const account = Services.accounts.createAccount("context", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "context",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
   const conversation = account.prplAccount.wrappedJSObject.makeDM("linker");
 
   const convNode = getConversationItem(conversation);
@@ -147,21 +153,24 @@ add_task(async function testMessageConte
     "popuphidden"
   );
   // Assume normal context menu semantics work and just close it directly.
   contextMenu.hidePopup();
   await popupHiddenAgain;
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testMessageAction() {
-  const account = Services.accounts.createAccount("context", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "context",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const conversation = account.prplAccount.wrappedJSObject.makeDM("context");
   const convNode = getConversationItem(conversation);
@@ -225,10 +234,10 @@ add_task(async function testMessageActio
   );
   item.click();
   // Assume normal context menu semantics work and just close it.
   contextMenu.hidePopup();
   await Promise.all([message.actionRan, popupHiddenAgain]);
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
--- a/mail/components/im/test/browser/browser_logs.js
+++ b/mail/components/im/test/browser/browser_logs.js
@@ -2,17 +2,20 @@
  * 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/. */
 
 const { mailTestUtils } = ChromeUtils.import(
   "resource://testing-common/mailnews/MailTestUtils.jsm"
 );
 
 add_task(async function testTopicRestored() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const conversation = account.prplAccount.wrappedJSObject.makeMUC(
     "logs topic"
@@ -87,10 +90,10 @@ add_task(async function testTopicRestore
     {}
   );
 
   ok(BrowserTestUtils.is_hidden(logBrowser));
   is(chatTopInfo.topic.value, "foo bar");
 
   newConversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
--- a/mail/components/im/test/browser/browser_messagesMail.js
+++ b/mail/components/im/test/browser/browser_messagesMail.js
@@ -1,14 +1,17 @@
 /* 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/. */
 
 add_task(async function testCollapse() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const conversation = account.prplAccount.wrappedJSObject.makeDM("collapse");
   const convNode = getConversationItem(conversation);
@@ -58,21 +61,24 @@ add_task(async function testCollapse() {
       attributes: true,
       attributeFilter: ["class"],
     },
     () => !hiddenGroup.classList.contains("hide-children")
   );
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testGrouping() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(
     BrowserTestUtils.is_visible(document.getElementById("chatPanel")),
     "Chat tab is visible"
   );
@@ -127,21 +133,24 @@ add_task(async function testGrouping() {
   is(
     messageParent.childElementCount,
     3,
     "All three messages are their own top level element"
   );
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testSystemMessageReplacement() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(
     BrowserTestUtils.is_visible(document.getElementById("chatPanel")),
     "Chat tab is visible"
   );
@@ -209,17 +218,17 @@ add_task(async function testSystemMessag
   is(
     firstMessage.querySelector(".body").textContent,
     "better system message",
     "Message content was updated"
   );
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 function addNotice(conversation, uiConversation) {
   conversation.addNotice();
   return BrowserTestUtils.waitForEvent(
     uiConversation.convBrowser,
     "MessagesDisplayed"
   );
--- a/mail/components/im/test/browser/browser_readMessage.js
+++ b/mail/components/im/test/browser/browser_readMessage.js
@@ -1,14 +1,17 @@
 /* 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/. */
 
 add_task(async function testDisplayed() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const conversation = account.prplAccount.wrappedJSObject.makeMUC("collapse");
   const convNode = getConversationItem(conversation);
@@ -37,10 +40,10 @@ add_task(async function testDisplayed() 
 
   await browserDisplayed;
   await message.displayed;
 
   ok(!convNode.hasAttribute("unread"), "Message read");
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
--- a/mail/components/im/test/browser/browser_removeMessage.js
+++ b/mail/components/im/test/browser/browser_removeMessage.js
@@ -1,14 +1,17 @@
 /* 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/. */
 
 add_task(async function testRemove() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const conversation = account.prplAccount.wrappedJSObject.makeMUC("collapse");
   const convNode = getConversationItem(conversation);
@@ -42,10 +45,10 @@ add_task(async function testRemove() {
   conversation.removeMessage("foo");
   await updateTextPromise;
   await TestUtils.waitForTick();
 
   ok(!messageParent.querySelector(".message"));
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
--- a/mail/components/im/test/browser/browser_requestNotifications.js
+++ b/mail/components/im/test/browser/browser_requestNotifications.js
@@ -1,14 +1,17 @@
 /* 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/. */
 
 add_task(async function testGrantingBuddyRequest() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   const prplAccount = account.prplAccount.wrappedJSObject;
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const notificationTopic = TestUtils.topicObserved(
@@ -41,21 +44,24 @@ add_task(async function testGrantingBudd
     {}
   );
   await requestPromise;
 
   await closePromise;
   ok(!notificationBox.getNotificationWithValue(value), "notification closed");
 
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testCancellingBuddyRequest() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   const prplAccount = account.prplAccount.wrappedJSObject;
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const notificationTopic = TestUtils.topicObserved(
@@ -91,21 +97,24 @@ add_task(async function testCancellingBu
   const [canceledRequest] = await cancelTopic;
   is(canceledRequest.userName, request.userName);
   is(canceledRequest.account.id, request.account.id);
 
   await closePromise;
   ok(!notificationBox.getNotificationWithValue(value), "notification closed");
 
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testDenyingBuddyRequest() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   const prplAccount = account.prplAccount.wrappedJSObject;
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const notificationTopic = TestUtils.topicObserved(
@@ -133,21 +142,24 @@ add_task(async function testDenyingBuddy
     {}
   );
   await requestPromise;
 
   await closePromise;
   ok(!notificationBox.getNotificationWithValue(value), "notification closed");
 
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testGrantingChatRequest() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   const prplAccount = account.prplAccount.wrappedJSObject;
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const requestTopic = TestUtils.topicObserved("conv-authorization-request");
@@ -180,21 +192,24 @@ add_task(async function testGrantingChat
   await requestPromise;
   const result = await request.completePromise;
   ok(result);
 
   await closePromise;
   ok(!notificationBox.getNotificationWithValue(value), "notification closed");
 
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testCancellingChatRequest() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   const prplAccount = account.prplAccount.wrappedJSObject;
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(
     BrowserTestUtils.is_visible(document.getElementById("chatPanel")),
     "chat tab visible"
@@ -231,21 +246,24 @@ add_task(async function testCancellingCh
     /Cancelled/,
     "completePromise is rejected to indicate cancellation"
   );
 
   await closePromise;
   ok(!notificationBox.getNotificationWithValue(value), "notification closed");
 
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testDenyingChatRequest() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   const prplAccount = account.prplAccount.wrappedJSObject;
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const requestTopic = TestUtils.topicObserved("conv-authorization-request");
@@ -275,21 +293,24 @@ add_task(async function testDenyingChatR
   await requestPromise;
   const result = await request.completePromise;
   ok(!result);
 
   await closePromise;
   ok(!notificationBox.getNotificationWithValue(value), "notification closed");
 
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testUndenyableChatRequest() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   const prplAccount = account.prplAccount.wrappedJSObject;
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const requestTopic = TestUtils.topicObserved("conv-authorization-request");
@@ -320,10 +341,10 @@ add_task(async function testUndenyableCh
   await requestPromise;
   const result = await request.completePromise;
   ok(result);
 
   await closePromise;
   ok(!notificationBox.getNotificationWithValue(value), "notification closed");
 
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
--- a/mail/components/im/test/browser/browser_spacesToolbarChat.js
+++ b/mail/components/im/test/browser/browser_spacesToolbarChat.js
@@ -1,15 +1,18 @@
 /* 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/. */
 
 add_task(async function test_spacesToolbarChatBadgeMUC() {
   window.gSpacesToolbar.toggleToolbar(false);
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   if (window.chatHandler._chatButtonUpdatePending) {
     await TestUtils.waitForTick();
   }
 
   const chatButton = document.getElementById("chatButton");
@@ -52,22 +55,25 @@ add_task(async function test_spacesToolb
     () => unreadContainer.textContent !== unreadContainerText
   );
 
   is(unreadContainer.textContent, "1", "Unread count is in badge");
   ok(unreadContainer.title);
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function test_spacesToolbarChatBadgeDM() {
   window.gSpacesToolbar.toggleToolbar(false);
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   if (window.chatHandler._chatButtonUpdatePending) {
     await TestUtils.waitForTick();
   }
 
   const chatButton = document.getElementById("chatButton");
@@ -121,22 +127,25 @@ add_task(async function test_spacesToolb
 
   ok(
     !chatButton.classList.contains("has-badge"),
     "Unread badge is hidden again"
   );
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function test_spacesToolbarPinnedChatBadgeMUC() {
   window.gSpacesToolbar.toggleToolbar(true);
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   if (window.chatHandler._chatButtonUpdatePending) {
     await TestUtils.waitForTick();
   }
 
   const spacesPopupButtonChat = document.getElementById(
@@ -180,22 +189,25 @@ add_task(async function test_spacesToolb
     document
       .getElementById("spacesPinnedButton")
       .classList.contains("has-badge"),
     "Unread state is propagated to pinned menu button"
   );
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function test_spacesToolbarPinnedChatBadgeDM() {
   window.gSpacesToolbar.toggleToolbar(true);
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   if (window.chatHandler._chatButtonUpdatePending) {
     await TestUtils.waitForTick();
   }
 
   const spacesPopupButtonChat = document.getElementById(
@@ -236,10 +248,10 @@ add_task(async function test_spacesToolb
   ok(
     !spacesPopupButtonChat.classList.contains("has-badge"),
     "Unread badge is hidden again"
   );
   ok(!spacesPinnedButton.classList.contains("has-badge"));
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
--- a/mail/components/im/test/browser/browser_tooltips.js
+++ b/mail/components/im/test/browser/browser_tooltips.js
@@ -1,14 +1,17 @@
 /* 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/. */
 
 add_task(async function testMUCMessageSenderTooltip() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   const conversation = account.prplAccount.wrappedJSObject.makeMUC("tooltips");
   const convNode = getConversationItem(conversation);
   ok(convNode);
 
@@ -98,21 +101,24 @@ add_task(async function testMUCMessageSe
       await hideTooltip(tooltip, chatConv.convBrowser);
     }
   } finally {
     window.windowUtils.disableNonTestMouseEvents(false);
   }
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 add_task(async function testTimestampTooltip() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   const conversation = account.prplAccount.wrappedJSObject.makeMUC("tooltips");
   const convNode = getConversationItem(conversation);
   ok(convNode);
 
@@ -159,17 +165,17 @@ add_task(async function testTimestampToo
     is(htmlTooltip.textContent, expectedText);
     await hideTooltip(tooltip, chatConv.convBrowser);
   } finally {
     window.windowUtils.disableNonTestMouseEvents(false);
   }
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
 
 async function showTooltip(elementSelector, tooltip, browser) {
   const popupShown = BrowserTestUtils.waitForEvent(tooltip, "popupshown");
   await BrowserTestUtils.synthesizeMouseAtCenter(
     elementSelector,
     { type: "mousemove" },
     browser
--- a/mail/components/im/test/browser/browser_updateMessage.js
+++ b/mail/components/im/test/browser/browser_updateMessage.js
@@ -1,14 +1,17 @@
 /* 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/. */
 
 add_task(async function testUpdate() {
-  const account = Services.accounts.createAccount("testuser", "prpl-mochitest");
+  const account = IMServices.accounts.createAccount(
+    "testuser",
+    "prpl-mochitest"
+  );
   account.password = "this is a test";
   account.connect();
 
   await openChatTab();
   ok(BrowserTestUtils.is_visible(document.getElementById("chatPanel")));
 
   const conversation = account.prplAccount.wrappedJSObject.makeMUC("collapse");
   const convNode = getConversationItem(conversation);
@@ -50,10 +53,10 @@ add_task(async function testUpdate() {
     messageParent.querySelector(".message.incoming:nth-child(1) .ib-msg-txt")
       .textContent,
     "bye world",
     "message text updated"
   );
 
   conversation.close();
   account.disconnect();
-  Services.accounts.deleteAccount(account.id);
+  IMServices.accounts.deleteAccount(account.id);
 });
--- a/mail/components/im/test/browser/head.js
+++ b/mail/components/im/test/browser/head.js
@@ -1,16 +1,17 @@
 /* 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/. */
 
 var { registerTestProtocol, unregisterTestProtocol } = ChromeUtils.import(
   "resource://testing-common/TestProtocol.jsm"
 );
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 
 async function openChatTab() {
   let tabmail = document.getElementById("tabmail");
   let chatMode = tabmail.tabModes.chat;
 
   if (chatMode.tabs.length == 1) {
     tabmail.selectedTab = chatMode.tabs[0];
   } else {
@@ -99,33 +100,33 @@ function waitForNotification(target, exp
 }
 
 registerTestProtocol();
 
 registerCleanupFunction(async () => {
   // Make sure the chat state is clean
   await closeChatTab();
 
-  const conversations = Services.conversations.getConversations();
+  const conversations = IMServices.conversations.getConversations();
   is(conversations.length, 0, "All conversations were closed by their test");
   for (const conversation of conversations) {
     try {
       conversation.close();
     } catch (error) {
       ok(false, error.message);
     }
   }
 
-  const accounts = Services.accounts.getAccounts();
+  const accounts = IMServices.accounts.getAccounts();
   is(accounts.length, 0, "All accounts were removed by their test");
   for (const account of accounts) {
     try {
       if (account.connected || account.connecting) {
         account.disconnect();
       }
-      Services.accounts.deleteAccount(account.id);
+      IMServices.accounts.deleteAccount(account.id);
     } catch (error) {
       ok(false, "Error deleting account " + account.id + ": " + error.message);
     }
   }
 
   unregisterTestProtocol();
 });
--- a/mail/components/preferences/messagestyle.js
+++ b/mail/components/preferences/messagestyle.js
@@ -6,31 +6,33 @@
 
 var { GenericConvIMPrototype, GenericMessagePrototype } = ChromeUtils.import(
   "resource:///modules/jsProtoHelper.jsm"
 );
 var { getThemeByName, getThemeVariants } = ChromeUtils.import(
   "resource:///modules/imThemes.jsm"
 );
 
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
+
 function Conversation(aName) {
   this._name = aName;
   this._observers = [];
   let now = new Date();
   this._date =
     new Date(now.getFullYear(), now.getMonth(), now.getDate(), 10, 42, 22) *
     1000;
 }
 Conversation.prototype = {
   __proto__: GenericConvIMPrototype,
   account: {
     protocol: { name: "Fake Protocol" },
     alias: "",
     name: "Fake Account",
-    statusInfo: Services.core.globalUserStatus,
+    statusInfo: IMServices.core.globalUserStatus,
   },
 };
 
 function Message(aWho, aMessage, aObject, aConversation) {
   this._init(aWho, aMessage, aObject, aConversation);
 }
 Message.prototype = {
   __proto__: GenericMessagePrototype,
--- a/mail/test/browser/account/browser_accountTelemetry.js
+++ b/mail/test/browser/account/browser_accountTelemetry.js
@@ -5,16 +5,17 @@
 
 /**
  * Test telemetry related to account.
  */
 
 let { MailServices } = ChromeUtils.import(
   "resource:///modules/MailServices.jsm"
 );
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 let { TelemetryTestUtils } = ChromeUtils.import(
   "resource://testing-common/TelemetryTestUtils.jsm"
 );
 let { FeedUtils } = ChromeUtils.import("resource:///modules/FeedUtils.jsm");
 var {
   add_message_to_folder,
   create_message,
   msgGen,
@@ -40,17 +41,17 @@ add_task(async function test_account_typ
   const NUM_IMAP = 3;
   const NUM_RSS = 1;
   const NUM_IRC = 1;
 
   // Add incoming servers.
   let imapServer = MailServices.accounts
     .createIncomingServer("nobody", "foo.invalid", "imap")
     .QueryInterface(Ci.nsIImapIncomingServer);
-  let imAccount = Services.accounts.createAccount(
+  let imAccount = IMServices.accounts.createAccount(
     "telemetry-irc-user",
     "prpl-irc"
   );
   imAccount.autoLogin = false;
   let ircServer = MailServices.accounts.createIncomingServer(
     "nobody",
     "foo.invalid",
     "im"
--- a/mail/test/browser/im/browser_toolbarButtons.js
+++ b/mail/test/browser/im/browser_toolbarButtons.js
@@ -3,17 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 var { mc } = ChromeUtils.import(
   "resource://testing-common/mozmill/FolderDisplayHelpers.jsm"
 );
 
-var { Services } = ChromeUtils.import("resource:///modules/imServices.jsm");
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var { IMServices } = ChromeUtils.import("resource:///modules/IMServices.jsm");
 
 /* This test checks that the toolbar buttons of the chat toolbar are
  * correctly disabled/enabled, and that the placeholder displayed in
  * the middle of the chat tab is correct.
  */
 add_task(function test_toolbar_and_placeholder() {
   Assert.notEqual(
     mc.tabmail.selectedTab.mode.type,
@@ -62,17 +63,17 @@ add_task(function test_toolbar_and_place
     "the Add Buddy button is disabled"
   );
   Assert.ok(
     mc.e("button-join-chat").disabled,
     "the Join Chat button is disabled"
   );
 
   // The next tests require an account, get the unwrapped default IRC account.
-  let account = Services.accounts.getAccountByNumericId(1);
+  let account = IMServices.accounts.getAccountByNumericId(1);
   Assert.equal(
     account.protocol.id,
     "prpl-irc",
     "the default IM account is an IRC account"
   );
   let ircAccount = account.prplAccount.wrappedJSObject;
 
   // Pretend the account is connected and check how the UI reacts