Bug 1584614 - Remove source code for the Provider for Google Calendar. r=darktrojan
authorPhilipp Kewisch <mozilla@kewis.ch>
Sun, 06 Oct 2019 21:51:19 +0200
changeset 37084 d58d9fbdca017d16d2f1bbd23cc53a92447e0b2b
parent 37083 6b88366d415ec0bf89ff6125e683a4a61347ee0f
child 37085 e7476e934b191ffac787208323191c9c034049ce
push id395
push userclokep@gmail.com
push dateMon, 02 Dec 2019 19:38:57 +0000
reviewersdarktrojan
bugs1584614
Bug 1584614 - Remove source code for the Provider for Google Calendar. r=darktrojan
calendar/base/modules/utils/calProviderUtils.jsm
calendar/base/themes/common/widgets/calendar-widgets.css
calendar/locales/en-US/chrome/calendar/providers/gdata/amo.properties
calendar/locales/en-US/chrome/calendar/providers/gdata/gdata.dtd
calendar/locales/en-US/chrome/calendar/providers/gdata/gdata.properties
calendar/locales/filter.py
calendar/locales/l10n.toml
calendar/providers/gdata/Makefile.in
calendar/providers/gdata/components/calGoogleCalendar.js
calendar/providers/gdata/components/calGoogleCalendar.manifest
calendar/providers/gdata/content/browserRequest.css
calendar/providers/gdata/content/browserRequest.js
calendar/providers/gdata/content/browserRequest.xul
calendar/providers/gdata/content/gcal.png
calendar/providers/gdata/content/gdata-bindings.css
calendar/providers/gdata/content/gdata-calendar-creation.js
calendar/providers/gdata/content/gdata-calendar-creation.xul
calendar/providers/gdata/content/gdata-calendar-properties.js
calendar/providers/gdata/content/gdata-calendar-properties.xul
calendar/providers/gdata/content/gdata-event-dialog-reminder.css
calendar/providers/gdata/content/gdata-event-dialog-reminder.js
calendar/providers/gdata/content/gdata-event-dialog-reminder.xul
calendar/providers/gdata/content/gdata-event-dialog.js
calendar/providers/gdata/content/gdata-event-dialog.xul
calendar/providers/gdata/content/gdata-lightning-item-iframe.js
calendar/providers/gdata/content/gdata-lightning-item-iframe.xul
calendar/providers/gdata/content/gdata-lightning-item-toolbar.xul
calendar/providers/gdata/content/gdata-migration-overlay.xul
calendar/providers/gdata/content/gdata-migration-wizard.xul
calendar/providers/gdata/content/gdata-migration.js
calendar/providers/gdata/content/reminder-action-sms.svg
calendar/providers/gdata/defaults/preferences.js
calendar/providers/gdata/jar.mn
calendar/providers/gdata/manifest.json
calendar/providers/gdata/modules/OAuth2.jsm
calendar/providers/gdata/modules/gdataLogging.jsm
calendar/providers/gdata/modules/gdataRequest.jsm
calendar/providers/gdata/modules/gdataSession.jsm
calendar/providers/gdata/modules/gdataUtils.jsm
calendar/providers/gdata/modules/timezoneMap.jsm
calendar/providers/gdata/moz.build
calendar/test/unit/test_gdata_provider.js
calendar/test/unit/xpcshell-libical.ini
mail/app.mozbuild
mail/testsuite-targets.mk
taskcluster/ci/test/tests.yml
taskcluster/comm_taskgraph/manifests/thunderbird_candidates.yml
taskcluster/comm_taskgraph/manifests/thunderbird_nightly.yml
--- a/calendar/base/modules/utils/calProviderUtils.jsm
+++ b/calendar/base/modules/utils/calProviderUtils.jsm
@@ -371,18 +371,16 @@ var calprovider = {
       }
       calprovider.getCalendarDirectory.mDir = dir;
     }
     return calprovider.getCalendarDirectory.mDir.clone();
   },
 
   /**
    * Base prototype to be used implementing a provider.
-   *
-   * @see e.g. providers/gdata
    */
   BaseClass: class {
     /**
      * The transient properties that are not pesisted to storage
      */
     static get mTransientProperties() {
       return {
         "cache.uncachedCalendar": true,
--- a/calendar/base/themes/common/widgets/calendar-widgets.css
+++ b/calendar/base/themes/common/widgets/calendar-widgets.css
@@ -116,22 +116,21 @@ checkbox.treenode-checkbox > .checkbox-l
   cursor:default;
 }
 
 .categories-textbox {
   -moz-appearance: textfield;
 }
 
 /*
- * Note that #calendar-list is used for 3 separate lists that look similar,
+ * Note that #calendar-list is used for 2 separate lists that look similar,
  * but are otherwise independent:
  *
  * - calendar-providerUninstall-dialog.xul
  * - messenger-overlay-sidebar.xul
- * - gdata-calendar-creation.xul
  *
  * Please be careful when changing the following CSS.
  */
 
 #calendar-list-inner-pane > #calendar-list {
   -moz-appearance: none;
   margin: 0;
   border-style: none;
deleted file mode 100644
--- a/calendar/locales/en-US/chrome/calendar/providers/gdata/amo.properties
+++ /dev/null
@@ -1,27 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# The addon name and short description are localized in gdata.properties
-
-# This is the addon description. The en-US version will sometimes have
-# additional news items at the end of the description. If you notice this and
-# would like them translated, please email the author directly.
-# params: %1$S - See amo.faqlocation
-#         %2$S - See amo.website
-# NOTE: This is a multiline string, be sure to end lines with \n\ to make sure
-# it stays that way.
-amo.description=This extension allows Lightning to read and write events and tasks to a Google Calendar.\n\
-\n\
-Please read <a href="%1$S">the FAQ</a> for more details and before filing a bug. Also, be sure to visit the <a href="%2$S">discussion forums</a>, maybe your bug already has a solution!\n\
-\n\
-To search for and submit bugs, visit http://bugzilla.mozilla.org/ \n\
-Product: Calendar\n\
-Component: Provider: GData
-
-# You can change this if you have localized the FAQ on wiki.mozilla.org
-amo.faqlocation=http://wiki.mozilla.org/Calendar:GDATA_Provider
-
-# You can change this if you would like to provide localized support.
-amo.email=
-amo.website=http://groups.google.com/group/provider-for-google-calendar
deleted file mode 100644
--- a/calendar/locales/en-US/chrome/calendar/providers/gdata/gdata.dtd
+++ /dev/null
@@ -1,22 +0,0 @@
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!ENTITY gdata-provider.label "Google Calendar">
-
-<!ENTITY gdata.privacy.default.label "Google Default">
-<!ENTITY gdata.privacy.default.accesskey "D">
-
-<!ENTITY gdata.migration.title "Migrate read-only calendars">
-<!ENTITY gdata.migration.description "The Provider for Google Calendar has detected that you have existing calendars that are only capable of accessing Google Calendar in read-only mode. If you would like to upgrade any of these calendars, please select them below">
-<!ENTITY gdata.migration.upgrade.label "Upgrade">
-<!ENTITY gdata.migration.upgrade.accesskey "U">
-<!ENTITY gdata.migration.showagain.label "Always check ">
-
-<!ENTITY gdata.reminder.default "Default Reminder">
-<!ENTITY gdata.reminder.action.sms.label "Send a Text Message">
-
-<!ENTITY gdata.wizard.session.description "Please pick an existing session or enter your email address to create a new session. You only need one session per account.">
-<!ENTITY gdata.wizard.calendars.description "Please select the calendars and task lists you would like to subscribe to.">
-
-<!ENTITY gdata.wizard.nextstep.description "Please advance to the next step to set up your calendars.">
deleted file mode 100644
--- a/calendar/locales/en-US/chrome/calendar/providers/gdata/gdata.properties
+++ /dev/null
@@ -1,60 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# If you wish to be mentioned as a translator, please make sure your name and
-# email is in the licence block as a contributor. Multiple names are fine too.
-
-# extension information.
-# When localizing, please keep in mind that these strings had to be approved by
-# the Google Brand Features Team. Be sure to make clear that this extension is
-# *FOR* Google Calendar and not *BY* Google. Also, it was explicitly stated,
-# that the phrase "Google Calendar" should be localized just as it is on the
-# localized versions of the Google Calendar UI.
-
-# Extension Manager strings
-extensions.{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}.description=Allows bidirectional access to Google Calendar
-extensions.{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}.name=Provider for Google Calendar
-
-calendarsHeader=Calendars
-taskListsHeader=Task Lists
-
-# LOCALIZATION NOTE (busyTitle):
-# Events with only free/busy access don't have a title, they will use this
-# title instead. The calendar name is used as a parameter, since its often
-# named after the person whose calendar you are viewing.
-# %1$S = The calendar name
-busyTitle=Busy (%1$S)
-
-# LOCALIZATION NOTE (quotaExceeded):
-# This is shown when the request quota has been exceeded.
-# %1$S = The session id (what the user enters as an email
-#                        in the new calendar dialog)
-quotaExceeded=The quota for %1$S has been exceeded, please try again later.
-providerOutdated=This version of the provider has expired, please update to the latest version.
-
-reminderOutOfRange=Google Calendar only allows reminders up to 4 weeks before the event starts.
-
-# LOCALIZATION NOTE (syncProgressEvent):
-# %1$S = The name of the calendar that is being synchronized
-# %2$S = The number of events that have been synchronzed
-# %3$S = The total number of events in the synchronization run
-syncProgressEvent=Synchronizing %1$S event %2$S of %3$S
-
-# LOCALIZATION NOTE (syncProgressTask):
-# %1$S = The name of the calendar that is being synchronized
-# %2$S = The number of tasks that have been synchronzed
-# %3$S = The total number of tasks in the synchronization run
-syncProgressTask=Synchronizing %1$S task %2$S of %3$S
-
-# LOCALIZATION NOTE (syncStatus):
-# %1$S = The name of the calendar that is being synchronized
-syncStatus=Synchronizing Calendar %1$S
-
-# LOCALIZATION NOTE (requestWindowDescription):
-# %1$S - The session id (email) used for authentication
-requestWindowDescription=The Provider for Google Calendar would like to access your account %1$S to retrieve events and tasks. Credentials and calendaring data is only transferred between your computer and Google, no third party sites are involved.
-
-# LOCALIZATION NOTE (requestWindowTitle)
-# %1$S - The session id (email) used for authentication
-requestWindowTitle=Sign in to your account %1$S
--- a/calendar/locales/filter.py
+++ b/calendar/locales/filter.py
@@ -15,14 +15,10 @@ def test(mod, path, entity = None):
   if path == "chrome/calendar/calendar-event-dialog.properties":
     return not re.match(r".*Nounclass[1-9]", entity)
 
   # most extraction related strings are not required
   if path == "chrome/calendar/calendar-extract.properties":
     if not re.match(r"from.today", entity):
       return "report"
 
-  # Provider for Google Calendar AMO strings do not have to be translated
-  if path == "chrome/calendar/providers/gdata/amo.properties":
-    return "report"
-
   # Everything else should be taken into account
   return True
--- a/calendar/locales/l10n.toml
+++ b/calendar/locales/l10n.toml
@@ -77,14 +77,8 @@ locales = [
     key = "re:.*Nounclass[1-9].*"
     action = "ignore"
 
 # most extraction related strings are not required
 [[filters]]
     path = "{l}calendar/chrome/calendar/calendar-extract.properties"
     key = "re:.*from\\.today.*"
     action = "warning"
-
-# Provider for Google Calendar AMO strings do not have to be translated
-[[filters]]
-    path = "{l}calendar/chrome/calendar/providers/gdata/amo.properties"
-    key = "re:."
-    action = "warning"
deleted file mode 100644
--- a/calendar/providers/gdata/Makefile.in
+++ /dev/null
@@ -1,27 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-XPI_PKGNAME = gdata-provider
-
-final_parent = $(ABS_DIST)/bin/extensions
-ifdef MOZ_ARTIFACT_BUILDS
-final_dest = $(final_parent)/{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}
-
-tools::
-	$(RM) -r $(final_dest)
-ifeq ($(OS_ARCH),WINNT)
-	$(NSINSTALL) -D $(final_dest)
-	$(call copy_dir,$(FINAL_TARGET),$(final_dest))
-else
-	$(NSINSTALL) -D $(final_parent)
-	ln -s $(ABS_DIST)/xpi-stage/gdata-provider $(final_dest)
-endif
-endif # MOZ_ARTIFACT_BUILDS
-
-stage-package:
-ifdef MOZ_ARTIFACT_BUILDS
-	$(PYTHON) -u $(MOZILLA_DIR)/build/upload.py $(DIST)/xpi-stage/$(XPI_PKGNAME).xpi
-else
-	$(PYTHON) -u $(MOZILLA_DIR)/build/upload.py $(final_parent)/$(XPI_PKGNAME).xpi
-endif
deleted file mode 100644
--- a/calendar/providers/gdata/components/calGoogleCalendar.js
+++ /dev/null
@@ -1,926 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-// Backwards compatibility with Thunderbird <60.
-if (!("Cc" in this)) {
-  // eslint-disable-next-line mozilla/no-define-cc-etc, no-unused-vars
-  const { classes: Cc, interfaces: Ci, results: Cr } = Components;
-}
-
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-var { stringException } = ChromeUtils.import("resource://gdata-provider/modules/gdataLogging.jsm");
-var { calGoogleRequest, getCorrectedDate, API_BASE } = ChromeUtils.import(
-  "resource://gdata-provider/modules/gdataRequest.jsm"
-);
-var { getGoogleSessionManager } = ChromeUtils.import(
-  "resource://gdata-provider/modules/gdataSession.jsm"
-);
-var {
-  ItemToJSON,
-  JSONToItem,
-  ItemSaver,
-  checkResolveConflict,
-  getGoogleId,
-  getItemMetadata,
-  saveItemMetadata,
-  deleteItemMetadata,
-  migrateItemMetadata,
-  JSONToAlarm,
-} = ChromeUtils.import("resource://gdata-provider/modules/gdataUtils.jsm");
-
-var cIOL = Ci.calIOperationListener;
-
-var MIN_REFRESH_INTERVAL = 30;
-
-/**
- * calGoogleCalendar
- * This Implements a calICalendar Object adapted to the Google Calendar
- * Provider.
- *
- * @class
- * @constructor
- */
-function calGoogleCalendar() {
-  this.initProviderBase();
-  this.mThrottle = Object.create(null);
-}
-
-var calGoogleCalendarClassID = Components.ID("{d1a6e988-4b4d-45a5-ba46-43e501ea96e3}");
-var calGoogleCalendarInterfaces = [Ci.calICalendar, Ci.calISchedulingSupport, Ci.calIChangeLog];
-calGoogleCalendar.prototype = {
-  __proto__: cal.provider.BaseClass.prototype,
-
-  classID: calGoogleCalendarClassID,
-  QueryInterface: cal.generateQI(calGoogleCalendarInterfaces),
-  classInfo: cal.generateCI({
-    classDescription: "Google Calendar Provider",
-    contractID: "@mozilla.org/calendar/calendar;1?type=gdata",
-    classID: calGoogleCalendarClassID,
-    interfaces: calGoogleCalendarInterfaces,
-  }),
-
-  /* Used to reset the local cache between releases */
-  CACHE_DB_VERSION: 3,
-
-  /* Member Variables */
-  mCalendarName: null,
-  mThrottle: null,
-  mThrottleLimits: {
-    calendarList: 3600 * 1000,
-    events: 30 * 1000,
-    tasks: 30 * 1000,
-  },
-
-  /* Public Members */
-  session: null,
-
-  /**
-   * Make sure a session is available.
-   */
-  ensureSession: function() {
-    if (!this.session) {
-      // Now actually set up the session
-      let sessionMgr = getGoogleSessionManager();
-      this.session = sessionMgr.getSessionByCalendar(this, true);
-
-      // Aside from setting up the session, bump the refresh interval to
-      // a higher value if its below the minimal refresh interval to
-      // avoid exceeding quota.
-      let interval = this.getProperty("refreshInterval");
-      if (interval < MIN_REFRESH_INTERVAL && interval != 0) {
-        cal.LOG(
-          "[calGoogleCalendar] Sorry, auto-refresh intervals under " +
-            MIN_REFRESH_INTERVAL +
-            " minutes would cause the quota to be reached too fast."
-        );
-        this.setProperty("refreshInterval", 2 * MIN_REFRESH_INTERVAL);
-      }
-    }
-  },
-
-  ensureWritable: function() {
-    // Check if calendar is readonly
-    if (this.readOnly) {
-      throw new Components.Exception("", Ci.calIErrors.CAL_IS_READONLY);
-    }
-  },
-
-  get isDefaultCalendar() {
-    return this.mCalendarName ? !this.mCalendarName.endsWith("@group.calendar.google.com") : false;
-  },
-
-  /*
-   * implement calICalendar
-   */
-  get type() {
-    return "gdata";
-  },
-  get providerID() {
-    return "{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}";
-  },
-  get canRefresh() {
-    return true;
-  },
-
-  get id() {
-    return this.mID;
-  },
-  set id(val) {
-    let setter = this.__proto__.__proto__.__lookupSetter__("id");
-    val = setter.call(this, val);
-
-    if (this.id && this.uri) {
-      this.ensureSession();
-    }
-    return val;
-  },
-
-  get uri() {
-    return this.mUri;
-  },
-  set uri(aUri) {
-    const protocols = ["http", "https", "webcal", "webcals"];
-    this.mUri = aUri;
-    if (aUri && aUri.schemeIs("googleapi")) {
-      // new format:  googleapi://session-id/?calendar=calhash@group.calendar.google.com&tasks=taskhash
-      let [fullUser, path] = aUri.pathQueryRef.substr(2).split("/", 2);
-      let keyvalues = path
-        .substr(1)
-        .split("&")
-        .filter(Boolean);
-      let pairs = keyvalues.map(keyvalue => keyvalue.split("=", 2).map(decodeURIComponent));
-      let parameters = new Map(pairs);
-
-      if (parameters.size == 0) {
-        this.mCalendarName = fullUser;
-        this.mTasklistName = this.isDefaultCalendar ? "@default" : null;
-      } else {
-        this.mCalendarName = parameters.get("calendar");
-        this.mTasklistName = parameters.get("tasks");
-      }
-
-      // Users that installed 1.0 had an issue where secondary calendars
-      // were migrated to their own session. This code fixes that and
-      // should be removed once 1.0.1 has been out for a while.
-      let googleUser = Services.prefs.getStringPref(
-        "calendar.google.calPrefs." + fullUser + ".googleUser",
-        null
-      );
-      if (googleUser && googleUser != fullUser) {
-        let newUri = "googleapi://" + googleUser + "/" + path;
-        cal.LOG("[calGoogleCalendar] Migrating url format from " + aUri.spec + " to " + newUri);
-        this.setProperty("uri", newUri);
-        this.mUri = Services.io.newURI(newUri);
-      }
-
-      // Unit tests will use a local uri, if the magic parameter is passed.
-      let port = parameters.get("testport");
-      if (port) {
-        cal.LOG("[calGoogleCalendar] Redirecting request to test port " + port);
-        API_BASE.EVENTS = "http://localhost:" + port + "/calendar/v3/";
-        API_BASE.TASKS = "http://localhost:" + port + "/tasks/v1/";
-      }
-    } else if (aUri && protocols.some(scheme => aUri.schemeIs(scheme))) {
-      // Parse google url, catch private cookies, public calendars,
-      // basic and full types, bogus ics file extensions, invalid hostnames
-      let re = new RegExp(
-        "/calendar/(feeds|ical)/" +
-          "([^/]+)/(public|private|free-busy)-?([^/]+)?/" +
-          "(full|basic)(.ics)?$"
-      );
-
-      let matches = aUri.pathQueryRef.match(re);
-      if (matches) {
-        this.mCalendarName = decodeURIComponent(matches[2]);
-
-        let googleUser = Services.prefs.getStringPref(
-          "calendar.google.calPrefs." + this.mCalendarName + ".googleUser",
-          null
-        );
-        let newUri =
-          "googleapi://" + (googleUser || this.mCalendarName) + "/?calendar=" + matches[2];
-
-        // Use the default task list, but only if this is the primary account.
-        if (googleUser && googleUser == this.mCalendarName) {
-          this.mTasklistName = "@default";
-          newUri += "&tasks=%40default";
-        }
-
-        cal.LOG("[calGoogleCalendar] Migrating url format from " + aUri.spec + " to " + newUri);
-        this.setProperty("uri", newUri);
-        this.mUri = Services.io.newURI(newUri);
-      }
-    }
-
-    if (this.id && this.uri) {
-      this.ensureSession();
-    }
-
-    return this.mUri;
-  },
-
-  createEventsURI: function(...extraParts) {
-    let eventsURI = null;
-    if (this.mCalendarName) {
-      let encodedName = encodeURIComponent(this.mCalendarName);
-      let parts = ["calendars", encodedName].concat(extraParts.filter(Boolean));
-      eventsURI = API_BASE.EVENTS + parts.join("/");
-    }
-    return eventsURI;
-  },
-
-  createUsersURI: function(...extraParts) {
-    let parts = ["users", "me"].concat(extraParts).map(encodeURIComponent);
-    return API_BASE.EVENTS + parts.join("/");
-  },
-
-  createTasksURI: function(...extraParts) {
-    let tasksURI = null;
-    if (this.mTasklistName) {
-      let encodedName = encodeURIComponent(this.mTasklistName);
-      let parts = ["lists", encodedName].concat(extraParts.filter(Boolean));
-      tasksURI = API_BASE.TASKS + parts.join("/");
-    }
-    return tasksURI;
-  },
-
-  getUpdatedMin: function(aWhich) {
-    let updatedMin = null;
-    let lastUpdated = this.getProperty("lastUpdated." + aWhich);
-    if (lastUpdated) {
-      updatedMin = cal.createDateTime(lastUpdated);
-      let lastWeek = cal.dtz.now();
-      lastWeek.day -= 7;
-      if (updatedMin.compare(lastWeek) <= 0) {
-        cal.LOG(
-          "[calGoogleCalendar] Last updated time for " + aWhich + " is very old, doing full sync"
-        );
-        this.resetLog();
-        updatedMin = null;
-      }
-    }
-    return updatedMin ? getCorrectedDate(updatedMin) : null;
-  },
-
-  checkThrottle: function(type) {
-    let shouldRequest = true;
-    let now = new Date().getTime();
-
-    if (type in this.mThrottle) {
-      let then = this.mThrottle[type];
-
-      if (now - then < this.mThrottleLimits[type]) {
-        shouldRequest = false;
-      }
-    }
-
-    if (shouldRequest) {
-      this.mThrottle[type] = now;
-    } else {
-      cal.LOG("[calGoogleCalendar] Skipping " + type + " request to reduce requests");
-    }
-
-    return shouldRequest;
-  },
-
-  getProperty: function(aName) {
-    switch (aName) {
-      case "googleCalendarName":
-        return this.mCalendarName;
-      case "isDefaultCalendar":
-        return this.isDefaultCalendar;
-
-      // Capabilities
-      case "cache.enabled":
-      case "cache.always":
-        return true;
-      case "capabilities.timezones.floating.supported":
-      case "capabilities.attachments.supported":
-      case "capabilities.priority.supported":
-        return false;
-      case "capabilities.privacy.values":
-        return ["DEFAULT", "PUBLIC", "PRIVATE"];
-      case "capabilities.alarms.maxCount":
-        return 5;
-      case "capabilities.alarms.actionValues": {
-        let actionValues = ["DISPLAY", "EMAIL"];
-        if (Services.prefs.getBoolPref("calendar.google.enableSMSReminders", false)) {
-          actionValues.push("SMS");
-        }
-        return actionValues;
-      }
-      case "capabilities.tasks.supported":
-        return !!this.mTasklistName;
-      case "capabilities.events.supported":
-        return !!this.mCalendarName;
-      case "readOnly": {
-        // If this calendar displays events, make it readonly if we are
-        // not the owner or have write access.
-        let accessRole = this.getProperty("settings.accessRole");
-        let isReader = accessRole == "freeBusyReader" || accessRole == "reader";
-        if (this.mCalendarName && isReader) {
-          return true;
-        }
-        // Otherwise fall through
-        break;
-      }
-      case "organizerId":
-        return "mailto:" + this.mCalendarName;
-      case "itip.transport":
-        if (
-          !this.isDefaultCalendar ||
-          !Services.prefs.getBoolPref("calendar.google.enableEmailInvitations", false)
-        ) {
-          // If we explicitly return null here, then these calendars
-          // will not be included in the list of calendars to accept
-          // invitations to and imip will effectively be disabled.
-          return null;
-        }
-        break;
-      case "imip.identity.disabled":
-        // Disabling this hides the picker for identities in the new
-        // calendar wizard and calendar properties dialog. This should
-        // be done for all secondary calendars as they cannot accept
-        // invitations and if email invitations are generally disabled.
-        if (
-          !this.isDefaultCalendar ||
-          !Services.prefs.getBoolPref("calendar.google.enableEmailInvitations", false)
-        ) {
-          return true;
-        }
-        break;
-    }
-
-    return this.__proto__.__proto__.getProperty.apply(this, arguments);
-  },
-
-  setProperty: function(aName, aValue) {
-    switch (aName) {
-      case "refreshInterval":
-        if (aValue < MIN_REFRESH_INTERVAL && aValue != 0) {
-          cal.LOG(
-            "[calGoogleCalendar] Sorry, auto-refresh intervals under " +
-              MIN_REFRESH_INTERVAL +
-              " minutes would cause the quota " +
-              "to be reached too fast."
-          );
-          this.superCalendar.setProperty("refreshInterval", 2 * MIN_REFRESH_INTERVAL);
-          return undefined;
-        }
-        break;
-    }
-
-    return this.__proto__.__proto__.setProperty.apply(this, arguments);
-  },
-
-  addItem: function(aItem, aListener) {
-    return this.adoptItem(aItem.clone(), aListener);
-  },
-  adoptItem: function(aItem, aListener) {
-    function stackContains(part, max = 8) {
-      let stack = Components.stack.caller;
-      while (stack && --max) {
-        if (stack.filename && stack.filename.endsWith(part)) {
-          return true;
-        }
-        stack = stack.caller;
-      }
-      return false;
-    }
-
-    // Now this sucks...both invitations and the offline cache send over
-    // items with the id set, but we have no way to figure out which is
-    // happening just by inspecting the item. Adding offline items should
-    // not be an import, but invitations should.
-    let isImport = aItem.id && (aItem.id == "xpcshell-import" || stackContains("calItipUtils.jsm"));
-    let request = new calGoogleRequest();
-
-    (async () => {
-      let itemData = ItemToJSON(aItem, this.offlineStorage, isImport);
-
-      // Add the calendar to the item, for later use.
-      aItem.calendar = this.superCalendar;
-
-      request.type = request.ADD;
-      request.calendar = this;
-      if (cal.item.isEvent(aItem)) {
-        if (isImport) {
-          cal.LOG("[calGoogleCalendar] Adding invitation event " + aItem.title);
-          request.uri = this.createEventsURI("events", "import");
-        } else {
-          cal.LOG("[calGoogleCalendar] Adding regular event " + aItem.title);
-          request.uri = this.createEventsURI("events");
-        }
-
-        if (Services.prefs.getBoolPref("calendar.google.sendEventNotifications", false)) {
-          request.addQueryParameter("sendNotifications", "true");
-        }
-      } else if (cal.item.isToDo(aItem)) {
-        cal.LOG("[calGoogleCalendar] Adding task " + aItem.title);
-        request.uri = this.createTasksURI("tasks");
-        // Tasks sent with an id will cause a bad request
-        delete itemData.id;
-      }
-
-      if (!request.uri) {
-        throw Components.Exception("Item type not supported", Cr.NS_ERROR_NOT_IMPLEMENTED);
-      }
-
-      request.setUploadData("application/json; charset=UTF-8", JSON.stringify(itemData));
-      let data = await this.session.asyncItemRequest(request);
-
-      // All we need to do now is parse the item and complete the
-      // operation. The cache layer will take care of adding the item
-      // to the storage.
-      let metaData = Object.create(null);
-      let item = JSONToItem(data, this, this.defaultReminders || [], null, metaData);
-
-      // Make sure to update the etag and id
-      saveItemMetadata(this.offlineStorage, item.hashId, metaData);
-
-      if (aItem.id && item.id != aItem.id) {
-        // Looks like the id changed, probably because its an offline
-        // item. This really sucks for us now, because the cache will
-        // reset the wrong item. As a hack, delete the item with its
-        // original id and complete the adoptItem call with the new
-        // item. This will add the new item to the calendar.
-        let pcal = cal.async.promisifyCalendar(this.offlineStorage);
-        await pcal.deleteItem(aItem);
-      }
-      return item;
-    })().then(
-      item => {
-        cal.LOG("[calGoogleCalendar] Adding " + item.title + " succeeded");
-        this.observers.notify("onAddItem", [item]);
-        this.notifyOperationComplete(aListener, Cr.NS_OK, cIOL.ADD, item.id, item);
-      },
-      e => {
-        let code = e.result || Cr.NS_ERROR_FAILURE;
-        cal.ERROR(
-          "[calGoogleCalendar] Adding Item " + aItem.title + " failed:" + code + ": " + e.message
-        );
-        this.notifyPureOperationComplete(aListener, code, cIOL.ADD, aItem.id, e.message);
-      }
-    );
-    return request;
-  },
-
-  modifyItem: function(aNewItem, aOldItem, aListener) {
-    cal.LOG(
-      "[calGoogleCalendar] Modifying item " +
-        aNewItem.title +
-        " (" +
-        (aNewItem.recurrenceId ? aNewItem.recurrenceId.icalString : "master item") +
-        ")"
-    );
-
-    // Set up the request
-    let request = new calGoogleRequest();
-    (async () => {
-      request.type = request.MODIFY;
-      request.calendar = this;
-      if (cal.item.isEvent(aNewItem)) {
-        let googleId = getGoogleId(aNewItem, this.offlineStorage);
-        request.uri = this.createEventsURI("events", googleId);
-
-        // Updating invitations often causes a forbidden error because
-        // some parts are not writable. Using PATCH ignores anything
-        // that isn't allowed.
-        if (cal.itip.isInvitation(aNewItem)) {
-          request.type = request.PATCH;
-        }
-
-        if (Services.prefs.getBoolPref("calendar.google.sendEventNotifications", false)) {
-          request.addQueryParameter("sendNotifications", "true");
-        }
-      } else if (cal.item.isToDo(aNewItem)) {
-        request.uri = this.createTasksURI("tasks", aNewItem.id);
-      }
-
-      if (!request.uri) {
-        throw Components.Exception("Item type not supported", Cr.NS_ERROR_NOT_IMPLEMENTED);
-      }
-
-      request.setUploadData(
-        "application/json; charset=UTF-8",
-        JSON.stringify(ItemToJSON(aNewItem, this.offlineStorage))
-      );
-
-      // Set up etag from storage so we don't overwrite any foreign changes
-      let refItem = aOldItem || aNewItem;
-      let meta =
-        getItemMetadata(this.offlineStorage, refItem) ||
-        getItemMetadata(this.offlineStorage, refItem.parentItem);
-      if (meta && meta.etag) {
-        request.addRequestHeader("If-Match", meta.etag);
-      } else {
-        cal.ERROR("[calGoogleCalendar] Missing ETag for " + refItem.hashId);
-      }
-
-      let data;
-      try {
-        data = await this.session.asyncItemRequest(request);
-      } catch (e) {
-        if (
-          e.result == calGoogleRequest.CONFLICT_MODIFY ||
-          e.result == calGoogleRequest.CONFLICT_DELETED
-        ) {
-          data = await checkResolveConflict(request, this, aNewItem);
-        } else {
-          throw e;
-        }
-      }
-
-      // All we need to do now is parse the item and complete the
-      // operation. The cache layer will take care of adding the item
-      // to the storage cache.
-      let metaData = Object.create(null);
-      let item = JSONToItem(data, this, this.defaultReminders || [], aNewItem.clone(), metaData);
-
-      // Make sure to update the etag. Do so before switching to the
-      // parent item, as google saves its own etags for changed
-      // instances.
-      migrateItemMetadata(this.offlineStorage, aOldItem, item, metaData);
-
-      if (item.recurrenceId) {
-        // If we only modified an exception item, then we need to
-        // set the parent item and modify the exception.
-        let modifiedItem = aNewItem.parentItem.clone();
-        if (item.status == "CANCELLED") {
-          // Canceled means the occurrence is an EXDATE.
-          modifiedItem.recurrenceInfo.removeOccurrenceAt(item.recurrenceId);
-        } else {
-          // Not canceled means the occurrence was modified.
-          modifiedItem.recurrenceInfo.modifyException(item, true);
-        }
-        item = modifiedItem;
-      }
-
-      return item;
-    })().then(
-      item => {
-        cal.LOG("[calGoogleCalendar] Modifying " + aNewItem.title + " succeeded");
-        this.observers.notify("onModifyItem", [item, aOldItem]);
-        this.notifyOperationComplete(aListener, Cr.NS_OK, cIOL.MODIFY, item.id, item);
-      },
-      e => {
-        let code = e.result || Cr.NS_ERROR_FAILURE;
-        if (code != Ci.calIErrors.OPERATION_CANCELLED) {
-          cal.ERROR(
-            "[calGoogleCalendar] Modifying item " +
-              aNewItem.title +
-              " failed:" +
-              code +
-              ": " +
-              e.message
-          );
-        }
-        this.notifyPureOperationComplete(aListener, code, cIOL.MODIFY, aNewItem.id, e.message);
-      }
-    );
-    return request;
-  },
-
-  deleteItem: function(aItem, aListener) {
-    cal.LOG("[calGoogleCalendar] Deleting item " + aItem.title + "(" + aItem.id + ")");
-
-    let request = new calGoogleRequest();
-    (async () => {
-      request.type = request.DELETE;
-      request.calendar = this;
-      if (cal.item.isEvent(aItem)) {
-        request.uri = this.createEventsURI("events", getGoogleId(aItem, this.offlineStorage));
-        if (Services.prefs.getBoolPref("calendar.google.sendEventNotifications", false)) {
-          request.addQueryParameter("sendNotifications", "true");
-        }
-      } else if (cal.item.isToDo(aItem)) {
-        request.uri = this.createTasksURI("tasks", aItem.id);
-      }
-
-      if (!request.uri) {
-        throw Components.Exception("Item type not supported", Cr.NS_ERROR_NOT_IMPLEMENTED);
-      }
-
-      // Set up etag from storage so we don't overwrite any foreign changes
-      let meta =
-        getItemMetadata(this.offlineStorage, aItem) ||
-        getItemMetadata(this.offlineStorage, aItem.parentItem);
-      if (meta && meta.etag) {
-        request.addRequestHeader("If-Match", meta.etag);
-      } else {
-        cal.ERROR("[calGoogleCalendar] Missing ETag for " + aItem.hashId);
-      }
-
-      try {
-        await this.session.asyncItemRequest(request);
-      } catch (e) {
-        if (
-          e.result == calGoogleRequest.CONFLICT_MODIFY ||
-          e.result == calGoogleRequest.CONFLICT_DELETED
-        ) {
-          await checkResolveConflict(request, this, aItem);
-        } else {
-          throw e;
-        }
-      }
-
-      deleteItemMetadata(this.offlineStorage, aItem);
-
-      return aItem;
-    })().then(
-      item => {
-        cal.LOG("[calGoogleCalendar] Deleting " + aItem.title + " succeeded");
-        this.observers.notify("onDeleteItem", [item]);
-        this.notifyOperationComplete(aListener, Cr.NS_OK, cIOL.DELETE, item.id, item);
-      },
-      e => {
-        let code = e.result || Cr.NS_ERROR_FAILURE;
-        if (code != Ci.calIErrors.OPERATION_CANCELLED) {
-          cal.ERROR(
-            "[calGoogleCalendar] Deleting item " +
-              aItem.title +
-              " failed:" +
-              code +
-              ": " +
-              e.message
-          );
-        }
-        this.notifyPureOperationComplete(aListener, code, cIOL.DELETE, aItem.id, e.message);
-      }
-    );
-    return request;
-  },
-
-  getItem: function(aId, aListener) {
-    this.mOfflineStorage.getItem(...arguments);
-  },
-
-  getItems: function(aFilter, aCount, aRangeStart, aRangeEnd, aListener) {
-    this.mOfflineStorage.getItems(...arguments);
-  },
-
-  refresh: function() {
-    this.mObservers.notify("onLoad", [this]);
-  },
-
-  migrateStorageCache: function() {
-    let cacheVersion = this.getProperty("cache.version");
-    if (!cacheVersion || cacheVersion >= this.CACHE_DB_VERSION) {
-      // Either up to date or first run, make sure property set right.
-      this.setProperty("cache.version", this.CACHE_DB_VERSION);
-      return Promise.resolve(false);
-    }
-
-    let needsReset = false;
-    cal.LOG(
-      "[calGoogleCalendar] Migrating cache from " +
-        cacheVersion +
-        " to " +
-        this.CACHE_DB_VERSION +
-        " for " +
-        this.name
-    );
-
-    if (cacheVersion < 2) {
-      // The initial version 1.0 had some issues that required resetting
-      // the cache.
-      needsReset = true;
-    }
-
-    if (cacheVersion < 3) {
-      // There was an issue with ids from the birthday calendar, we need
-      // to reset just this calendar. See bug 1169062.
-      let birthdayCalendar = "#contacts@group.v.calendar.google.com";
-      if (this.mCalendarName && this.mCalendarName == birthdayCalendar) {
-        needsReset = true;
-      }
-    }
-
-    // Migration all done. Reset if requested.
-    if (needsReset) {
-      return this.resetSync().then(() => {
-        this.setProperty("cache.version", this.CACHE_DB_VERSION);
-        return needsReset;
-      });
-    } else {
-      this.setProperty("cache.version", this.CACHE_DB_VERSION);
-      return Promise.resolve(needsReset);
-    }
-  },
-
-  /**
-   * Implement calIChangeLog
-   */
-  get offlineStorage() {
-    return this.mOfflineStorage;
-  },
-  set offlineStorage(val) {
-    this.mOfflineStorage = val;
-    this.migrateStorageCache();
-    return val;
-  },
-
-  resetLog: function() {
-    this.resetSync().then(() => {
-      this.mObservers.notify("onLoad", [this]);
-    });
-  },
-
-  resetSync: function() {
-    return new Promise((resolve, reject) => {
-      cal.LOG("[calGoogleCalendar] Resetting last updated counter for " + this.name);
-      this.setProperty("syncToken.events", "");
-      this.setProperty("lastUpdated.tasks", "");
-      this.mThrottle = Object.create(null);
-      let listener = {
-        onDeleteCalendar: function(aCalendar, aStatus, aDetail) {
-          if (Components.isSuccessCode(aStatus)) {
-            resolve();
-          } else {
-            reject(aDetail);
-          }
-        },
-      };
-      this.mOfflineStorage
-        .QueryInterface(Ci.calICalendarProvider)
-        .deleteCalendar(this.mOfflineStorage, listener);
-    });
-  },
-
-  replayChangesOn: function(aListener) {
-    // Figure out if the user is idle, no need to synchronize if so.
-    let idleTime = Cc["@mozilla.org/widget/idleservice;1"].getService(Ci.nsIIdleService).idleTime;
-    let maxIdleTime = Services.prefs.getIntPref("calendar.google.idleTime", 300) * 1000;
-
-    if (maxIdleTime != 0 && idleTime > maxIdleTime) {
-      cal.LOG("[calGoogleCalendar] Skipping refresh since user is idle");
-      aListener.onResult({ status: Cr.NS_OK }, null);
-      return Promise.resolve();
-    }
-
-    // Now that we've determined we are not idle we can continue with the sync.
-    let maxResults = Services.prefs.getIntPref("calendar.google.maxResultsPerRequest", null);
-
-    // We are going to be making potentially lots of changes to the offline
-    // storage, start a batch operation.
-    this.mOfflineStorage.startBatch();
-
-    // Update the calendar settings
-    let calendarPromise = Promise.resolve();
-    if (this.mCalendarName && this.checkThrottle("calendarList")) {
-      let calendarRequest = new calGoogleRequest();
-      calendarRequest.calendar = this;
-      calendarRequest.type = calendarRequest.GET;
-      calendarRequest.uri = this.createUsersURI("calendarList", this.mCalendarName);
-      calendarPromise = this.session.asyncItemRequest(calendarRequest).then(aData => {
-        if (aData.defaultReminders) {
-          this.defaultReminders = aData.defaultReminders.map(reminder =>
-            JSONToAlarm(reminder, true)
-          );
-        } else {
-          this.defaultReminders = [];
-        }
-
-        let settings = [
-          "accessRole",
-          "backgroundColor",
-          "description",
-          "foregroundColor",
-          "location",
-          "primary",
-          "summary",
-          "summaryOverride",
-          "timeZone",
-        ];
-
-        for (let k of settings) {
-          this.setProperty("settings." + k, aData[k]);
-        }
-        this.setProperty("settings.defaultReminders", JSON.stringify(aData.defaultReminders));
-      });
-    }
-
-    // Set up a request for the events
-    let eventsRequest = new calGoogleRequest();
-    let eventsPromise = Promise.resolve();
-    eventsRequest.calendar = this;
-    eventsRequest.type = eventsRequest.GET;
-    eventsRequest.uri = this.createEventsURI("events");
-    eventsRequest.addQueryParameter("maxResults", maxResults);
-    let syncToken = this.getProperty("syncToken.events");
-    if (syncToken) {
-      eventsRequest.addQueryParameter("showDeleted", "true");
-      eventsRequest.addQueryParameter("syncToken", syncToken);
-    }
-    if (eventsRequest.uri && this.checkThrottle("events")) {
-      let saver = new ItemSaver(this);
-      eventsPromise = this.session.asyncPaginatedRequest(
-        eventsRequest,
-        null,
-        aData => {
-          // On each request...
-          return saver.parseItemStream(aData);
-        },
-        aData => {
-          // On last request...
-          return saver.complete().then(() => {
-            if (aData.nextSyncToken) {
-              cal.LOG(
-                "[calGoogleCalendar] New sync token for " +
-                  this.name +
-                  "(events) is now: " +
-                  aData.nextSyncToken
-              );
-              this.setProperty("syncToken.events", aData.nextSyncToken);
-            }
-          });
-        }
-      );
-    }
-
-    // Set up a request for tasks
-    let tasksRequest = new calGoogleRequest();
-    let tasksPromise = Promise.resolve();
-    tasksRequest.calendar = this;
-    tasksRequest.type = tasksRequest.GET;
-    tasksRequest.uri = this.createTasksURI("tasks");
-    tasksRequest.addQueryParameter("maxResults", maxResults);
-    let lastUpdated = this.getUpdatedMin("tasks");
-    if (lastUpdated) {
-      tasksRequest.addQueryParameter("updatedMin", cal.dtz.toRFC3339(lastUpdated));
-      tasksRequest.addQueryParameter("showDeleted", "true");
-    }
-    if (tasksRequest.uri && this.checkThrottle("tasks")) {
-      let saver = new ItemSaver(this);
-      let newLastUpdated = null;
-      tasksPromise = this.session.asyncPaginatedRequest(
-        tasksRequest,
-        aData => {
-          // On the first request...
-          newLastUpdated = tasksRequest.requestDate.icalString;
-        },
-        aData => {
-          // On each request...
-          return saver.parseItemStream(aData);
-        },
-        aData => {
-          // On last request...
-          return saver.complete().then(() => {
-            cal.LOG(
-              "[calGoogleCalendar] Last sync date for " +
-                this.name +
-                "(tasks) is now: " +
-                tasksRequest.requestDate.toString()
-            );
-            this.setProperty("newLastUpdated.tasks", newLastUpdated);
-          });
-        }
-      );
-    }
-
-    return Promise.all([calendarPromise, eventsPromise, tasksPromise]).then(
-      () => {
-        this.mOfflineStorage.endBatch();
-        aListener.onResult({ status: Cr.NS_OK }, null);
-      },
-      e => {
-        this.mOfflineStorage.endBatch();
-        let code = e.result || Cr.NS_ERROR_FAILURE;
-        if (code == calGoogleRequest.RESOURCE_GONE) {
-          cal.LOG(
-            "[calGoogleCalendar] Server did not accept " +
-              "incremental update, resetting calendar and " +
-              "starting over."
-          );
-          this.resetSync().then(
-            () => {
-              this.replayChangesOn(aListener);
-            },
-            err => {
-              cal.ERROR("[calGoogleCalendar] Error resetting calendar:\n" + stringException(err));
-              aListener.onResult({ status: err.result }, err.message);
-            }
-          );
-        } else {
-          cal.LOG("[calGoogleCalendar] Error syncing:\n" + code + ":" + stringException(e));
-          aListener.onResult({ status: code }, e.message);
-        }
-      }
-    );
-  },
-
-  /**
-   * Implement calISchedulingSupport. Most is taken care of by the base
-   * provider, but we want to advertise that we will always take care of
-   * notifications.
-   */
-  canNotify: function(aMethod, aItem) {
-    return true;
-  },
-};
-
-var NSGetFactory = XPCOMUtils.generateNSGetFactory([calGoogleCalendar]); /* exported NSGetFactory */
deleted file mode 100644
--- a/calendar/providers/gdata/components/calGoogleCalendar.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {d1a6e988-4b4d-45a5-ba46-43e501ea96e3} calGoogleCalendar.js
-contract @mozilla.org/calendar/calendar;1?type=gdata {d1a6e988-4b4d-45a5-ba46-43e501ea96e3}
deleted file mode 100644
--- a/calendar/providers/gdata/content/browserRequest.css
+++ /dev/null
@@ -1,52 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#security-button {
-  width: 20px;
-  margin-top: -1px;
-  margin-right: 5px;
-  background-repeat: no-repeat;
-}
-
-#security-button[level="high"] {
-  background-image: url("chrome://messenger/skin/icons/secure.png");
-}
-
-#security-button[level="broken"] {
-  background-image: url("chrome://messenger/skin/icons/insecure.png");
-}
-
-#security-button[loading="true"] {
-  background-image: url("chrome://global/skin/icons/loading.png");
-  background-position: 4px 3px;
-}
-
-@media (min-resolution: 2dppx) {
-  #security-button[loading="true"] {
-    background-image: url("chrome://global/skin/icons/loading@2x.png");
-  }
-}
-
-#header {
-    border-bottom: 1px solid rgb(105, 105, 105);
-    overflow: hidden;
-}
-
-#dialogMessage {
-    margin: 1em 1em 2em;
-}
-
-#addressbox {
-    font-weight: bold;
-    font-size: medium;
-    -moz-appearance: textfield;
-    overflow: hidden;
-    margin: 5px 5px;
-    font-weight: normal;
-}
-
-#headerMessage {
-  margin-top: 3px;
-  margin-bottom: 3px;
-}
deleted file mode 100644
--- a/calendar/providers/gdata/content/browserRequest.js
+++ /dev/null
@@ -1,101 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// Backwards compatibility with Thunderbird <60.
-if (!("Cc" in this)) {
-  // eslint-disable-next-line mozilla/no-define-cc-etc, no-unused-vars
-  const { interfaces: Ci } = Components;
-}
-
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-
-/* exported cancelRequest, loadRequestedUrl, reportUserClosed */
-
-var wpl = Ci.nsIWebProgressListener;
-
-var reporterListener = {
-  _isBusy: false,
-  get securityButton() {
-    delete this.securityButton;
-    return (this.securityButton = document.getElementById("security-button"));
-  },
-
-  QueryInterface: cal.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
-
-  onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {},
-
-  onProgressChange: function(
-    aWebProgress,
-    aRequest,
-    aCurSelfProgress,
-    aMaxSelfProgress,
-    aCurTotalProgress,
-    aMaxTotalProgress
-  ) {},
-
-  onLocationChange: function(aWebProgress, aRequest, aLocation) {
-    document.getElementById("headerMessage").textContent = aLocation.spec;
-  },
-
-  onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {},
-
-  onSecurityChange: function(aWebProgress, aRequest, aState) {
-    const wpl_security_bits = wpl.STATE_IS_SECURE | wpl.STATE_IS_BROKEN | wpl.STATE_IS_INSECURE;
-    let browser = document.getElementById("requestFrame");
-    let level;
-
-    switch (aState & wpl_security_bits) {
-      case wpl.STATE_IS_SECURE:
-        level = "high";
-        break;
-      case wpl.STATE_IS_BROKEN:
-        level = "broken";
-        break;
-    }
-    if (level) {
-      this.securityButton.setAttribute("level", level);
-      this.securityButton.hidden = false;
-    } else {
-      this.securityButton.hidden = true;
-      this.securityButton.removeAttribute("level");
-    }
-    this.securityButton.setAttribute("tooltiptext", browser.securityUI.tooltipText);
-  },
-
-  onContentBlockingEvent: function(aWebProgress, aRequest, aEvent) {},
-};
-
-function cancelRequest() {
-  reportUserClosed();
-  window.close();
-}
-
-function reportUserClosed() {
-  let request = window.arguments[0].wrappedJSObject;
-  request.cancelled();
-}
-
-function loadRequestedUrl() {
-  let request = window.arguments[0].wrappedJSObject;
-  document.getElementById("headerMessage").textContent = request.promptText;
-  if (request.iconURI != "") {
-    document.getElementById("headerImage").src = request.iconURI;
-  }
-
-  let browser = document.getElementById("requestFrame");
-  browser.addProgressListener(reporterListener, Ci.nsIWebProgress.NOTIFY_ALL);
-  let url = request.url;
-  if (url != "") {
-    browser.setAttribute("src", url);
-    document.getElementById("headerMessage").textContent = url;
-  }
-
-  let dialogMessage = document.getElementById("dialogMessage");
-  if (request.description) {
-    dialogMessage.textContent = request.description;
-  } else {
-    dialogMessage.setAttribute("hidden", "true");
-  }
-  request.loaded(window, browser.webProgress);
-}
deleted file mode 100644
--- a/calendar/providers/gdata/content/browserRequest.xul
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0"?>
-<!--# This Source Code Form is subject to the terms of the Mozilla Public
-    # License, v. 2.0. If a copy of the MPL was not distributed with this file,
-    # You can obtain one at http://mozilla.org/MPL/2.0/.
- -->
-
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<?xml-stylesheet href="chrome://gdata-provider/skin/browserRequest.css" type="text/css"?>
-
-<!DOCTYPE window>
-<window id="browserRequest"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml"
-        buttons=","
-        onload="loadRequestedUrl()"
-        onclose="reportUserClosed()"
-        title=""
-        width="800"
-        height="500"
-        orient="vertical">
-
-  <script src="chrome://gdata-provider/content/browserRequest.js"/>
-
-  <keyset id="mainKeyset">
-    <key id="key_close" key="w" modifiers="accel" oncommand="cancelRequest()"/>
-    <key id="key_close2"  keycode="VK_ESCAPE" oncommand="cancelRequest()"/>
-  </keyset>
-  <vbox id="header">
-    <description id="dialogMessage"/>
-    <hbox id="addressbox" flex="1" disabled="true">
-      <image id="security-button" src="chrome://messenger/skin/icons/mailicon32.png"/>
-      <description id="headerMessage"/>
-    </hbox>
-  </vbox>
-  <browser type="content" src="about:blank" id="requestFrame" flex="1"/>
-</window>
deleted file mode 100644
index 02ccfa8db28d18c68a746eca42ad94d2a8317a6b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-bindings.css
+++ /dev/null
@@ -1,23 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#calendar-list richlistitem[loading="true"] {
-  -moz-box-flex: 1;
-  background: url("chrome://global/skin/icons/loading.png") center 33% / 16px no-repeat;
-}
-
-@media (min-resolution: 1.1dppx) {
-  #calendar-list richlistitem[loading="true"] {
-    background-image: url("chrome://global/skin/icons/loading@2x.png");
-  }
-}
-
-#calendar-list richlistitem[selected] {
-  color: unset;
-  background-color: unset;
-}
-
-#calendar-list .header-label {
-  font-weight: bold;
-}
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-calendar-creation.js
+++ /dev/null
@@ -1,330 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* import-globals-from ../../../lightning/content/lightning-calendar-creation.js */
-
-// Backwards compatibility with Thunderbird <60.
-if (!("Cc" in this)) {
-  // eslint-disable-next-line mozilla/no-define-cc-etc, no-unused-vars
-  const { utils: Cu } = Components;
-}
-
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-var { getGoogleSessionManager } = ChromeUtils.import(
-  "resource://gdata-provider/modules/gdataSession.jsm"
-);
-var { monkeyPatch } = ChromeUtils.import("resource://gdata-provider/modules/gdataUtils.jsm");
-
-(function() {
-  function pageorder(anchor, ...pages) {
-    let wizard = document.documentElement;
-    let page = wizard.getPageById(anchor);
-    for (let id of pages) {
-      page.next = id;
-      page = wizard.getPageById(id);
-    }
-  }
-
-  function trycatch(func) {
-    return function() {
-      try {
-        return func.apply(this, arguments);
-      } catch (e) {
-        Cu.reportError(e);
-        throw e;
-      }
-    };
-  }
-
-  let previousUriValue = null;
-  function selectProvider(type) {
-    let isGdata = type == "gdata";
-    let curi = document.getElementById("calendar-uri");
-
-    curi.parentNode.style.visibility = isGdata ? "hidden" : "visible";
-    document.getElementById("cache").parentNode.style.visibility = isGdata ? "hidden" : "visible";
-
-    // Move the next step description to the right place
-    let locationRows = document.querySelector(
-      "#calendar-wizard > [pageid='locationPage'] > grid > rows"
-    );
-    let nextStepDescr = document.getElementById("gdata-nextstep-description");
-    locationRows.appendChild(nextStepDescr);
-
-    if (isGdata) {
-      pageorder("locationPage", "gdata-session", "gdata-calendars", "finishPage");
-      previousUriValue = curi.value;
-      curi.value = "googleapi://unknown";
-      nextStepDescr.removeAttribute("hidden");
-    } else {
-      nextStepDescr.setAttribute("hidden", "true");
-      pageorder("locationPage", "customizePage", "finishPage");
-      if (previousUriValue !== null) {
-        curi.value = previousUriValue;
-        previousUriValue = null;
-      }
-    }
-
-    checkRequired();
-  }
-  this.gdataSelectProvider = selectProvider;
-
-  if (typeof tmpCalendarCreation == "undefined") {
-    monkeyPatch(window, "onSelectProvider", (protofunc, type) => {
-      selectProvider(type);
-      return protofunc(type);
-    });
-  } else {
-    // The exchange provider overwrites the select handler, which causes
-    // our provider to fail. The exchange provider overwrites the select
-    // handler, which causes our provider to fail. Given the exchange
-    // provider is currently not maintained and we want them to work
-    // together, here is a workaround.
-
-    // eslint-disable-next-line no-undef
-    monkeyPatch(tmpCalendarCreation, "doRadioExchangeCalendar", (protofunc, target) => {
-      // We need to run our function first, otherwise resetting the
-      // pageorder will overwrite what the exchange provider does.
-      selectProvider(target.value);
-      let rv = protofunc(target);
-
-      // But then again, when switching to the gdata provider, the
-      // exchange provider overwrites the uri we set.
-      if (target.value == "gdata") {
-        let curi = document.getElementById("calendar-uri");
-        curi.value = "googleapi://unknown";
-        checkRequired();
-      }
-      return rv;
-    });
-  }
-
-  monkeyPatch(window, "prepareCreateCalendar", protofunc => {
-    let type = document.getElementById("calendar-format").selectedItem.value;
-    return type == "gdata" ? true : protofunc();
-  });
-
-  monkeyPatch(window, "checkRequired", protofunc => {
-    let wizard = document.documentElement;
-    let currentPageId = wizard.currentPage && wizard.currentPage.pageid;
-
-    if (currentPageId == "gdata-session") {
-      let sessionGroup = document.getElementById("gdata-session-group");
-      let sessionName = document.getElementById("gdata-session-name");
-      let sessionNameIsValid = document.getAnonymousElementByAttribute(
-        sessionName,
-        "anonid",
-        "input"
-      ).validity.valid;
-      // TODO for some reason the validity doesn't work on windows. Here is a hack:
-      // eslint-disable-next-line no-useless-escape
-      sessionNameIsValid = !!sessionName.value.match(/^[^\/]+@[^\/]+\.[^\/]+$/);
-      wizard.canAdvance = sessionGroup.value || (sessionName.value && sessionNameIsValid);
-    } else if (currentPageId == "gdata-calendars") {
-      let calendarList = document.getElementById("calendar-list");
-      wizard.canAdvance = !!calendarList.querySelector(
-        ".calendar-selected[checked]:not([readonly])"
-      );
-    } else {
-      protofunc();
-    }
-  });
-
-  this.gdataSessionShow = trycatch(() => {
-    let sessionMgr = getGoogleSessionManager();
-    let sessionContainer = document.getElementById("gdata-session-group");
-    let newSessionItem = document.getElementById("session-new");
-    let calendars = cal.getCalendarManager().getCalendars({});
-    let sessions = new Set(
-      calendars.map(calendar => {
-        return sessionMgr.getSessionByCalendar(calendar, true);
-      })
-    );
-
-    while (sessionContainer.firstChild.id != "session-new") {
-      sessionContainer.firstChild.remove();
-    }
-
-    // forEach is needed for backwards compatibility.
-    sessions.forEach(session => {
-      if (!session) {
-        return;
-      }
-
-      let radio = document.createXULElement("radio");
-      radio.setAttribute("value", session.id);
-      radio.setAttribute("label", session.id);
-      sessionContainer.insertBefore(radio, newSessionItem);
-      radio.gdataSession = session;
-    });
-
-    sessionContainer.value = sessionContainer.firstChild.value;
-    if (sessionContainer.value == "") {
-      let sessionName = document.getElementById("gdata-session-name");
-      sessionName.focus();
-    }
-  });
-
-  this.gdataCalendarsShow = trycatch(() => {
-    let calMgr = cal.getCalendarManager();
-    let sessionMgr = getGoogleSessionManager();
-    let sessionContainer = document.getElementById("gdata-session-group");
-
-    let calendarList = document.getElementById("calendar-list");
-    while (calendarList.lastElementChild) {
-      calendarList.lastElementChild.remove();
-    }
-    let loadingItem = document.createXULElement("richlistitem");
-    loadingItem.setAttribute("loading", "true");
-    calendarList.appendChild(loadingItem);
-
-    let session = sessionContainer.selectedItem.gdataSession;
-    if (!session) {
-      let newSessionItem = document.getElementById("gdata-session-name");
-      session = sessionMgr.getSessionById(newSessionItem.value, true);
-    }
-
-    Promise.all([session.getTasksList(), session.getCalendarList()]).then(
-      ([tasksLists, calendars]) => {
-        let existing = new Set();
-        let sessionPrefix = "googleapi://" + session.id;
-        for (let calendar of calMgr.getCalendars({})) {
-          let spec = calendar.uri.spec;
-          if (calendar.type == "gdata" && spec.substr(0, sessionPrefix.length) == sessionPrefix) {
-            let match;
-            if ((match = spec.match(/calendar=([^&]*)/))) {
-              existing.add(decodeURIComponent(match[0]));
-            }
-            if ((match = spec.match(/tasks=([^&]*)/))) {
-              existing.add(decodeURIComponent(match[0]));
-            }
-          }
-        }
-
-        let taskcals = tasksLists.map(tasklist => {
-          let uri = "googleapi://" + session.id + "/?tasks=" + encodeURIComponent(tasklist.id);
-          let calendar = calMgr.createCalendar("gdata", Services.io.newURI(uri));
-          calendar.id = cal.getUUID();
-          calendar.setProperty("color", cal.view.hashColor(tasklist.title));
-          calendar.name = tasklist.title;
-          if (existing.has("tasks=" + tasklist.id)) {
-            calendar.readOnly = true;
-          }
-          return calendar;
-        });
-        let calcals = calendars.map(calendarEntry => {
-          let uri =
-            "googleapi://" + session.id + "/?calendar=" + encodeURIComponent(calendarEntry.id);
-          let calendar = calMgr.createCalendar("gdata", Services.io.newURI(uri));
-          calendar.name = calendarEntry.summary;
-          calendar.id = cal.getUUID();
-          calendar.setProperty("color", calendarEntry.backgroundColor);
-          if (existing.has("calendar=" + calendarEntry.id)) {
-            calendar.readOnly = true;
-          }
-          return calendar;
-        });
-
-        loadingItem.remove();
-        let strings = Services.strings.createBundle(
-          "chrome://gdata-provider/locale/gdata.properties"
-        );
-
-        let header = document.createXULElement("richlistitem");
-        let headerLabel = document.createXULElement("label");
-        headerLabel.classList.add("header-label");
-        headerLabel.value = strings.GetStringFromName("calendarsHeader");
-        header.appendChild(headerLabel);
-        calendarList.appendChild(header);
-
-        for (let calendar of calcals) {
-          addCalendarItem(calendar);
-        }
-
-        header = document.createXULElement("richlistitem");
-        headerLabel = document.createXULElement("label");
-        headerLabel.classList.add("header-label");
-        headerLabel.value = strings.GetStringFromName("taskListsHeader");
-        header.appendChild(headerLabel);
-        calendarList.appendChild(header);
-
-        for (let calendar of taskcals) {
-          addCalendarItem(calendar);
-        }
-
-        function addCalendarItem(calendar) {
-          let item = document.createXULElement("richlistitem");
-          item.calendar = calendar;
-          item.setAttribute("calendar-id", calendar.id);
-
-          let checkbox = document.createXULElement("checkbox");
-          checkbox.classList.add("calendar-selected");
-          if (calendar.readOnly) {
-            checkbox.checked = true;
-            checkbox.setAttribute("readonly", "true");
-          }
-          item.appendChild(checkbox);
-
-          let image = document.createXULElement("image");
-          image.classList.add("calendar-color");
-          item.appendChild(image);
-          image.style.backgroundColor = calendar.getProperty("color");
-
-          let label = document.createXULElement("label");
-          label.classList.add("calendar-name");
-          label.value = calendar.name;
-          item.appendChild(label);
-
-          calendarList.appendChild(item);
-        }
-      },
-      e => {
-        Cu.reportError(e);
-      }
-    );
-  });
-
-  this.gdataCalendarsAdvance = trycatch(() => {
-    let calendarList = document.getElementById("calendar-list");
-
-    let calMgr = cal.getCalendarManager();
-    for (let item of calendarList.children) {
-      let checkbox = item.querySelector(".calendar-selected[checked]:not([readonly])");
-      if (checkbox) {
-        calMgr.registerCalendar(item.calendar);
-      }
-    }
-  });
-
-  this.gdataFocusNewSession = trycatch(() => {
-    let sessionContainer = document.getElementById("gdata-session-group");
-    sessionContainer.value = "";
-  });
-
-  document.addEventListener("DOMContentLoaded", () => {
-    // Older versions of Lightning don't set the onselect attribute at all.
-    let calendarFormat = document.getElementById("calendar-format");
-    if (!calendarFormat.hasAttribute("onselect")) {
-      calendarFormat.setAttribute("onselect", "gdataSelectProvider(this.value)");
-    }
-
-    if (document.getElementById("gdata-session").pageIndex == -1) {
-      let wizard = document.documentElement;
-      wizard._initPages();
-    }
-  });
-
-  let gdataSessionPage = document.getElementById("gdata-session");
-  gdataSessionPage.addEventListener("pageshow", () => {
-    this.gdataSessionShow();
-    checkRequired();
-  });
-  let gdataCalendarsPage = document.getElementById("gdata-calendars");
-  gdataCalendarsPage.addEventListener("pageshow", () => {
-    this.gdataCalendarsShow();
-    checkRequired();
-  });
-  gdataCalendarsPage.addEventListener("pageadvanced", this.gdataCalendarsAdvance);
-}.call(window));
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-calendar-creation.xul
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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/. -->
-
-<!DOCTYPE overlay [
-  <!ENTITY % gdata SYSTEM "chrome://gdata-provider/locale/gdata.dtd"> %gdata;
-  <!ENTITY % calendarCreation SYSTEM "chrome://calendar/locale/calendarCreation.dtd" > %calendarCreation;
-]>
-
-<?xml-stylesheet href="chrome://calendar-common/skin/widgets/calendar-widgets.css" type="text/css"?>
-<?xml-stylesheet href="chrome://gdata-provider/skin/gdata-bindings.css" type="text/css"?>
-<?xml-stylesheet type="text/css" href="chrome://messenger/skin/input-fields.css"?>
-
-<overlay id="gdataCalendarCreation"
-         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
-
-  <script src="chrome://global/content/globalOverlay.js"/>
-  <script src="chrome://global/content/editMenuOverlay.js"/>
-  <script src="chrome://gdata-provider/content/gdata-calendar-creation.js"/>
-
-  <radiogroup id="calendar-format">
-    <radio value="gdata" label="&gdata-provider.label;"/>
-  </radiogroup>
-
-  <wizard id="calendar-wizard">
-    <description id="gdata-nextstep-description" hidden="true">&gdata.wizard.nextstep.description;</description>
-
-    <wizardpage id="gdata-session"
-                pageid="gdata-session"
-                description="&wizard.description;">
-      <description>&gdata.wizard.session.description;</description>
-      <radiogroup id="gdata-session-group" onselect="checkRequired()">
-        <hbox id="session-new" class="input-container">
-          <radio value=""/>
-          <html:input id="gdata-session-name"
-                      type="email"
-                      onfocus="gdataFocusNewSession()"
-                      oninput="gdataFocusNewSession(); checkRequired();"
-                      class="input-inline"/>
-        </hbox>
-      </radiogroup>
-    </wizardpage>
-    <wizardpage id="gdata-calendars"
-                pageid="gdata-calendars"
-                description="&wizard.description;">
-      <description>&gdata.wizard.calendars.description;</description>
-      <richlistbox id="calendar-list"
-                   flex="1"
-                   onclick="checkRequired();"/>
-    </wizardpage>
-  </wizard>
-</overlay>
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-calendar-properties.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* import-globals-from ../../../lightning/content/lightning-calendar-properties.js */
-
-var { monkeyPatch } = ChromeUtils.import("resource://gdata-provider/modules/gdataUtils.jsm");
-
-window.addEventListener("load", () => {
-  if (document.getElementById("calendar-uri").value) {
-    // Calendar's load function needs to be called first, and that seems to have happened.
-    gdataOnLoad();
-  } else {
-    // onLoad has not yet been called, so we can piggyback on that function.
-    monkeyPatch(window, "onLoad", (protofunc, ...args) => {
-      let rv = protofunc(...args);
-      gdataOnLoad();
-      return rv;
-    });
-  }
-});
-
-function gdataOnLoad() {
-  if (gCalendar.type == "gdata") {
-    let accessRole = gCalendar.getProperty("settings.accessRole");
-    let isReader = accessRole == "freeBusyReader" || accessRole == "reader";
-    let isEventsCalendar = gCalendar.getProperty("capabilities.events.supported");
-    let isDisabled = gCalendar.getProperty("disabled");
-
-    // Disable setting read-only if the calendar is readonly anyway
-    document.getElementById("read-only").disabled = isDisabled || (isEventsCalendar && isReader);
-    // Don't allow setting refresh interval to less than 30 minutes
-    let refInterval = document.getElementById("calendar-refreshInterval-menupopup");
-    Array.from(refInterval.childNodes)
-      .filter(node => {
-        let nodeval = parseInt(node.getAttribute("value"), 10);
-        return nodeval < 30 && nodeval != 0;
-      })
-      .forEach(node => {
-        refInterval.removeChild(node);
-      });
-  }
-}
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-calendar-properties.xul
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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/. -->
-
-<overlay id="gdata-calendar-properties"
-         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
-  <script src="chrome://gdata-provider/content/gdata-calendar-properties.js"/>
-</overlay>
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-event-dialog-reminder.css
+++ /dev/null
@@ -1,7 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-.reminder-icon[value="SMS"] {
-  list-style-image: url(chrome://gdata-provider/skin/reminder-action-sms.svg);
-}
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-event-dialog-reminder.js
+++ /dev/null
@@ -1,109 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* global MozElements */
-
-/* import-globals-from ../../../base/content/dialogs/calendar-event-dialog-reminder.js */
-
-(function() {
-  const FOUR_WEEKS_BEFORE = -2419200;
-  const { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-  const { monkeyPatch, getProviderString } = ChromeUtils.import(
-    "resource://gdata-provider/modules/gdataUtils.jsm"
-  );
-  const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-  XPCOMUtils.defineLazyGetter(this, "notificationbox", () => {
-    return new MozElements.NotificationBox(element => {
-      element.setAttribute("flex", "1");
-      document.getElementById("reminder-notifications").append(element);
-    });
-  });
-
-  // NOTE: This function exits early if its not a gdata calendar
-  let item = window.arguments[0].item;
-  let calendar = window.arguments[0].calendar;
-  if (calendar.type != "gdata") {
-    return;
-  }
-
-  let label = getProviderString("reminderOutOfRange");
-
-  function checkReminderRange(reminder) {
-    let offset = cal.alarms.calculateAlarmOffset(item, reminder);
-    let seconds = offset.inSeconds;
-    return seconds < 1 && seconds >= FOUR_WEEKS_BEFORE;
-  }
-
-  function checkAllReminders() {
-    let listbox = document.getElementById("reminder-listbox");
-
-    let validated = true;
-    for (let node of listbox.childNodes) {
-      validated = validated && checkReminderRange(node.reminder);
-      if (!validated) {
-        break;
-      }
-    }
-
-    let acceptButton = document.documentElement.getButton("accept");
-    acceptButton.disabled = !validated;
-
-    if (validated) {
-      this.notificationbox.removeAllNotifications();
-    } else {
-      let notification = this.notificationbox.appendNotification(
-        label,
-        "reminderNotification",
-        null,
-        this.notificationbox.PRIORITY_CRITICAL_HIGH
-      );
-
-      let closeButton = notification.messageDetails.nextSibling;
-      closeButton.setAttribute("hidden", "true");
-    }
-  }
-
-  /**
-   * Hides the "after the event starts" reminder relations, these are not
-   * supported by Google.
-   */
-  function hideReminderRelations() {
-    document.getElementById("reminder-after-start-menuitem").hidden = true;
-    document.getElementById("reminder-after-end-menuitem").hidden = true;
-  }
-
-  /**
-   * SMS Reminders are only supported for Google Apps for Work, Education,
-   * and Government. hide the menuitem if SMS reminders are not supported
-   */
-  function hideSMSReminders() {
-    if (!Services.prefs.getBoolPref("calendar.google.enableSMSReminders", false)) {
-      document.getElementById("reminder-action-SMS").hidden = true;
-    }
-  }
-
-  monkeyPatch(window, "updateReminder", function(protofunc, event) {
-    let rv = protofunc.apply(this, Array.from(arguments).slice(1));
-    if (
-      event.explicitOriginalTarget.localName == "listitem" ||
-      event.explicitOriginalTarget.id == "reminder-remove-button" ||
-      !document.commandDispatcher.focusedElement
-    ) {
-      // Same hack from the original dialog
-      return undefined;
-    }
-
-    checkAllReminders();
-    return rv;
-  });
-
-  monkeyPatch(window, "loadReminders", function(protofunc, ...args) {
-    let rv = protofunc.apply(this, args);
-    checkAllReminders();
-    hideReminderRelations();
-    hideSMSReminders();
-    return rv;
-  });
-})();
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-event-dialog-reminder.xul
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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/. -->
-
-<?xml-stylesheet type="text/css" href="chrome://messenger/content/notification.css"?>
-<?xml-stylesheet type="text/css" href="chrome://gdata-provider/skin/gdata-event-dialog-reminder.css"?>
-
-<!DOCTYPE overlay SYSTEM "chrome://gdata-provider/locale/gdata.dtd">
-
-<overlay id="gdata-event-dialog-reminder-overlay"
-         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
-  <script src="chrome://gdata-provider/content/gdata-event-dialog-reminder.js"/>
-  <menupopup id="reminder-actions-menupopup">
-    <menuitem id="reminder-action-SMS"
-              class="reminder-icon menuitem-iconic"
-              value="SMS"
-              insertafter="reminder-action-EMAIL reminder-action-DISPLAY"
-              provider="gdata"
-              label="&gdata.reminder.action.sms.label;"/>
-  </menupopup>
-</overlay>
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-event-dialog.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-window.addEventListener("message", aEvent => {
-  if (aEvent.origin !== "chrome://lightning") {
-    return;
-  }
-
-  switch (aEvent.data.command) {
-    case "gdataIsTask": {
-      let disableForTaskIds = [
-        "options-attachments-menu",
-        "options-attendees-menuitem",
-        "options-privacy-menu",
-        "options-priority-menu",
-        "options-freebusy-menu",
-        "button-attendees",
-        "button-privacy",
-        "button-url",
-      ];
-
-      for (let id of disableForTaskIds) {
-        let node = document.getElementById(id);
-        if (node) {
-          node.disabled = aEvent.data.isGoogleTask;
-        }
-      }
-    }
-  }
-});
-
-const gdataStatusPrivacyHbox = document.createXULElement("hbox");
-gdataStatusPrivacyHbox.setAttribute("id", "gdata-status-privacy-default-box");
-gdataStatusPrivacyHbox.setAttribute("privacy", "DEFAULT");
-gdataStatusPrivacyHbox.setAttribute("provider", "gdata");
-
-const statusPrivacy = document.getElementById("status-privacy");
-statusPrivacy.insertBefore(
-  gdataStatusPrivacyHbox,
-  document.getElementById("status-privacy-public-box")
-);
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-event-dialog.xul
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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/. -->
-
-<!DOCTYPE overlay SYSTEM "chrome://gdata-provider/locale/gdata.dtd">
-
-<overlay id="gdata-calendar-event-dialog"
-         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
-  <script src="chrome://gdata-provider/content/gdata-event-dialog.js"/>
-
-  <!-- Privacy items -->
-  <menupopup id="options-privacy-menupopup">
-    <menuitem id="gdata-options-privacy-default-menuitem"
-              insertbefore="options-privacy-public-menuitem,options-privacy-private-menuitem"
-              label="&gdata.privacy.default.label;"
-              accesskey="&gdata.privacy.default.accesskey;"
-              type="radio"
-              privacy="DEFAULT"
-              provider="gdata"
-              oncommand="editPrivacy(this)"/>
-  </menupopup>
-
-  <hbox id="status-privacy" class="statusbarpanel" />
-</overlay>
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-lightning-item-iframe.js
+++ /dev/null
@@ -1,207 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* import-globals-from ../../../lightning/content/lightning-item-iframe.js */
-/* import-globals-from ../../../base/content/dialogs/calendar-dialog-utils.js */
-
-var { monkeyPatch } = ChromeUtils.import("resource://gdata-provider/modules/gdataUtils.jsm");
-
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-
-(function() {
-  monkeyPatch(window, "updateCalendar", function(protofunc, ...args) {
-    let rv = protofunc.apply(this, args);
-    let calendar = getCurrentCalendar();
-    let isGoogleCalendar = calendar.type == "gdata";
-    let isTask = cal.item.isToDo(window.calendarItem);
-    let isEvent = cal.item.isEvent(window.calendarItem);
-    let isGoogleTask = isGoogleCalendar && isTask;
-    let isGoogleEvent = isGoogleCalendar && isEvent;
-
-    sendMessage({ command: "gdataIsTask", isGoogleTask: isGoogleTask });
-
-    let xulHideForTaskIds = [
-      "timezone-endtime",
-      "link-image-bottom",
-
-      "event-grid-tab-attendees",
-      "event-grid-tabpanel-attendees",
-
-      "todo-status-none-menuitem",
-      "todo-status-inprogress-menuitem",
-      "todo-status-canceled-menuitem",
-
-      "percent-complete-textbox",
-      "percent-complete-label",
-    ];
-
-    for (let id of xulHideForTaskIds) {
-      let node = document.getElementById(id);
-      if (node) {
-        node.hidden = isGoogleTask;
-      }
-    }
-
-    let hideForTaskIds = [
-      "event-grid-location-row",
-      "event-grid-startdate-row",
-      "event-grid-recurrence-row",
-      "event-grid-alarm-row",
-    ];
-
-    for (let id of hideForTaskIds) {
-      document.getElementById(id).toggleAttribute("hidden", isGoogleTask);
-    }
-
-    let duedate = document.getElementById("todo-duedate");
-    let duetime =
-      duedate._timepicker || // From Lightning 6.9 onwards
-      document.getAnonymousElementByAttribute(duedate, "anonid", "time-picker");
-    duetime.style.display = isGoogleTask ? "none" : "";
-
-    if (gEndTime) {
-      if (isGoogleTask) {
-        let floating = cal.dtz.floating;
-        if (gEndTimezone != floating) {
-          gOldEndTimezone = gEndTimezone;
-        }
-        gEndTimezone = cal.dtz.floating;
-        gEndTime = gEndTime.getInTimezone(gEndTimezone);
-        gEndTime.isDate = true;
-      } else {
-        if (gOldEndTimezone) {
-          gEndTimezone = gOldEndTimezone;
-        }
-        gEndTime.isDate = false;
-        gEndTime = gEndTime.getInTimezone(gEndTimezone);
-      }
-      updateDateTime();
-    }
-
-    let elements = document.getElementsByAttribute("provider", "gdata");
-    for (let elem of elements) {
-      elem.style.display = isGoogleCalendar ? "" : "none";
-    }
-
-    let reminderList = document.getElementById("item-alarm");
-    let hasDefaultReminders = isGoogleEvent && calendar.getProperty("settings.defaultReminders");
-    if (isGoogleCalendar && !hasDefaultReminders && reminderList.value == "default") {
-      reminderList.value = "none";
-    }
-
-    document.getElementById("gdata-reminder-default-menuitem").style.display = hasDefaultReminders
-      ? ""
-      : "none";
-
-    // Remove categories for Google Tasks
-    let categoriesLabel = document.getElementById("item-categories-label");
-    let calendarLabel = document.getElementById("item-calendar-label");
-    if (!categoriesLabel.origLabel) {
-      categoriesLabel.origLabel = categoriesLabel.value;
-    }
-
-    document
-      .getElementById("event-grid-category-color-row")
-      .toggleAttribute("hidden", isGoogleTask);
-
-    if (isGoogleTask) {
-      categoriesLabel.value = calendarLabel.value;
-    } else {
-      categoriesLabel.value = categoriesLabel.origLabel;
-    }
-
-    return rv;
-  });
-
-  monkeyPatch(window, "updateCategoryMenulist", function(protofunc, ...args) {
-    let rv;
-    let calendar = getCurrentCalendar();
-    if (calendar.type == "gdata" && cal.item.isToDo(window.calendarItem)) {
-      let unwrappedCal = calendar.getProperty("cache.uncachedCalendar").wrappedJSObject;
-      unwrappedCal.mProperties["capabilities.categories.maxCount"] = 0;
-      rv = protofunc.apply(this, args);
-      delete unwrappedCal.mProperties["capabilities.categories.maxCount"];
-    } else {
-      rv = protofunc.apply(this, args);
-    }
-    return rv;
-  });
-
-  monkeyPatch(window, "updateReminderDetails", function(protofunc, ...args) {
-    let rv = protofunc.apply(this, args);
-    let reminderList = document.getElementById("item-alarm");
-
-    if (reminderList.value == "default") {
-      removeChildren("reminder-icon-box");
-    }
-
-    return rv;
-  });
-
-  monkeyPatch(window, "saveReminder", function(protofunc, item, ...args) {
-    let calendar = getCurrentCalendar();
-    let reminderList = document.getElementById("item-alarm");
-    if (calendar.type == "gdata" && reminderList.value == "default") {
-      item.clearAlarms();
-      let unwrappedCal = item.calendar.getProperty("cache.uncachedCalendar").wrappedJSObject;
-      let defaultReminders = unwrappedCal.defaultReminders;
-
-      defaultReminders.forEach(item.addAlarm, item);
-      if (!defaultReminders.length) {
-        item.setProperty("X-DEFAULT-ALARM", "TRUE");
-      }
-      return null;
-    } else {
-      item.deleteProperty("X-DEFAULT-ALARM");
-      return protofunc.call(this, item, ...args);
-    }
-  });
-
-  monkeyPatch(window, "loadReminders", function(protofunc, reminders, ...args) {
-    let reminderList = document.getElementById("item-alarm");
-
-    // Set up the default reminders item
-    let defaultItem = document.getElementById("gdata-reminder-default-menuitem");
-    let calendar = getCurrentCalendar().getProperty("cache.uncachedCalendar");
-    let unwrappedCal = calendar && calendar.wrappedJSObject;
-    let defaultReminders = unwrappedCal.defaultReminders
-      ? unwrappedCal.defaultReminders.concat([])
-      : [];
-    defaultItem.reminders = defaultReminders;
-
-    let rv = null;
-    let usesDefault;
-    if (reminders.length) {
-      usesDefault = reminders.every(reminder => reminder.hasProperty("X-DEFAULT-ALARM"));
-    } else {
-      usesDefault = window.calendarItem.getProperty("X-DEFAULT-ALARM") == "TRUE";
-    }
-
-    if (calendar.type == "gdata" && (window.mode == "new" || usesDefault)) {
-      // If all reminders are default reminders, then select the menuitem.
-      reminderList.value = "default";
-
-      // remember the selected index
-      gLastAlarmSelection = reminderList.selectedIndex;
-    } else {
-      rv = protofunc.call(this, reminders, ...args);
-    }
-    return rv;
-  });
-
-  monkeyPatch(window, "editReminder", function(protofunc, ...args) {
-    let rv = protofunc.apply(this, args);
-
-    // Now that the custom reminders were changed, we need to remove the
-    // default alarm status, otherwise the wrong alarm will be set.
-    let customItem = document.getElementById("reminder-custom-menuitem");
-    if (customItem.reminders) {
-      for (let reminder of customItem.reminders) {
-        reminder.deleteProperty("X-DEFAULT-ALARM");
-      }
-    }
-
-    return rv;
-  });
-})();
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-lightning-item-iframe.xul
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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/. -->
-
-<!DOCTYPE overlay SYSTEM "chrome://gdata-provider/locale/gdata.dtd">
-
-<overlay id="gdata-lightning-item-iframe"
-         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
-  <script src="chrome://gdata-provider/content/gdata-lightning-item-iframe.js"/>
-
-  <menupopup id="item-alarm-menupopup">
-    <menuitem id="gdata-reminder-default-menuitem"
-              insertbefore="reminder-none-separator"
-              label="&gdata.reminder.default;"
-              provider="gdata"
-              value="default"/>
-  </menupopup>
-</overlay>
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-lightning-item-toolbar.xul
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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/. -->
-
-<!DOCTYPE overlay SYSTEM "chrome://gdata-provider/locale/gdata.dtd">
-
-<overlay id="gdata-lightning-item-toolbar"
-         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
-  <menupopup id="event-privacy-menupopup">
-    <menuitem id="gdata-event-privacy-default-menuitem"
-              name="event-privacy-group"
-              insertbefore="event-privacy-public-menuitem,event-privacy-private-menuitem"
-              label="&gdata.privacy.default.label;"
-              type="radio"
-              provider="gdata"
-              privacy="DEFAULT"
-              oncommand="editPrivacy(this)"/>
-  </menupopup>
-</overlay>
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-migration-overlay.xul
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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/. -->
-
-<overlay id="gdata-migration-overlay"
-         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
-  <script src="chrome://gdata-provider/content/gdata-migration.js"/>
-</overlay>
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-migration-wizard.xul
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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/. -->
-
-<!DOCTYPE dialog SYSTEM "chrome://gdata-provider/locale/gdata.dtd">
-
-<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
-
-<dialog id="gdata-migration-wizard"
-        title="&gdata.migration.title;"
-        windowtype="Calendar:GData:MigrationDialog"
-        buttons="accept,cancel"
-        acceptLabel="&gdata.migration.upgrade.label;"
-        acceptKey="&gdata.migration.upgrade.accesskey;"
-        width="300"
-        height="300"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml">
-  <script src="chrome://gdata-provider/content/gdata-migration.js"/>
-  <script src="chrome://calendar/content/calendar-views-utils.js"/>
-  <script src="chrome://calendar/content/calendar-ui-utils.js"/>
-
-  <description>&gdata.migration.description;</description>
-  <vbox id="calendars-listbox" flex="1"/>
-  <checkbox id="showagain-checkbox" label="&gdata.migration.showagain.label;"/>
-</dialog>
deleted file mode 100644
--- a/calendar/providers/gdata/content/gdata-migration.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* import-globals-from ../../../base/content/calendar-ui-utils.js */
-
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-/**
- * Migrate the calendar selected in the wizard from ics to gdata.
- */
-if (document.documentElement.id == "gdata-migration-wizard") {
-  document.addEventListener("dialogaccept", () => {
-    let listbox = document.getElementById("calendars-listbox");
-    let calmgr = cal.getCalendarManager();
-
-    for (let i = 0; i < listbox.childNodes.length; i++) {
-      let item = listbox.childNodes[i];
-      if (item.checked) {
-        // Migrate the calendar to a gdata calendar
-        let newCal = calmgr.createCalendar("gdata", item.calendar.uri);
-        calmgr.removeCalendar(item.calendar);
-
-        // Copy some properties to the new calendar
-        newCal.name = item.calendar.name;
-        newCal.setProperty("color", item.calendar.getProperty("color"));
-        newCal.setProperty("disabled", item.calendar.getProperty("disabled"));
-        newCal.setProperty("cache.enabled", item.calendar.getProperty("cache.enabled"));
-        newCal.setProperty("suppressAlarms", item.calendar.getProperty("suppressAlarms"));
-        newCal.setProperty(
-          "calendar-main-in-composite",
-          item.calendar.getProperty("calendar-main-in-composite")
-        );
-        newCal.setProperty(
-          "calendar-main-default",
-          item.calendar.getProperty("calendar-main-default")
-        );
-
-        calmgr.registerCalendar(newCal);
-      }
-    }
-
-    // Only bring up the dialog on the next startup if the user wants us to.
-    Services.prefs.setBoolPref(
-      "calendar.google.migrate",
-      document.getElementById("showagain-checkbox").checked
-    );
-  });
-}
-
-/**
- * Get all calendars that are ics and point to a google calendar
- *
- * @return An array of calendars that are migratable
- */
-function getMigratableCalendars() {
-  function isMigratable(calendar) {
-    let re = new RegExp(
-      "^http[s]?://(www|calendar)\\.google\\.com/calendar/ical/" +
-        "[^/]+/(private(-[^/]+)?|public)/" +
-        "(full|full-noattendees|composite|" +
-        "attendees-only|free-busy|basic)(\\.ics)?$"
-    );
-    return calendar.type == "ics" && calendar.uri.spec.match(re);
-  }
-
-  return cal
-    .getCalendarManager()
-    .getCalendars({})
-    .filter(isMigratable);
-}
-
-/**
- * Load Handler for both the wizard and the Thunderbird main window.
- */
-function gdata_migration_loader() {
-  if (document.documentElement.id == "gdata-migration-wizard") {
-    // This is the migration wizard, load the calendars needed.
-    let listbox = document.getElementById("calendars-listbox");
-
-    for (let calendar of sortCalendarArray(getMigratableCalendars())) {
-      let item = document.createXULElement("checkbox");
-      item.setAttribute("label", calendar.name);
-      item.setAttribute("value", calendar.id);
-      item.calendar = calendar;
-      listbox.appendChild(item);
-    }
-
-    // Set up the "always check" field
-    document.getElementById("showagain-checkbox").checked = Services.prefs.getBoolPref(
-      "calendar.google.migrate",
-      true
-    );
-  } else if (
-    Services.prefs.getBoolPref("calendar.google.migrate", true) &&
-    getMigratableCalendars().length > 0
-  ) {
-    // This is not the migration wizard, so it must be a main window. Check
-    // if the migration wizard needs to be shown and calendars are worth
-    // migrating.
-
-    // Do this after load, so the calendar window appears before the
-    // wizard is opened.
-    // XXX Waiting a second gives the views enough time to display
-    // right, at least on my system. The viewloaded event is quite
-    // view specific, so there is no good non-hacked way to do this.
-    setTimeout(() => {
-      window.openDialog(
-        "chrome://gdata-provider/content/gdata-migration-wizard.xul",
-        "GdataMigrationWizard",
-        "chrome,titlebar,modal,alwaysRaised"
-      );
-    }, 1000);
-  }
-}
-
-// Add a Load handler to check for migratable calendars in the main window, or
-// to load the migration wizard if this is the migration wizard
-window.addEventListener("load", gdata_migration_loader, { capture: false, once: true });
deleted file mode 100644
--- a/calendar/providers/gdata/content/reminder-action-sms.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
-   - License, v. 2.0. If a copy of the MPL was not distributed with this
-   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity" viewBox="0 0 16 16">
-  <path d="M12 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zM9 15H7v-1h2zm3-2.5a.5.5 0 0 1-.5.5h-7a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 .5.5z"/>
-</svg>
deleted file mode 100644
--- a/calendar/providers/gdata/defaults/preferences.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* extension description */
-pref("extensions.{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}.description",
-     "chrome://gdata-provider/locale/gdata.properties");
-pref("extensions.{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}.name",
-     "chrome://gdata-provider/locale/gdata.properties");
-
-/* other default prefs */
-pref("calendar.google.useHTTPMethodOverride", true);
-pref("calendar.google.alarmClosest", true);
-pref("calendar.google.migrate", true);
-pref("calendar.google.maxResultsPerRequest", 1000);
-pref("calendar.google.idleTime", 300);
-pref("calendar.google.enableSMSReminders", false);
-
-/**
- * Invitations and notifications.
- * Note that if enableEmailInvitations is enabled it is a good idea to disable
- * attendees or at least sending event notifications.
- */
-pref("calendar.google.sendEventNotifications", true);
-pref("calendar.google.enableAttendees", true);
-pref("calendar.google.enableEmailInvitations", false);
deleted file mode 100644
--- a/calendar/providers/gdata/jar.mn
+++ /dev/null
@@ -1,48 +0,0 @@
-#filter substitution
-# 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/.
-
-
-gdata-provider.jar:
-% content gdata-provider %content/
-% resource gdata-provider .
-% overlay chrome://calendar/content/calendar-event-dialog.xul chrome://gdata-provider/content/gdata-event-dialog.xul
-% overlay chrome://calendar/content/calendar-event-dialog-reminder.xul chrome://gdata-provider/content/gdata-event-dialog-reminder.xul
-% overlay chrome://calendar/content/calendar-properties-dialog.xul chrome://gdata-provider/content/gdata-calendar-properties.xul
-% overlay chrome://calendar/content/calendarCreation.xul chrome://gdata-provider/content/gdata-calendar-creation.xul
-% overlay chrome://lightning/content/lightning-item-iframe.xul chrome://gdata-provider/content/gdata-lightning-item-iframe.xul
-% overlay chrome://lightning/content/lightning-item-toolbar.xul chrome://gdata-provider/content/gdata-lightning-item-toolbar.xul
-% overlay chrome://messenger/content/messenger.xul chrome://gdata-provider/content/gdata-migration-overlay.xul
-% overlay chrome://messenger/content/messenger.xul chrome://gdata-provider/content/gdata-event-dialog.xul
-% style chrome://calendar/content/calendar-event-dialog.xul chrome://gdata-provider/skin/gdata-event-dialog-reminder.css
-% style chrome://messenger/content/messenger.xul chrome://gdata-provider/skin/gdata-event-dialog-reminder.css
-    content/browserRequest.js                    (content/browserRequest.js)
-    content/browserRequest.xul                   (content/browserRequest.xul)
-    content/gcal.png                             (content/gcal.png)
-    content/gdata-calendar-creation.js           (content/gdata-calendar-creation.js)
-    content/gdata-calendar-creation.xul          (content/gdata-calendar-creation.xul)
-    content/gdata-calendar-properties.js         (content/gdata-calendar-properties.js)
-    content/gdata-calendar-properties.xul        (content/gdata-calendar-properties.xul)
-    content/gdata-event-dialog-reminder.js       (content/gdata-event-dialog-reminder.js)
-    content/gdata-event-dialog-reminder.xul      (content/gdata-event-dialog-reminder.xul)
-    content/gdata-event-dialog.js                (content/gdata-event-dialog.js)
-    content/gdata-event-dialog.xul               (content/gdata-event-dialog.xul)
-    content/gdata-lightning-item-iframe.js       (content/gdata-lightning-item-iframe.js)
-    content/gdata-lightning-item-iframe.xul      (content/gdata-lightning-item-iframe.xul)
-    content/gdata-lightning-item-toolbar.xul     (content/gdata-lightning-item-toolbar.xul)
-    content/gdata-migration-overlay.xul          (content/gdata-migration-overlay.xul)
-    content/gdata-migration-wizard.xul           (content/gdata-migration-wizard.xul)
-    content/gdata-migration.js                   (content/gdata-migration.js)
-% skin gdata-provider classic/1.0 %skin/
-    skin/browserRequest.css                      (content/browserRequest.css)
-    skin/gdata-bindings.css                      (content/gdata-bindings.css)
-    skin/gdata-event-dialog-reminder.css         (content/gdata-event-dialog-reminder.css)
-    skin/reminder-action-sms.svg                 (content/reminder-action-sms.svg)
-
-
-gdata-provider-@AB_CD@.jar:
-relativesrcdir comm/calendar/locales:
-% locale gdata-provider @AB_CD@ %
-    gdata.dtd                                    (%chrome/calendar/providers/gdata/gdata.dtd)
-    gdata.properties                             (%chrome/calendar/providers/gdata/gdata.properties)
deleted file mode 100644
--- a/calendar/providers/gdata/manifest.json
+++ /dev/null
@@ -1,24 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-#filter substitution
-{
-  "manifest_version": 2,
-  "name": "Provider for Google Calendar",
-  "description": "Allows bidirectional access to Google Calendar",
-  "version": "@THUNDERBIRD_VERSION_DISPLAY@",
-  "author": "Philipp Kewisch",
-  "homepage_url": "https://addons.mozilla.org/thunderbird/addon/4631",
-  "legacy": true,
-  "applications": {
-    "gecko": {
-      "id": "{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}",
-      "strict_min_version": "@MOZ_APP_VERSION@",
-      "strict_max_version": "@MOZ_APP_MAXVERSION@"
-    }
-  },
-  "icons": {
-    "256": "chrome/gdata-provider/content/gcal.png"
-  }
-}
deleted file mode 100644
--- a/calendar/providers/gdata/modules/OAuth2.jsm
+++ /dev/null
@@ -1,262 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * Provides OAuth 2.0 authentication
- */
-var EXPORTED_SYMBOLS = ["OAuth2"]; /* exported OAuth2 */
-
-// Backwards compatibility with Thunderbird <60.
-if (!("Cc" in this)) {
-  // eslint-disable-next-line mozilla/no-define-cc-etc, no-unused-vars
-  const { interfaces: Ci, results: Cr } = Components;
-}
-
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-var { Log4Moz } = ChromeUtils.import("resource:///modules/gloda/log4moz.js");
-var { httpRequest } = ChromeUtils.import("resource://gre/modules/Http.jsm");
-
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-
-function parseURLData(aData) {
-  let result = {};
-  aData
-    .split(/[?#]/, 2)[1]
-    .split("&")
-    .forEach(aParam => {
-      let [key, value] = aParam.split("=");
-      result[key] = value;
-    });
-  return result;
-}
-
-function OAuth2(aBaseURI, aScope, aAppKey, aAppSecret) {
-  this.authURI = aBaseURI + "oauth2/auth";
-  this.tokenURI = aBaseURI + "oauth2/token";
-  this.consumerKey = aAppKey;
-  this.consumerSecret = aAppSecret;
-  this.scope = aScope;
-  this.extraAuthParams = [];
-
-  this.log = Log4Moz.getConfiguredLogger("TBOAuth");
-}
-
-OAuth2.CODE_AUTHORIZATION = "authorization_code";
-OAuth2.CODE_REFRESH = "refresh_token";
-
-OAuth2.prototype = {
-  responseType: "code",
-  consumerKey: null,
-  consumerSecret: null,
-  completionURI: "http://localhost",
-  requestWindowURI: "chrome://messenger/content/browserRequest.xul",
-  requestWindowFeatures: "chrome,private,centerscreen,width=980,height=750",
-  requestWindowTitle: "",
-  requestWindowDescription: "",
-  scope: null,
-
-  accessToken: null,
-  refreshToken: null,
-  tokenExpires: 0,
-  connecting: false,
-
-  connect: function(aSuccess, aFailure, aWithUI, aRefresh) {
-    if (this.connecting) {
-      return;
-    }
-
-    this.connectSuccessCallback = aSuccess;
-    this.connectFailureCallback = aFailure;
-
-    if (!aRefresh && this.accessToken) {
-      aSuccess();
-    } else if (this.refreshToken) {
-      this.connecting = true;
-      this.requestAccessToken(this.refreshToken, OAuth2.CODE_REFRESH);
-    } else {
-      if (!aWithUI) {
-        aFailure('{ "error": "auth_noui" }');
-        return;
-      }
-      this.connecting = true;
-      this.requestAuthorization();
-    }
-  },
-
-  requestAuthorization: function() {
-    let params = [
-      ["response_type", this.responseType],
-      ["client_id", this.consumerKey],
-      ["redirect_uri", this.completionURI],
-    ];
-    // The scope can be optional.
-    if (this.scope) {
-      params.push(["scope", this.scope]);
-    }
-
-    // Add extra parameters, if they exist
-    Array.prototype.push.apply(params, this.extraAuthParams);
-
-    // Now map the parameters to a string
-    params = params.map(([k, v]) => k + "=" + encodeURIComponent(v)).join("&");
-
-    this._browserRequest = {
-      account: this,
-      url: this.authURI + "?" + params,
-      description: this.requestWindowDescription,
-      _active: true,
-      iconURI: "",
-      cancelled: function() {
-        if (!this._active) {
-          return;
-        }
-
-        this.account.finishAuthorizationRequest();
-        this.account.onAuthorizationFailed(Cr.NS_ERROR_ABORT, '{ "error": "cancelled"}');
-      },
-
-      loaded: function(aWindow, aWebProgress) {
-        if (!this._active) {
-          return;
-        }
-
-        this._listener = {
-          window: aWindow,
-          webProgress: aWebProgress,
-          _parent: this.account,
-
-          QueryInterface: cal.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]),
-
-          _cleanUp: function() {
-            this.webProgress.removeProgressListener(this);
-            this.window.close();
-            delete this.window;
-          },
-
-          _checkForRedirect: function(aURL) {
-            if (!aURL.startsWith(this._parent.completionURI)) {
-              return;
-            }
-
-            this._parent.finishAuthorizationRequest();
-            this._parent.onAuthorizationReceived(aURL);
-          },
-
-          onStateChange: function(aChangedWebProgress, aRequest, aStateFlags, aStatus) {
-            const wpl = Ci.nsIWebProgressListener;
-            if (aStateFlags & wpl.STATE_STOP) {
-              try {
-                let httpchannel = aRequest.QueryInterface(Ci.nsIHttpChannel);
-
-                let responseCategory = Math.floor(httpchannel.responseStatus / 100);
-
-                if (responseCategory != 2 && responseCategory != 3) {
-                  this._parent.finishAuthorizationRequest();
-                  this._parent.onAuthorizationFailed(
-                    null,
-                    '{ "error": "http_' + httpchannel.responseStatus + '" }'
-                  );
-                }
-              } catch (e) {
-                // Throw the case where it's a http channel.
-                if (e.result != Cr.NS_ERROR_NO_INTERFACE) {
-                  throw e;
-                }
-              }
-            }
-
-            if (aStateFlags & (wpl.STATE_START | wpl.STATE_IS_NETWORK)) {
-              this._checkForRedirect(aRequest.name);
-            }
-          },
-          onLocationChange: function(aChangedWebProgress, aRequest, aLocation) {
-            this._checkForRedirect(aLocation.spec);
-          },
-          onProgressChange: function() {},
-          onStatusChange: function() {},
-          onSecurityChange: function() {},
-        };
-        aWebProgress.addProgressListener(this._listener, Ci.nsIWebProgress.NOTIFY_ALL);
-        aWindow.document.title = this.account.requestWindowTitle;
-      },
-    };
-
-    this.wrappedJSObject = this._browserRequest;
-    Services.ww.openWindow(null, this.requestWindowURI, null, this.requestWindowFeatures, this);
-  },
-  finishAuthorizationRequest: function() {
-    if (!("_browserRequest" in this)) {
-      return;
-    }
-
-    this._browserRequest._active = false;
-    if ("_listener" in this._browserRequest) {
-      this._browserRequest._listener._cleanUp();
-    }
-    delete this._browserRequest;
-  },
-
-  onAuthorizationReceived: function(aData) {
-    this.log.info("authorization received" + aData);
-    let results = parseURLData(aData);
-    if (this.responseType == "code") {
-      this.requestAccessToken(results.code, OAuth2.CODE_AUTHORIZATION);
-    } else if (this.responseType == "token") {
-      this.onAccessTokenReceived(JSON.stringify(results));
-    }
-  },
-
-  onAuthorizationFailed: function(aError, aData) {
-    this.connecting = false;
-    this.connectFailureCallback(aData);
-  },
-
-  requestAccessToken: function(aCode, aType) {
-    let params = [
-      ["client_id", this.consumerKey],
-      ["client_secret", this.consumerSecret],
-      ["grant_type", aType],
-    ];
-
-    if (aType == OAuth2.CODE_AUTHORIZATION) {
-      params.push(["code", aCode]);
-      params.push(["redirect_uri", this.completionURI]);
-    } else if (aType == OAuth2.CODE_REFRESH) {
-      params.push(["refresh_token", aCode]);
-    }
-
-    let options = {
-      postData: params,
-      onLoad: this.onAccessTokenReceived.bind(this),
-      onError: this.onAccessTokenFailed.bind(this),
-    };
-    httpRequest(this.tokenURI, options);
-  },
-
-  onAccessTokenFailed: function(aError, aData) {
-    if (aError != "offline") {
-      this.refreshToken = null;
-    }
-    this.connecting = false;
-    this.connectFailureCallback(aData);
-  },
-
-  onAccessTokenReceived: function(aData) {
-    let result = JSON.parse(aData);
-
-    this.accessToken = result.access_token;
-    if ("refresh_token" in result) {
-      this.refreshToken = result.refresh_token;
-    }
-    if ("expires_in" in result) {
-      this.tokenExpires = new Date().getTime() + result.expires_in * 1000;
-    } else {
-      this.tokenExpires = Number.MAX_VALUE;
-    }
-    this.tokenType = result.token_type;
-
-    this.connecting = false;
-    this.connectSuccessCallback();
-  },
-};
deleted file mode 100644
--- a/calendar/providers/gdata/modules/gdataLogging.jsm
+++ /dev/null
@@ -1,179 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ["LOGitem", "LOGverbose", "LOGinterval", "stringException"];
-
-// Backwards compatibility with Thunderbird <60.
-if (!("Cc" in this)) {
-  // eslint-disable-next-line mozilla/no-define-cc-etc, no-unused-vars
-  const { interfaces: Ci } = Components;
-}
-
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-function LOGverbose(aStr) {
-  if (Services.prefs.getBoolPref("calendar.debug.log.verbose", false)) {
-    cal.LOG(aStr);
-  }
-}
-
-function stringException(e) {
-  if ("fileName" in e && "lineNumber" in e) {
-    return " (" + e.fileName + ":" + e.lineNumber + "):" + e;
-  } else {
-    return e.toString();
-  }
-}
-
-/**
- * LOGitem
- * Custom logging functions
- */
-function LOGitem(item) {
-  if (!item) {
-    return;
-  }
-
-  let attendees = item.getAttendees({});
-  let attendeeString = "";
-  for (let a of attendees) {
-    attendeeString += "\n" + LOGattendee(a);
-  }
-
-  let rstr = "\n";
-  if (item.recurrenceInfo) {
-    let ritems = item.recurrenceInfo.getRecurrenceItems({});
-    for (let ritem of ritems) {
-      rstr += "\t\t" + ritem.icalProperty.icalString;
-    }
-
-    rstr += "\tExceptions:\n";
-    let exids = item.recurrenceInfo.getExceptionIds({});
-    for (let exc of exids) {
-      rstr += "\t\t" + exc + "\n";
-    }
-  }
-
-  let astr = "\n";
-  let alarms = item.getAlarms({});
-  for (let alarm of alarms) {
-    astr += "\t\t" + LOGalarm(alarm) + "\n";
-  }
-
-  LOGverbose(
-    "[calGoogleCalendar] Logging calIEvent:" +
-      "\n\tid:" +
-      item.id +
-      "\n\tcreated:" +
-      item.getProperty("CREATED") +
-      "\n\tupdated:" +
-      item.getProperty("LAST-MODIFIED") +
-      "\n\ttitle:" +
-      item.title +
-      "\n\tdescription:" +
-      item.getProperty("DESCRIPTION") +
-      "\n\ttransparency:" +
-      item.getProperty("TRANSP") +
-      "\n\tstatus:" +
-      item.status +
-      "\n\tstartTime:" +
-      (item.startDate && item.startDate.toString()) +
-      "\n\tendTime:" +
-      (item.endDate && item.endDate.toString()) +
-      "\n\tlocation:" +
-      item.getProperty("LOCATION") +
-      "\n\tprivacy:" +
-      item.privacy +
-      "\n\tsequence:" +
-      item.getProperty("SEQUENCE") +
-      "\n\talarmLastAck:" +
-      item.alarmLastAck +
-      "\n\tsnoozeTime:" +
-      item.getProperty("X-MOZ-SNOOZE-TIME") +
-      "\n\tisOccurrence: " +
-      (item.recurrenceId != null) +
-      "\n\tOrganizer: " +
-      LOGattendee(item.organizer) +
-      "\n\tAttendees: " +
-      attendeeString +
-      "\n\trecurrence: " +
-      (rstr.length > 1 ? "yes: " + rstr : "no") +
-      "\n\talarms: " +
-      (astr.length > 1 ? "yes: " + astr : "no")
-  );
-}
-
-function LOGattendee(aAttendee, asString) {
-  return (
-    aAttendee &&
-    "\n\t\tID: " +
-      aAttendee.id +
-      "\n\t\t\tName: " +
-      aAttendee.commonName +
-      "\n\t\t\tRsvp: " +
-      aAttendee.rsvp +
-      "\n\t\t\tIs Organizer: " +
-      (aAttendee.isOrganizer ? "yes" : "no") +
-      "\n\t\t\tRole: " +
-      aAttendee.role +
-      "\n\t\t\tStatus: " +
-      aAttendee.participationStatus
-  );
-}
-
-function LOGalarm(aAlarm) {
-  if (!aAlarm) {
-    return "";
-  }
-
-  let xpropstr = "";
-  for (let [name, value] of aAlarm.properties) {
-    xpropstr += "\n\t\t\t" + name + ":" + value;
-  }
-
-  return (
-    "\n\t\tAction: " +
-    aAlarm.action +
-    "\n\t\tOffset: " +
-    (aAlarm.offset && aAlarm.offset.toString()) +
-    "\n\t\talarmDate: " +
-    (aAlarm.alarmDate && aAlarm.alarmDate.toString()) +
-    "\n\t\trelated: " +
-    aAlarm.related +
-    "\n\t\trepeat: " +
-    aAlarm.repeat +
-    "\n\t\trepeatOffset: " +
-    (aAlarm.repeatOffset && aAlarm.repeatOffset.toString()) +
-    "\n\t\trepeatDate: " +
-    (aAlarm.repeatDate && aAlarm.repeatDate.toString()) +
-    "\n\t\tdescription: " +
-    aAlarm.description +
-    "\n\t\tsummary: " +
-    aAlarm.summary +
-    "\n\t\tproperties: " +
-    (xpropstr.length > 0 ? "yes:" + xpropstr : "no")
-  );
-}
-
-function LOGinterval(aInterval) {
-  const fbtypes = Ci.calIFreeBusyInterval;
-  let type;
-  if (aInterval.freeBusyType == fbtypes.FREE) {
-    type = "FREE";
-  } else if (aInterval.freeBusyType == fbtypes.BUSY) {
-    type = "BUSY";
-  } else {
-    type = aInterval.freeBusyType + " (UNKNOWN)";
-  }
-
-  cal.LOG(
-    "[calGoogleCalendar] Interval from " +
-      aInterval.interval.start +
-      " to " +
-      aInterval.interval.end +
-      " is " +
-      type
-  );
-}
deleted file mode 100644
--- a/calendar/providers/gdata/modules/gdataRequest.jsm
+++ /dev/null
@@ -1,557 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// Backwards compatibility with Thunderbird <60.
-if (!("Cc" in this)) {
-  // eslint-disable-next-line mozilla/no-define-cc-etc, no-unused-vars
-  const { classes: Cc, interfaces: Ci, results: Cr } = Components;
-}
-
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-var { PromiseUtils } = ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm");
-
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-
-var API_BASE = {
-  EVENTS: "https://www.googleapis.com/calendar/v3/",
-  TASKS: "https://www.googleapis.com/tasks/v1/",
-};
-
-var EXPORTED_SYMBOLS = ["calGoogleRequest", "getCorrectedDate", "API_BASE"];
-
-/**
- * Gets the date and time that Google's http server last sent us. Note the
- * passed argument is modified. This might not be the exact server time (i.e it
- * may be off by network latency), but it does give a good guess when syncing.
- *
- * @param aDate     The date to modify.
- */
-function getCorrectedDate(aDate) {
-  if (getCorrectedDate.mClockSkew) {
-    aDate.second += getCorrectedDate.mClockSkew;
-  }
-  return aDate;
-}
-
-/**
- * calGoogleRequest
- * This class represents a HTTP request sent to Google
- *
- * @constructor
- * @class
- */
-function calGoogleRequest() {
-  this.mQueryParameters = new Map();
-  this.mRequestHeaders = new Map();
-  this.wrappedJSObject = this;
-}
-calGoogleRequest.ADD = "POST";
-calGoogleRequest.MODIFY = "PUT";
-calGoogleRequest.DELETE = "DELETE";
-calGoogleRequest.GET = "GET";
-calGoogleRequest.PATCH = "PATCH";
-
-var GDATA_ERROR_BASE = Ci.calIErrors.ERROR_BASE + 0x400;
-calGoogleRequest.LOGIN_FAILED = GDATA_ERROR_BASE + 1;
-calGoogleRequest.CONFLICT_DELETED = GDATA_ERROR_BASE + 2;
-calGoogleRequest.CONFLICT_MODIFY = GDATA_ERROR_BASE + 3;
-calGoogleRequest.NOT_MODIFIED = GDATA_ERROR_BASE + 4;
-calGoogleRequest.QUOTA_FAILURE = GDATA_ERROR_BASE + 5;
-calGoogleRequest.TOKEN_FAILURE = GDATA_ERROR_BASE + 6;
-calGoogleRequest.RESOURCE_GONE = GDATA_ERROR_BASE + 7;
-
-calGoogleRequest.prototype = {
-  /* Members */
-  mUploadContent: null,
-  mUploadData: null,
-  mSession: null,
-  mQueryParameters: null,
-  mType: null,
-  mLoader: null,
-  mDeferred: null,
-  mStatus: Cr.NS_OK,
-
-  /* Constants */
-  ADD: calGoogleRequest.ADD,
-  MODIFY: calGoogleRequest.MODIFY,
-  DELETE: calGoogleRequest.DELETE,
-  GET: calGoogleRequest.GET,
-  PATCH: calGoogleRequest.PATCH,
-
-  /* Simple Attributes */
-  method: "GET",
-  id: null,
-  uri: null,
-  calendar: null,
-  reauthenticate: true,
-  requestDate: null,
-
-  QueryInterface: cal.generateQI([
-    Ci.calIOperation,
-    Ci.nsIStreamLoaderObserver,
-    Ci.nsIInterfaceRequestor,
-    Ci.nsIChannelEventSink,
-  ]),
-
-  /**
-   * Implement calIOperation
-   */
-  get isPending() {
-    return this.mLoader && this.mLoader.request != null;
-  },
-
-  get status() {
-    if (this.isPending) {
-      return this.mLoader.request.status;
-    } else {
-      return this.mStatus;
-    }
-  },
-
-  cancel: function(aStatus) {
-    if (this.isPending) {
-      if (this.mLoader) {
-        this.mLoader.request.cancel(aStatus);
-      }
-      this.mStatus = aStatus;
-    }
-  },
-
-  /**
-   * attribute type
-   * The type of this request. Must be one of
-   * GET, ADD, MODIFY, DELETE
-   */
-  get type() {
-    return this.method;
-  },
-
-  set type(val) {
-    let valid = [this.GET, this.ADD, this.MODIFY, this.PATCH, this.DELETE];
-    if (!valid.includes(val)) {
-      throw new Components.Exception("Invalid request type: " + val, Cr.NS_ERROR_ILLEGAL_VALUE);
-    }
-    return (this.method = val);
-  },
-
-  /**
-   * setUploadData
-   * The HTTP body data for a POST or PUT request.
-   *
-   * @param aContentType The Content type of the Data.
-   * @param aData        The Data to upload.
-   */
-  setUploadData: function(aContentType, aData) {
-    this.mUploadContent = aContentType;
-    this.mUploadData = aData;
-  },
-
-  addQueryParameter: function(aKey, aValue) {
-    if (aValue) {
-      this.mQueryParameters.set(aKey, aValue);
-    } else {
-      this.mQueryParameters.delete(aKey);
-    }
-  },
-
-  addRequestHeader: function(aKey, aValue) {
-    if (aValue) {
-      this.mRequestHeaders.set(aKey, aValue);
-    } else {
-      this.mRequestHeaders.delete(aKey);
-    }
-  },
-
-  /**
-   * commit
-   * Starts the request process. This can be called multiple times if the
-   * request should be repeated
-   *
-   * @param aSession  The session object this request should be made with.
-   *                  This parameter is optional.
-   */
-  commit: function(aSession) {
-    if (!this.mDeferred) {
-      this.mDeferred = PromiseUtils.defer();
-    }
-    let promise = this.mDeferred.promise;
-
-    try {
-      // Set the session to request with
-      if (aSession) {
-        this.mSession = aSession;
-      }
-
-      // create the channel
-      let uristring = this.uri;
-      if (this.mQueryParameters.size > 0) {
-        let params = [];
-
-        // Using forEach is needed for backwards compatibility
-        this.mQueryParameters.forEach((val, key) => {
-          params.push(key + "=" + encodeURIComponent(val));
-        });
-        uristring += "?" + params.join("&");
-      }
-      let uri = Services.io.newURI(uristring);
-      let channel;
-      if ("newChannelFromURI2" in Services.io) {
-        // Before mozilla67, Lightning 6.8 and below.
-        channel = Services.io.newChannelFromURI2(
-          uri,
-          null,
-          Services.scriptSecurityManager.getSystemPrincipal(),
-          null,
-          Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
-          Ci.nsIContentPolicy.TYPE_OTHER
-        );
-      } else {
-        // mozilla67 and later, Lightning 6.9.
-        channel = Services.io.newChannelFromURI(
-          uri,
-          null,
-          Services.scriptSecurityManager.getSystemPrincipal(),
-          null,
-          Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
-          Ci.nsIContentPolicy.TYPE_OTHER
-        );
-      }
-
-      cal.LOG("[calGoogleRequest] Requesting " + this.method + " " + channel.URI.spec);
-
-      this.prepareChannel(channel);
-
-      channel = channel.QueryInterface(Ci.nsIHttpChannel);
-      channel.redirectionLimit = 3;
-
-      this.mLoader = cal.provider.createStreamLoader();
-      channel.notificationCallbacks = this;
-      cal.provider.sendHttpRequest(this.mLoader, channel, this);
-    } catch (e) {
-      // Let the response function handle the error that happens here
-      this.fail(e.result, e.message);
-    }
-    return promise;
-  },
-
-  /**
-   * fail
-   * Call this request's listener with the given code and Message
-   *
-   * @param aCode     The Error code to fail with.
-   * @param aMessage  The Error message. If this is null, an error Message
-   *                  from calGoogleRequest will be used.
-   */
-  fail: function(aCode, aMessage) {
-    let ex = new Components.Exception(aMessage, aCode);
-    this.mLoader = null;
-    this.mStatus = aCode;
-    this.mDeferred.reject(ex);
-    this.mDeferred = null;
-  },
-
-  /**
-   * succeed
-   * Call this request's listener with a Success Code and the given Result.
-   *
-   * @param aResult   The result Text of this request.
-   */
-  succeed: function(aResult) {
-    this.mLoader = null;
-    this.mStatus = Cr.NS_OK;
-    this.mDeferred.resolve(aResult);
-    this.mDeferred = null;
-  },
-
-  /**
-   * prepareChannel
-   * Prepares the passed channel to match this objects properties
-   *
-   * @param aChannel    The Channel to be prepared.
-   */
-  prepareChannel: function(aChannel) {
-    // No caching
-    aChannel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
-
-    // Set upload Data
-    if (this.mUploadData) {
-      let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(
-        Ci.nsIScriptableUnicodeConverter
-      );
-      converter.charset = "UTF-8";
-
-      let stream = converter.convertToInputStream(this.mUploadData);
-      aChannel = aChannel.QueryInterface(Ci.nsIUploadChannel);
-      aChannel.setUploadStream(stream, this.mUploadContent, -1);
-
-      cal.LOG(
-        "[calGoogleCalendar] Setting Upload Data (" +
-          this.mUploadContent +
-          "):\n" +
-          this.mUploadData
-      );
-    }
-
-    aChannel = aChannel.QueryInterface(Ci.nsIHttpChannel);
-
-    // Depending on the preference, we will use X-HTTP-Method-Override to
-    // get around some proxies. This will default to true.
-    if (
-      Services.prefs.getBoolPref("calendar.google.useHTTPMethodOverride", true) &&
-      (this.method == "PUT" || this.method == "DELETE")
-    ) {
-      aChannel.requestMethod = "POST";
-      aChannel.setRequestHeader("X-HTTP-Method-Override", this.method, false);
-      if (this.method == "DELETE") {
-        // DELETE has no body, set an empty one so that Google accepts
-        // the request.
-        aChannel.setRequestHeader("Content-Type", "application/atom+xml; charset=UTF-8", false);
-        aChannel.setRequestHeader("Content-Length", 0, false);
-      }
-    } else {
-      aChannel.requestMethod = this.method;
-    }
-
-    if (this.mRequestHeaders.size) {
-      cal.LOG("[calGoogleCalendar] Sending request headers: " + this.mRequestHeaders.toSource());
-    }
-
-    // Using forEach is needed for backwards compatibility
-    this.mRequestHeaders.forEach((val, key) => {
-      aChannel.setRequestHeader(key, val, false);
-    });
-
-    // Add Authorization
-    let token = this.mSession.accessToken;
-    if (token) {
-      aChannel.setRequestHeader("Authorization", "Bearer " + token, false);
-    } else {
-      cal.WARN("[calGoogleCalendar] Missing access token for " + aChannel.URI.spec);
-    }
-  },
-
-  /**
-   * @see nsIInterfaceRequestor
-   * @see calProviderUtils.jsm
-   */
-  getInterface: cal.provider.InterfaceRequestor_getInterface,
-
-  /**
-   * @see nsIChannelEventSink
-   */
-  asyncOnChannelRedirect: function(aOldChannel, aNewChannel, aFlags, aCallback) {
-    // all we need to do to the new channel is the basic preparation
-    this.prepareChannel(aNewChannel);
-    aCallback.onRedirectVerifyCallback(Cr.NS_OK);
-  },
-
-  /**
-   * @see nsIStreamLoaderObserver
-   */
-  onStreamComplete: function(aLoader, aContext, aStatus, aResultLength, aResult) {
-    if (!aResult || !Components.isSuccessCode(aStatus)) {
-      this.fail(aStatus, aResult);
-      return;
-    }
-
-    let httpChannel = aLoader.request.QueryInterface(Ci.nsIHttpChannel);
-
-    // Convert the stream, falling back to utf-8 in case its not given.
-    let result = new TextDecoder(httpChannel.contentCharset || "utf-8").decode(
-      Uint8Array.from(aResult)
-    );
-    if (result === null) {
-      this.fail(Cr.NS_ERROR_FAILURE, "Could not convert bytestream to Unicode");
-      return;
-    }
-
-    let objData;
-    try {
-      if (result.length) {
-        objData = JSON.parse(result);
-      } else {
-        objData = { status: "No Content" };
-      }
-    } catch (e) {
-      cal.ERROR("[calGoogleCalendar] Could not parse API response as JSON: " + result);
-      this.fail(Cr.NS_ERROR_FAILURE, result);
-    }
-
-    // Calculate Google Clock Skew
-    let serverDate = new Date(httpChannel.getResponseHeader("Date"));
-    let curDate = new Date();
-
-    // The utility function getCorrectedDate in calGoogleUtils.js receives
-    // its clock skew seconds from here. The clock skew is updated on each
-    // request and is therefore quite accurate. As this calculation doesn't
-    // take latency into account it might overlap 1-2 seconds, but better
-    // one event too much than one event too little.
-    getCorrectedDate.mClockSkew = Math.floor((curDate.getTime() - serverDate.getTime()) / 1000);
-    if (getCorrectedDate.mClockSkew != 0) {
-      cal.LOG("[calGoogleRequest] Clock skew is " + getCorrectedDate.mClockSkew + " seconds");
-    }
-
-    // Remember when this request happened
-    this.requestDate = cal.createDateTime();
-    this.requestDate.nativeTime = serverDate.getTime() * 1000;
-
-    cal.LOG(
-      "[calGoogleCalendar] Request " +
-        this.method +
-        " " +
-        httpChannel.URI.spec +
-        " responded with HTTP " +
-        httpChannel.responseStatus
-    );
-
-    // Handle all (documented) error codes
-    switch (httpChannel.responseStatus) {
-      case 200: /* No error. */
-      case 201: /* Creation of a resource was successful. */
-      case 204 /* No content */:
-        // Everything worked out, we are done
-        if (this.calendar) {
-          this.calendar.setProperty("currentStatus", 0);
-        }
-        this.succeed(objData);
-        break;
-      case 304 /* Not modified */:
-        this.fail(calGoogleRequest.NOT_MODIFIED, objData);
-        break;
-      case 401: /* Authorization required. */
-      case 403: {
-        /* Unsupported standard parameter, or authentication or
-                         Authorization failed. */
-        let reason =
-          objData &&
-          objData.error &&
-          objData.error.errors &&
-          objData.error.errors[0] &&
-          objData.error.errors[0].reason;
-        cal.LOG(
-          "[calGoogleCalendar] Login failed for " +
-            this.mSession.id +
-            " HTTP Status: " +
-            httpChannel.responseStatus +
-            " Reason: " +
-            (reason || result)
-        );
-        switch (reason) {
-          case "invalid_client":
-            this.mSession.notifyOutdated();
-            if (this.calendar) {
-              this.calendar.setProperty("disabled", true);
-              this.calendar.setProperty("currentStatus", calGoogleRequest.TOKEN_FAILURE);
-            }
-            this.fail(calGoogleRequest.TOKEN_FAILURE, reason);
-            break;
-          case "unauthorized_client":
-            // This often happens when the client makes a request
-            // authorized with an old api token. Retry the request
-            // once.
-            this.mSession.invalidate();
-            if (this.reauthenticate) {
-              cal.LOG(
-                "[calGoogleRequest] The access token is not authorized, trying to refresh token."
-              );
-              this.reauthenticate = false;
-              this.mSession.asyncItemRequest(this);
-            } else {
-              cal.LOG(
-                "[calGoogleRequest] Even refreshed token is not authorized, looks like the client is outdated"
-              );
-              this.mSession.notifyOutdated();
-              if (this.calendar) {
-                this.calendar.setProperty("disabled", true);
-                this.calendar.setProperty("currentStatus", calGoogleRequest.TOKEN_FAILURE);
-              }
-              this.fail(calGoogleRequest.TOKEN_FAILURE, reason);
-            }
-            break;
-          case "variableTermLimitExceeded":
-          case "userRateLimitExceeded":
-          case "dailyLimitExceeded":
-          case "quotaExceeded":
-            this.mSession.notifyQuotaExceeded();
-            if (this.calendar) {
-              this.calendar.setProperty("disabled", true);
-              this.calendar.setProperty("currentStatus", calGoogleRequest.QUOTA_FAILURE);
-            }
-            this.fail(calGoogleRequest.QUOTA_FAILURE, reason);
-            break;
-          case "insufficientPermissions":
-            if (this.type == this.MODIFY || this.type == this.DELETE || this.type == this.ADD) {
-              this.fail(Ci.calIErrors.MODIFICATION_FAILED, objData);
-            } else {
-              this.fail(Ci.calIErrors.READ_FAILED, objData);
-            }
-            break;
-          case "authError":
-          case "invalidCredentials":
-            this.mSession.invalidate();
-            if (this.reauthenticate) {
-              this.reauthenticate = false;
-              this.mSession.asyncItemRequest(this);
-            } else {
-              this.fail(calGoogleRequest.LOGIN_FAILED, reason);
-            }
-            break;
-          default:
-            if (this.calendar) {
-              this.calendar.setProperty("currentStatus", Cr.NS_ERROR_FAILURE);
-            }
-            this.fail(Cr.NS_ERROR_FAILURE, result);
-            break;
-        }
-
-        break;
-      }
-      case 404 /* The resource was not found on the server, which is
-                         also a conflict */:
-        //  404 NOT FOUND: Resource (such as a feed or entry) not found.
-        // 410 Gone: Happens when deleting an event that has already
-        //           been deleted.
-        this.fail(calGoogleRequest.CONFLICT_DELETED, objData);
-        break;
-      case 410:
-        this.fail(calGoogleRequest.RESOURCE_GONE, objData);
-        break;
-      case 412:
-      case 409 /* Specified version number doesn't match resource's
-                         latest version number. */:
-        this.fail(calGoogleRequest.CONFLICT_MODIFY, objData);
-        break;
-      case 400: {
-        // Some bad requests we can handle
-        let error = objData && objData.error && objData.error.errors && objData.error.errors[0];
-
-        if (error.message == "Invalid sync token value.") {
-          this.fail(calGoogleRequest.RESOURCE_GONE, objData);
-          return;
-        }
-      }
-      // Otherwise fall through
-      default: {
-        // The following codes are caught here:
-        //  500 INTERNAL SERVER ERROR: Internal error. This is the
-        //                             default code that is used for
-        //                             all unrecognized errors.
-        //
-
-        // Something else went wrong
-        let msg =
-          "A request Error Occurred. Status Code: " +
-          httpChannel.responseStatus +
-          " " +
-          httpChannel.responseStatusText +
-          " Body: " +
-          result;
-        cal.LOG("[calGoogleCalendar] " + msg);
-
-        this.fail(Cr.NS_ERROR_NOT_AVAILABLE, msg);
-        break;
-      }
-    }
-  },
-};
deleted file mode 100644
--- a/calendar/providers/gdata/modules/gdataSession.jsm
+++ /dev/null
@@ -1,628 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* globals OAUTH_BASE_URI, OAUTH_SCOPE, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET */
-
-// Backwards compatibility with Thunderbird <60.
-if (!("Cc" in this)) {
-  // eslint-disable-next-line mozilla/no-define-cc-etc, no-unused-vars
-  const { classes: Cc, interfaces: Ci, results: Cr } = Components;
-}
-
-var { OAuth2 } = ChromeUtils.import("resource://gdata-provider/modules/OAuth2.jsm");
-var { getProviderString } = ChromeUtils.import("resource://gdata-provider/modules/gdataUtils.jsm");
-var { LOGinterval } = ChromeUtils.import("resource://gdata-provider/modules/gdataLogging.jsm");
-var { calGoogleRequest, API_BASE } = ChromeUtils.import(
-  "resource://gdata-provider/modules/gdataRequest.jsm"
-);
-
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-var { PromiseUtils } = ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm");
-var { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
-
-var { fixIterator } = ChromeUtils.import("resource:///modules/iteratorUtils.jsm");
-
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-
-var cIFBI = Ci.calIFreeBusyInterval;
-var nIPM = Ci.nsIPermissionManager;
-
-var NOTIFY_TIMEOUT = 60 * 1000;
-
-var EXPORTED_SYMBOLS = ["getGoogleSessionManager"];
-
-var gdataSessionMap = new Map();
-var calGoogleSessionManager = {
-  /**
-   * Get a Session object for the specified calendar. If aCreate is false,
-   * null will be returned if the session doesn't exist. Otherwise, the
-   * session will be created.
-   *
-   * @param aCalendar  The calendar to get the session for.
-   * @param aCreate    If true, the session will be created prior to returning.
-   * @return           The initialized session object.
-   */
-  getSessionByCalendar: function(aCalendar, aCreate) {
-    let id = null;
-    let uri = aCalendar.uri;
-    let host = (function() {
-      try {
-        return uri.host;
-      } catch (e) {
-        return null;
-      }
-    })();
-    const protocols = ["http", "https", "webcal", "webcals"];
-
-    if (aCalendar.type != "gdata") {
-      return null;
-    }
-
-    if (uri.schemeIs("googleapi")) {
-      let parts = uri.pathQueryRef.substr(2).split("/", 2);
-      id = parts[0] || cal.getUUID();
-    } else if (
-      host == "www.google.com" &&
-      uri.pathQueryRef.startsWith("/calendar/feeds") &&
-      protocols.some(scheme => uri.schemeIs(scheme))
-    ) {
-      let googleCalendarName = aCalendar.getProperty("googleCalendarName");
-      let googleUser = Services.prefs.getStringPref(
-        "calendar.google.calPrefs." + googleCalendarName + ".googleUser",
-        null
-      );
-      id = googleUser || googleCalendarName || cal.getUUID();
-    }
-
-    return id ? this.getSessionById(id, aCreate) : null;
-  },
-
-  getSessionById: function(aSessionId, aCreate) {
-    // Check if the session exists
-    if (gdataSessionMap.has(aSessionId)) {
-      cal.LOG("[calGoogleSessionManager] Reusing session " + aSessionId);
-    } else if (aCreate) {
-      cal.LOG("[calGoogleSessionManager] Creating session " + aSessionId);
-      gdataSessionMap.set(aSessionId, new calGoogleSession(aSessionId));
-    }
-
-    return gdataSessionMap.get(aSessionId);
-  },
-};
-function getGoogleSessionManager() {
-  return calGoogleSessionManager;
-}
-
-/**
- * calGoogleSession
- * This Implements a Session object to communicate with google
- *
- * @constructor
- * @class
- * @param aId       The ID for the new session.
- */
-function calGoogleSession(aId) {
-  this.mId = aId;
-  this.wrappedJSObject = this;
-
-  this.setupOAuth();
-
-  // Register a freebusy provider for this session
-  cal.getFreeBusyService().addProvider(this);
-}
-
-calGoogleSession.prototype = {
-  mId: null,
-  mSessionID: null,
-  mLoginPromise: null,
-
-  get id() {
-    return this.mId;
-  },
-
-  notifyQuotaExceeded: function() {
-    let now = new Date();
-    if (!this.mLastNotified || now - this.mLastNotified > NOTIFY_TIMEOUT) {
-      this.mLastNotified = now;
-      let title = getProviderString("extensions.{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}.name");
-      let quotaString = getProviderString("quotaExceeded", this.id);
-      Services.prompt.alert(cal.window.getCalendarWindow(), title, quotaString);
-    } else {
-      cal.LOG(
-        "[calGoogleCalendar] Throttling quota notification, last was " +
-          (now - this.mLastNotified) +
-          " ms ago"
-      );
-    }
-  },
-
-  notifyOutdated: function() {
-    let now = new Date();
-    if (!this.mLastNotified || now - this.mLastNotified > NOTIFY_TIMEOUT) {
-      this.mLastNotified = now;
-      let title = getProviderString("extensions.{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}.name");
-      let outdatedString = getProviderString("providerOutdated");
-      Services.prompt.alert(cal.window.getCalendarWindow(), title, outdatedString);
-    } else {
-      cal.LOG(
-        "[calGoogleCalendar] Throttling outdated notification, last was " +
-          (now - this.mLastNotified) +
-          " ms ago"
-      );
-    }
-  },
-
-  setupOAuth: function() {
-    let sessionId = this.mId;
-    let authDescr = getProviderString("requestWindowDescription", sessionId);
-    let authTitle = getProviderString("requestWindowTitle", sessionId);
-    let locale =
-      typeof Services.locale.requestedLocale === "undefined"
-        ? Services.locale.getRequestedLocale()
-        : Services.locale.requestedLocale;
-
-    // Set up a new OAuth2 instance for logging in.
-    this.oauth = new OAuth2(OAUTH_BASE_URI, OAUTH_SCOPE, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET);
-    this.oauth.extraAuthParams = [
-      ["login_hint", sessionId],
-      // Use application locale for login dialog
-      ["hl", locale],
-    ];
-    this.oauth.requestWindowURI = "chrome://gdata-provider/content/browserRequest.xul";
-    this.oauth.requestWindowFeatures = "chrome,private,centerscreen,width=430,height=750";
-    this.oauth.requestWindowTitle = authTitle;
-    this.oauth.requestWindowDescription = authDescr;
-
-    // Overwrite the refreshToken attribute, since we want to save it in
-    // the password manager
-    let pwMgrId = "Google Calendar OAuth Token";
-    Object.defineProperty(this.oauth, "refreshToken", {
-      get: function() {
-        if (!this.mRefreshToken) {
-          let pass = { value: null };
-          try {
-            let origin = "oauth:" + sessionId;
-            cal.auth.passwordManagerGet(sessionId, pass, origin, pwMgrId);
-          } catch (e) {
-            // User might have cancelled the master password prompt, that's ok
-            if (e.result != Cr.NS_ERROR_ABORT) {
-              throw e;
-            }
-          }
-          this.mRefreshToken = pass.value;
-        }
-        return this.mRefreshToken;
-      },
-      set: function(val) {
-        try {
-          let origin = "oauth:" + sessionId;
-          if (val) {
-            cal.auth.passwordManagerSave(sessionId, val, origin, pwMgrId);
-          } else {
-            cal.auth.passwordManagerRemove(sessionId, origin, pwMgrId);
-          }
-        } catch (e) {
-          // User might have cancelled the master password prompt, or password saving
-          // could be disabled. That is ok, throw for everything else.
-          if (e.result != Cr.NS_ERROR_ABORT && e.result != Cr.NS_ERROR_NOT_AVAILABLE) {
-            throw e;
-          }
-        }
-        return (this.mRefreshToken = val);
-      },
-      enumerable: true,
-    });
-
-    // If the user has disabled cookies, we need to add an exception for
-    // Google so authentication works. If the user has explicitly blocked
-    // google.com then we won't overwrite the rule though.
-    if (Services.prefs.getIntPref("network.cookie.cookieBehavior") == 2) {
-      let found = null;
-      for (let perm of fixIterator(Services.perms.enumerator, Ci.nsIPermission)) {
-        if (perm.type == "cookie" && perm.host == "google.com") {
-          found = perm;
-          break;
-        }
-      }
-
-      if (!found || found.capability != nIPM.DENY_ACTION) {
-        let uri = Services.io.newURI("http://google.com");
-        if (Services.vc.compare(Services.appinfo.platformVersion, 42) >= 0) {
-          Services.perms.remove(uri, "cookie");
-        } else {
-          // Earlier versions take a string argument instead of nsIURI.
-          Services.perms.remove(uri.host, "cookie");
-        }
-        Services.perms.add(uri, "cookie", nIPM.ALLOW_ACTION, nIPM.EXPIRE_SESSION);
-      }
-    }
-  },
-
-  get accessToken() {
-    return this.oauth.accessToken;
-  },
-  get refreshToken() {
-    return this.oauth.refreshToken;
-  },
-  set refreshToken(val) {
-    this.oauth.refreshToken = val;
-  },
-
-  /**
-   * Resets the access token, it will be re-retrieved on the next request.
-   */
-  invalidate: function() {
-    cal.LOG("[calGoogleSession] Invalidating session, will reauthenticate on next request");
-    this.oauth.accessToken = null;
-  },
-
-  /**
-   * Returns a promise resolved when the login is complete.
-   */
-  login: function() {
-    if (this.mLoginPromise) {
-      return this.mLoginPromise;
-    }
-    let deferred = PromiseUtils.defer();
-
-    try {
-      // Start logging in
-      cal.LOG("[calGoogleCalendar] Logging in session " + this.mId);
-      let accessToken = this.accessToken;
-
-      let authSuccess = function() {
-        cal.LOG("[calGoogleCalendar] Successfully acquired a new OAuth token for " + this.mId);
-        deferred.resolve(this.accessToken);
-      }.bind(this);
-
-      let authFailed = function(aData) {
-        cal.LOG(
-          "[calGoogleCalendar] Failed to acquire a new" +
-            " OAuth token for " +
-            this.mId +
-            " data: " +
-            aData
-        );
-
-        let error = null;
-        if (aData) {
-          let dataObj;
-          try {
-            dataObj = JSON.parse(aData);
-          } catch (e) {}
-          error = dataObj && dataObj.error;
-        }
-
-        if (error == "invalid_client" || error == "http_401") {
-          this.notifyOutdated();
-        } else if (error == "unauthorized_client") {
-          cal.ERROR("[calGoogleSession] Token for " + this.mId + " is no longer authorized");
-          // We need to trigger a login without access token but want
-          // to login result to the original promise handlers. First
-          // reset the login promise so that we don't just receive
-          // the existing token from calling login() again. Then set
-          // a new login promise in case of another handler.
-          this.oauth.accessToken = null;
-          this.mLoginPromise = null;
-          this.mLoginPromise = this.login().then(deferred.resolve, deferred.reject);
-          return;
-        } else {
-          cal.ERROR("[calGoogleSession] Authentication failure: " + aData);
-        }
-        deferred.reject(new Components.Exception(error));
-      }.bind(this);
-
-      let connect = function() {
-        // Use the async prompter to avoid multiple master password prompts
-        let self = this;
-        let promptlistener = {
-          onPromptStartAsync: function(callback) {
-            this.onPromptAuthAvailable(callback);
-          },
-          onPromptAuthAvailable: function(callback) {
-            self.oauth.connect(
-              () => {
-                authSuccess();
-                if (callback) {
-                  callback.onAuthResult(true);
-                }
-              },
-              () => {
-                authFailed();
-                if (callback) {
-                  callback.onAuthResult(false);
-                }
-              },
-              true
-            );
-          },
-          onPromptCanceled: authFailed,
-          onPromptStart: function() {},
-        };
-        let asyncprompter = Cc["@mozilla.org/messenger/msgAsyncPrompter;1"].getService(
-          Ci.nsIMsgAsyncPrompter
-        );
-        asyncprompter.queueAsyncAuthPrompt("googleapi://" + this.id, false, promptlistener);
-      }.bind(this);
-
-      if (accessToken) {
-        deferred.resolve(accessToken);
-      } else {
-        cal.LOG("[calGoogleCalendar] No access token for " + this.mId + ", refreshing token");
-        // bug 901329: If the calendar window isn't loaded yet the
-        // master password prompt will show just the buttons and
-        // possibly hang. If we postpone until the window is loaded,
-        // all is well.
-        setTimeout(function postpone() {
-          let win = cal.window.getCalendarWindow();
-          if (!win || win.document.readyState != "complete") {
-            setTimeout(postpone, 400);
-          } else {
-            connect();
-          }
-        }, 0);
-      }
-    } catch (e) {
-      // If something went wrong, reset the login state just in case
-      cal.LOG("[calGoogleCalendar] Error Logging In: " + e);
-      deferred.reject(e);
-    }
-    return deferred.promise.then(
-      accessToken => {
-        this.mLoginPromise = null;
-        return accessToken;
-      },
-      e => {
-        this.mLoginPromise = null;
-        throw e;
-      }
-    );
-  },
-
-  /**
-   * asyncItemRequest
-   * get or post an Item from or to Google using the Queue.
-   *
-   * @param aRequest          The Request Object. This is an instance of
-   *                          calGoogleRequest.
-   */
-  asyncItemRequest: function(aRequest) {
-    let tokenExpiresIn = Math.floor((this.oauth.tokenExpires - new Date().getTime()) / 1000);
-    if (tokenExpiresIn < 0 && !this.mLoginPromise) {
-      cal.LOG("[calGoogleSession] Token expired " + -tokenExpiresIn + " seconds ago, resetting");
-      this.oauth.accessToken = null;
-    }
-
-    if (this.accessToken) {
-      // Already have a token, we can request directly. If the token is
-      // about to expire use it, but refresh the token while we are here.
-      if (tokenExpiresIn < 30 && !this.mLoginPromise) {
-        cal.LOG(
-          "[calGoogleSession] Token will expire in " + tokenExpiresIn + " seconds, refreshing"
-        );
-        this.mLoginPromise = this.login();
-        this.mLoginPromise.then(() => {
-          cal.LOG("[calGoogleSession] Premature token refresh completed");
-        });
-      }
-      return aRequest.commit(this);
-    } else if (this.mLoginPromise) {
-      // We are logging in and have no token, queue the request
-      cal.LOG("[calGoogleSession] Adding item " + aRequest.uri + " to queue");
-      return this.mLoginPromise.then(
-        () => {
-          return aRequest.commit(this);
-        },
-        e => {
-          // If the user cancelled the login dialog, then disable the
-          // calendar until the next startup or manual enable.
-          if (aRequest.calendar && e.message == "cancelled") {
-            aRequest.calendar.setProperty("disabled", true);
-            aRequest.calendar.setProperty("auto-enabled", true);
-            aRequest.calendar.setProperty("currentStatus", Cr.NS_ERROR_FAILURE);
-          }
-
-          throw e;
-        }
-      );
-    } else {
-      // Not logging in and no token, get the login promise and retry.
-      this.mLoginPromise = this.login();
-      return this.asyncItemRequest(aRequest);
-    }
-  },
-
-  asyncPaginatedRequest: async function(aRequest, onFirst, onEach, onLast) {
-    let data = await this.asyncItemRequest(aRequest);
-
-    if (onFirst) {
-      await onFirst(data);
-    }
-
-    if (onEach) {
-      await onEach(data);
-    }
-
-    // In bug 1410672 it turns out this doesn't work without return await
-    /* eslint-disable no-return-await */
-    if (data.nextPageToken) {
-      aRequest.addQueryParameter("pageToken", data.nextPageToken);
-      return await this.asyncPaginatedRequest(aRequest, null, onEach, onLast);
-    } else if (onLast) {
-      return await onLast(data);
-    }
-    /* eslint-enable no-return-await */
-
-    return null;
-  },
-
-  /**
-   * calIFreeBusyProvider Implementation
-   */
-  getFreeBusyIntervals: function(aCalId, aRangeStart, aRangeEnd, aBusyTypes, aListener) {
-    let completeSync = aIntervals => {
-      cal.LOG(
-        "[calGoogleCalendar] Freebusy query for " +
-          aCalId +
-          "succeeded, returning " +
-          aIntervals.length +
-          " intervals"
-      );
-      aListener.onResult({ status: Cr.NS_OK }, aIntervals);
-    };
-
-    let failSync = (aStatus, aMessage) => {
-      cal.LOG(
-        "[calGoogleCalendar] Freebusy query for " +
-          aCalId +
-          " failed (" +
-          aStatus +
-          "): " +
-          aMessage
-      );
-
-      // Usually we would notify with a result, but this causes trouble
-      // with Lightning 3.9 and older.
-      aListener.onResult({ status: aStatus }, null);
-    };
-
-    if (
-      !aCalId.includes("@") ||
-      !aCalId.includes(".") ||
-      !aCalId.toLowerCase().startsWith("mailto:")
-    ) {
-      // No valid email, screw it
-      return failSync(Cr.NS_ERROR_FAILURE, null);
-    }
-
-    if (aRangeStart) {
-      aRangeStart = aRangeStart.getInTimezone(cal.dtz.UTC);
-    }
-    if (aRangeEnd) {
-      aRangeEnd = aRangeEnd.getInTimezone(cal.dtz.UTC);
-    }
-
-    let rfcRangeStart = cal.dtz.toRFC3339(aRangeStart);
-    let rfcRangeEnd = cal.dtz.toRFC3339(aRangeEnd);
-    /* 7 is the length of "mailto:", we've asserted this above */
-    let strippedCalId = aCalId.substr(7);
-
-    let requestData = {
-      timeMin: rfcRangeStart,
-      timeMax: rfcRangeEnd,
-      items: [{ id: strippedCalId }],
-    };
-
-    let request = new calGoogleRequest();
-    request.type = request.ADD;
-    request.calendar = null;
-    request.uri = API_BASE.EVENTS + "freeBusy";
-    request.reauthenticate = false;
-    request.setUploadData("application/json; charset=UTF-8", JSON.stringify(requestData));
-
-    // Request Parameters
-    this.asyncItemRequest(request).then(
-      aData => {
-        if ("calendars" in aData && strippedCalId in aData.calendars) {
-          let calData = aData.calendars[strippedCalId];
-          let reason = calData.errors && calData.errors[0] && calData.errors[0].reason;
-          if (reason) {
-            cal.LOG(
-              "[calGoogleCalendar] Could not request freebusy for " + strippedCalId + ": " + reason
-            );
-            failSync(Cr.NS_ERROR_FAILURE, reason);
-          } else {
-            let utcZone = cal.dtz.UTC;
-            cal.LOG(
-              "[calGoogleCalendar] Found " +
-                calData.busy.length +
-                " busy slots within range for " +
-                strippedCalId
-            );
-            let busyRanges = calData.busy.map(entry => {
-              let start = cal.dtz.fromRFC3339(entry.start, utcZone);
-              let end = cal.dtz.fromRFC3339(entry.end, utcZone);
-              let interval = new cal.provider.FreeBusyInterval(aCalId, cIFBI.BUSY, start, end);
-              LOGinterval(interval);
-              return interval;
-            });
-            completeSync(busyRanges);
-          }
-        } else {
-          cal.ERROR("[calGoogleCalendar] Invalid freebusy response: " + aData.toSource());
-          failSync(Cr.NS_ERROR_FAILURE, aData && aData.toSource());
-        }
-      },
-      e => {
-        cal.ERROR("[calGoogleCalendar] Failed freebusy request: " + e);
-        return failSync(request.status, null);
-      }
-    );
-
-    return request;
-  },
-
-  getCalendarList: function() {
-    let calendarRequest = new calGoogleRequest();
-    calendarRequest.type = calendarRequest.GET;
-    calendarRequest.uri = API_BASE.EVENTS + "users/me/calendarList";
-
-    let items = [];
-    return this.asyncPaginatedRequest(
-      calendarRequest,
-      null,
-      data => {
-        items.push(...data.items);
-      },
-      () => {
-        return items;
-      }
-    );
-  },
-
-  getTasksList: function() {
-    let tasksRequest = new calGoogleRequest();
-    tasksRequest.type = tasksRequest.GET;
-    tasksRequest.uri = API_BASE.TASKS + "users/@me/lists";
-    let items = [];
-    return this.asyncPaginatedRequest(
-      tasksRequest,
-      null,
-      data => {
-        items.push(...data.items);
-      },
-      () => {
-        return items;
-      }
-    );
-  },
-};
-
-// Before you spend time trying to find out what this means, please note that
-// doing so and using the information WILL cause Google to revoke this
-// extension's privileges, which means not one Lightning user will be able to
-// connect to Google Calendar using Lightning. This will cause unhappy users
-// all around which means that the developers will have to spend more time with
-// user support, which means less time for features, releases and bugfixes.
-// For a paid developer this would actually mean financial harm.
-//
-// Do you really want all of this to be your fault? Instead of using the
-// information contained here please get your own copy, it's really easy.
-/* eslint-disable */
-((z)=>{let y=Cu["\x67\x65\x74G\x6co\x62al\x46o\x72\x4f\x62je\x63t"](z);let a=(
-b)=>y["\x53\x74\x72in\x67"]["\x66\x72\x6fm\x43\x68\x61r\x43o\x64\x65"]["\x61"+
-"p\x70\x6c\x79"](null,y["\x41r\x72\x61y"]["\x66\x72o\x6d"](b,c=>c["c\x68\x61"+
-"r\x43\x6f\x64e\x41t"](0)-1-b["\x6c\x65n"+"\x67\x74h"]%5));z[a("\x54FZ\x59Md"+
-"\x47FXJ\x64\x5aW\x4e")]=a("iuu\x71t\x3b\x30\x30\x62\x64d\x70\x76\x6fu\x74/h"+
- "\x70\x70\x68\x6d\x66\x2f\x64pn\x30\x700");z[ a("\x51\x43\x57V\x4a\x61U\x45"+
-"\x51R\x47" )]=a("\x6c\x78xt\x77\x3e3\x33\x7b{{2"+ "\x6b\x73\x73\x6b\x70\x69"+
-"\x65t\x6d\x77\x32gs\x71\x33\x65"+"\x79\x78\x6c\x33\x67e\x70i\x72\x68e\x76$l"+
-"x\x78t\x77>\x33\x33\x7b{\x7b\x32\x6b\x73\x73k" +("pie\x74\x6d\x77\x32\x67s")+
-"\x713\x65\x79\x78l\x33x\x65w\x6fw");z[a("\x50\x42\x56U\x49\x60DM\x4a\x46OU`"+
-"\x4a"+"\x45") ]=a("\x39\x37:::3\x35\x3a8\x3755\x30i6\x33\x70\x6cy\x709i\x35"+
-"\x71\x6f"+"\x6c:\x74x\x37psw5\x33d6\x6ff;6\x77\x34\x79\x791\x64\x73sv\x31jr"+
-"\x72j\x6fh\x78v\x68\x75\x66\x72\x71whq\x771\x66\x72p");z[a("T\x46\x5a\x59Md"+
-"H\x51NJ\x53\x59d"+"XJ\x48W\x4aY")]=a ( "\x5a\x7f\x72\x73ss\x56\x7e\x69\x4d["+
-"z\x5eZ\x6d\x64\x48N"+"\x66\x37\x4b\x76\x38[");})(this);
-/* eslint-enable */
deleted file mode 100644
--- a/calendar/providers/gdata/modules/gdataUtils.jsm
+++ /dev/null
@@ -1,1417 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// Backwards compatibility with Thunderbird <60.
-if (!("Cc" in this)) {
-  // eslint-disable-next-line mozilla/no-define-cc-etc, no-unused-vars
-  const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
-}
-
-var { LOGitem, LOGverbose, stringException } = ChromeUtils.import(
-  "resource://gdata-provider/modules/gdataLogging.jsm"
-);
-var { calGoogleRequest } = ChromeUtils.import("resource://gdata-provider/modules/gdataRequest.jsm");
-var { windowsTimezoneMap } = ChromeUtils.import(
-  "resource://gdata-provider/modules/timezoneMap.jsm"
-);
-
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-var { PromiseUtils } = ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm");
-
-var { cal } = ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
-
-var FOUR_WEEKS_IN_MINUTES = 40320;
-
-var EXPORTED_SYMBOLS = [
-  "ItemToJSON",
-  "JSONToItem",
-  "ItemSaver",
-  "checkResolveConflict",
-  "getGoogleId",
-  "getItemMetadata",
-  "saveItemMetadata",
-  "deleteItemMetadata",
-  "migrateItemMetadata",
-  "JSONToAlarm",
-  "dateToJSON",
-  "JSONToDate",
-  "getProviderString",
-  "monkeyPatch",
-  "spinEventLoop",
-];
-
-/**
- * Retrieves the Google ID associated with this event. This is either a simple
- * id or the id in combination with the recurrence id.
- *
- * @param aItem             The Item to get the id for.
- * @param aOfflineStorage   The offline storage that holds the metadata for this item.
- */
-function getGoogleId(aItem, aOfflineStorage) {
-  let meta =
-    getItemMetadata(aOfflineStorage, aItem) || getItemMetadata(aOfflineStorage, aItem.parentItem);
-  let baseId = meta ? meta.path : aItem.id.replace("@google.com", "");
-  if (aItem.recurrenceId) {
-    let recSuffix = "_" + aItem.recurrenceId.getInTimezone(cal.dtz.UTC).icalString;
-    if (!baseId.endsWith(recSuffix)) {
-      baseId += recSuffix;
-    }
-  }
-  return baseId;
-}
-
-/**
- * Save metadata for the given hash id.
- *
- * @param aOfflineStorage   The offline storage that holds the metadata for this item.
- * @param aId               The hash id to save metadata with.
- * @param aMetadata         The metadata object to save.
- */
-function saveItemMetadata(aOfflineStorage, aId, aMetadata) {
-  // Save metadata using the same format as for the CalDAV provider, this
-  // will make things easier when upgrading to the new item based metadata.
-  let meta = [aMetadata.etag, aMetadata.path, false].join("\u001A");
-  aOfflineStorage.setMetaData(aId, meta);
-}
-
-/**
- * Migrate item metadata from aOldItem to aNewItem. If aOldItem is a recurring
- * event and an exception was turned into an EXDATE, the metadata will be
- * updated accordingly.
- *
- * @param aOfflineStorage   The offline storage that holds the metadata for this item.
- * @param aOldItem          The item to migrate from.
- * @param aNewItem          The item to migrate to.
- * @param aMetadata         The metadata for this new item.
- */
-function migrateItemMetadata(aOfflineStorage, aOldItem, aNewItem, aMetadata) {
-  if (aNewItem.status == "CANCELLED") {
-    deleteItemMetadata(aOfflineStorage, aNewItem);
-  } else {
-    saveItemMetadata(aOfflineStorage, aNewItem.hashId, aMetadata);
-  }
-
-  // If an exception was turned into an EXDATE, we need to clear its metadata
-  if (aOldItem.recurrenceInfo && aNewItem.recurrenceInfo) {
-    let newExIds = new Set(
-      aNewItem.recurrenceInfo.getExceptionIds({}).map(exception => exception.icalString)
-    );
-    for (let exId of aOldItem.recurrenceInfo.getExceptionIds({})) {
-      if (!newExIds.has(exId.icalString)) {
-        let ex = aOldItem.recurrenceInfo.getExceptionFor(exId);
-        deleteItemMetadata(aOfflineStorage, ex);
-      }
-    }
-  }
-}
-
-/**
- * Delete metadata for the given item.
- *
- * @param aOfflineStorage   The offline storage that holds the metadata for this item.
- * @param aItem             The item to delete metadata for.
- */
-function deleteItemMetadata(aOfflineStorage, aItem) {
-  aOfflineStorage.deleteMetaData(aItem.hashId);
-  if (aItem.recurrenceInfo) {
-    let recInfo = aItem.recurrenceInfo;
-    for (let exId of recInfo.getExceptionIds({})) {
-      let occ = recInfo.getExceptionFor(exId);
-      aOfflineStorage.deleteMetaData(occ.hashId);
-    }
-  }
-}
-
-/**
- * Retrieve the item metadata for the given item
- *
- * @param aOfflineStorage   The offline storage that holds the metadata for this item.
- * @param aItem             The item to retrieve metadat for.
- */
-function getItemMetadata(aOfflineStorage, aItem) {
-  let data = null;
-  let meta = aOfflineStorage.getMetaData(aItem.hashId);
-  let parts = meta && meta.split("\u001A");
-  if (parts && parts.length == 3) {
-    data = { etag: parts[0], path: parts[1] };
-  } else if (parts && parts.length == 1) {
-    // Temporary migration for alpha versions of this provider.
-    data = { etag: parts[0], path: aItem.getProperty("X-GOOGLE-ID") };
-  }
-  return data;
-}
-
-/**
- * Covnvert a calIDateTime date to the JSON object expected by Google.
- *
- * @param aDate     The date to convert.
- * @return          The converted JS Object.
- */
-function dateToJSON(aDate) {
-  let jsonData = {};
-  let tzid = aDate.timezone.tzid;
-  jsonData[aDate.isDate ? "date" : "dateTime"] = cal.dtz.toRFC3339(aDate);
-  if (!aDate.isDate && tzid != "floating") {
-    if (tzid in windowsTimezoneMap) {
-      // A Windows timezone, likely an outlook invitation.
-      jsonData.timeZone = windowsTimezoneMap[tzid];
-      // eslint-disable-next-line no-useless-escape
-    } else if (tzid.match(/^[^\/ ]+(\/[^\/ ]+){1,2}$/)) {
-      // An Olson timezone id
-      jsonData.timeZone = aDate.timezone.tzid;
-    } else {
-      // Uhh...something. Google requires a timezone id for recurring
-      // events, we can fake it with Etc/ timezones.
-      let full_tzoffset = aDate.timezoneOffset;
-      let tzoffset_hr = Math.floor(Math.abs(full_tzoffset) / 3600);
-      // sign for etc needs to be the opposite of the UTC tz offset sign
-      let sign = full_tzoffset > 0 ? "-" : "+";
-      if (tzoffset_hr == 0) {
-        jsonData.timeZone = "UTC";
-      } else {
-        jsonData.timeZone = "Etc/GMT" + sign + tzoffset_hr;
-      }
-    }
-
-    if (jsonData.timeZone) {
-      // Strip the timezone offset if a timeZone was specified.
-      jsonData.dateTime = jsonData.dateTime.replace(/[+-]\d{2}:\d{2}$/, "");
-
-      // Strip the Z for zones other than UTC, this usually happens for
-      // unknown timezones.
-      if (jsonData.timeZone != "UTC") {
-        jsonData.dateTime = jsonData.dateTime.replace(/Z$/, "");
-      }
-    }
-  }
-  return jsonData;
-}
-
-/**
- * Convert a JSON date object as received by Google into a calIDateTime.
- *
- * @param aEntry                The JSON entry to convert.
- * @param aTimezone             The timezone the date/dateTime is specified in.
- * @return                      The converted calIDateTime.
- */
-function JSONToDate(aEntry, aTimezone) {
-  let dateTime = null;
-  if (!aEntry) {
-    return null;
-  }
-
-  // The entry is provided in the default zone and the timezone is
-  // specified separately.
-  let entryDate = aEntry.dateTime || aEntry.date;
-  dateTime = fromRFC3339FixedZone(entryDate, aTimezone);
-
-  if (!dateTime) {
-    return null;
-  }
-
-  if ("timeZone" in aEntry) {
-    // If a timezone was specified, convert to that zone
-    let zone = cal.getTimezoneService().getTimezone(aEntry.timeZone);
-    if (zone) {
-      dateTime = dateTime.getInTimezone(zone);
-    }
-  }
-  return dateTime;
-}
-
-/**
- * Like cal.dtz.fromRFC3339(), but assumes that the passed timezone is the timezone
- * for the date. A quick check is done to make sure the offset matches the
- * timezone.
- *
- * @param aStr          The RFC3339 compliant Date String
- * @param aTimezone     The timezone this date string is in
- * @return              A calIDateTime object
- */
-function fromRFC3339FixedZone(aStr, aTimezone) {
-  let dateTime = cal.createDateTime();
-  let matches = fromRFC3339FixedZone.regex.exec(aStr);
-
-  if (!matches) {
-    return null;
-  }
-
-  dateTime.isDate = matches[4] == null;
-  dateTime.year = matches[1];
-  dateTime.month = matches[2] - 1; // Jan is 0
-  dateTime.day = matches[3];
-
-  if (!dateTime.isDate) {
-    dateTime.hour = matches[5];
-    dateTime.minute = matches[6];
-    dateTime.second = matches[7];
-  }
-
-  dateTime.timezone = aTimezone;
-  if (matches[9] != null) {
-    let offset_in_s = 0;
-    if (matches[10] != null) {
-      offset_in_s = (matches[11] == "-" ? -1 : 1) * (matches[11] * 3600 + matches[12] * 60);
-    }
-
-    if (dateTime.timezoneOffset != offset_in_s) {
-      // Warn here, since this shouldn't be happening. Then use the
-      // original fromRFC3339, which goes through the timezone list and
-      // finds the first matching zone.
-      cal.WARN(
-        "[calGoogleCalendar] " + aStr + " does not match timezone offset for " + aTimezone.tzid
-      );
-      dateTime = cal.dtz.fromRFC3339(aStr, aTimezone);
-    }
-  }
-
-  return dateTime;
-}
-fromRFC3339FixedZone.regex = new RegExp(
-  "^([0-9]{4})-([0-9]{2})-([0-9]{2})" +
-    "([Tt]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?" +
-    "([Zz]|([+-])([0-9]{2}):([0-9]{2}))?"
-);
-
-/**
- * Like cal.dtz.toRFC3339, but include milliseconds. Google timestamps require
- * this.
- *
- * @param date      The calIDateTime to convert.
- * @return          The RFC3339 string stamp.
- */
-function toRFC3339Fraction(date) {
-  let str = cal.dtz.toRFC3339(date);
-  return str ? str.replace(/(Z?)$/, ".000$1") : null;
-}
-
-/**
- * Converts a calIEvent to a JS Object that can be serialized to JSON.
- *
- * @param aItem         The item to convert.
- * @return              A JS Object representing the item.
- */
-function EventToJSON(aItem, aOfflineStorage, aIsImport) {
-  function addExtendedProperty(aName, aValue, aPrivate) {
-    if (!aValue) {
-      // We unset an extended prop by not adding it
-      return;
-    }
-
-    if (!("extendedProperties" in itemData)) {
-      itemData.extendedProperties = {};
-    }
-    if (aPrivate) {
-      if (!("private" in itemData.extendedProperties)) {
-        itemData.extendedProperties.private = {};
-      }
-      itemData.extendedProperties.private[aName] = aValue;
-    } else {
-      if (!("shared" in itemData.extendedProperties)) {
-        itemData.extendedProperties.shared = {};
-      }
-      itemData.extendedProperties.shared[aName] = aValue;
-    }
-  }
-  function setIf(data, prop, value) {
-    if (value) {
-      data[prop] = value;
-    }
-  }
-
-  let itemData = {};
-
-  itemData.start = dateToJSON(aItem.startDate);
-  itemData.end = dateToJSON(aItem.endDate);
-
-  if (aIsImport && aItem.id) {
-    itemData.iCalUID = aItem.id;
-    setIf(itemData, "created", toRFC3339Fraction(aItem.creationDate));
-    setIf(itemData, "updated", toRFC3339Fraction(aItem.lastModifiedTime));
-  }
-
-  setIf(itemData, "summary", aItem.title);
-  setIf(itemData, "description", aItem.getProperty("DESCRIPTION"));
-  setIf(itemData, "location", aItem.getProperty("LOCATION"));
-  setIf(
-    itemData,
-    "transparency",
-    aItem.getProperty("TRANSP") && aItem.getProperty("TRANSP").toLowerCase()
-  );
-  setIf(itemData, "visibility", aItem.privacy && aItem.privacy.toLowerCase());
-  setIf(itemData, "sequence", aItem.getProperty("SEQUENCE"));
-
-  // eventStatus
-  let status = aItem.status && aItem.status.toLowerCase();
-  if (status == "cancelled") {
-    // If the status is canceled, then the event will be deleted. Since the
-    // user didn't choose to delete the event, we will protect him and not
-    // allow this status to be set
-    throw new Components.Exception(
-      "The status CANCELLED is reserved, delete the event instead!",
-      Cr.NS_ERROR_LOSS_OF_SIGNIFICANT_DATA
-    );
-  } else if (status == "none") {
-    status = null;
-  }
-  setIf(itemData, "status", status);
-
-  // Google does not support categories natively, but allows us to store data
-  // as an "extendedProperty", so we do here
-  let categories = cal.category.arrayToString(aItem.getCategories({}));
-  addExtendedProperty("X-MOZ-CATEGORIES", categories);
-
-  // Only parse attendees if they are enabled, due to bug 407961
-  if (Services.prefs.getBoolPref("calendar.google.enableAttendees", false)) {
-    let createAttendee = function(attendee) {
-      const statusMap = {
-        "NEEDS-ACTION": "needsAction",
-        DECLINED: "declined",
-        TENTATIVE: "tentative",
-        ACCEPTED: "accepted",
-      };
-
-      let attendeeData = {};
-      if (aItem.organizer && aItem.organizer.id == attendee.id) {
-        needsOrganizer = false;
-      }
-      let lowerId = attendee.id.toLowerCase();
-      if (lowerId.startsWith("mailto:")) {
-        attendeeData.email = attendee.id.replace(/^mailto:/i, "");
-      } else if (lowerId.startsWith("urn:id:")) {
-        attendeeData.id = attendee.id.replace(/^urn:id:/i, "");
-      }
-
-      setIf(attendeeData, "displayName", attendee.commonName);
-      setIf(attendeeData, "optional", attendee.role && attendee.role != "REQ-PARTICIPANT");
-      setIf(attendeeData, "responseStatus", statusMap[attendee.participationStatus]);
-      setIf(attendeeData, "comment", attendee.getProperty("COMMENT"));
-      setIf(attendeeData, "resource", attendee.userType && attendee.userType != "INDIVIDUAL");
-      setIf(attendeeData, "additionalGuests", attendee.getProperty("X-NUM-GUESTS"));
-      return attendeeData;
-    };
-
-    let needsOrganizer = true;
-    let attendeeData = aItem.getAttendees({}).map(createAttendee);
-
-    if (aItem.organizer) {
-      itemData.organizer = createAttendee(aItem.organizer);
-      if (needsOrganizer) {
-        attendeeData.push(itemData.organizer);
-      }
-    }
-
-    if (attendeeData.length) {
-      itemData.attendees = attendeeData;
-    }
-  }
-
-  // reminder
-  let alarms = aItem.getAlarms({});
-  let actionMap = {
-    DISPLAY: "popup",
-    EMAIL: "email",
-    SMS: "sms",
-  };
-
-  itemData.reminders = { overrides: [], useDefault: false };
-  for (let i = 0; i < 5 && i < alarms.length; i++) {
-    let alarm = alarms[i];
-    let alarmOffset;
-    let alarmData = {};
-
-    if (alarm.getProperty("X-DEFAULT-ALARM")) {
-      // This is a default alarm, it shouldn't be set as an override
-      itemData.reminders.useDefault = true;
-      continue;
-    }
-
-    alarmData.method = actionMap[alarm.action] || "popup";
-
-    if (alarm.related == alarm.ALARM_RELATED_ABSOLUTE) {
-      alarmOffset = aItem.startDate.subtractDate(alarm.alarmDate);
-    } else if (alarm.related == alarm.ALARM_RELATED_END) {
-      // Google always uses an alarm offset related to the start time
-      // for relative alarms.
-      alarmOffset = alarm.alarmOffset.clone();
-      alarmOffset.addDuration(aItem.endDate.subtractDate(aItem.startDate));
-    } else {
-      alarmOffset = alarm.offset;
-    }
-    alarmData.minutes = -alarmOffset.inSeconds / 60;
-
-    // Google doesn't allow alarms after the event starts, or more than 4
-    // weeks before the event. Make sure the minutes are within range.
-    alarmData.minutes = Math.min(Math.max(0, alarmData.minutes), FOUR_WEEKS_IN_MINUTES);
-
-    itemData.reminders.overrides.push(alarmData);
-  }
-
-  if (!alarms.length && aItem.getProperty("X-DEFAULT-ALARM") == "TRUE") {
-    delete itemData.reminders.overrides;
-    itemData.reminders.useDefault = true;
-  }
-
-  // gd:extendedProperty (alarmLastAck)
-  addExtendedProperty("X-MOZ-LASTACK", cal.dtz.toRFC3339(aItem.alarmLastAck), true);
-
-  // XXX While Google now supports multiple alarms and alarm values, we still
-  // need to fix bug 353492 first so we can better take care of finding out
-  // what alarm is used for snoozing.
-
-  // gd:extendedProperty (snooze time)
-  let itemSnoozeTime = aItem.getProperty("X-MOZ-SNOOZE-TIME");
-  let icalSnoozeTime = null;
-  if (itemSnoozeTime) {
-    // The property is saved as a string, translate back to calIDateTime.
-    icalSnoozeTime = cal.createDateTime();
-    icalSnoozeTime.icalString = itemSnoozeTime;
-  }
-  addExtendedProperty("X-MOZ-SNOOZE-TIME", cal.dtz.toRFC3339(icalSnoozeTime), true);
-
-  // gd:extendedProperty (snooze recurring alarms)
-  let snoozeValue = "";
-  if (aItem.recurrenceInfo) {
-    // This is an evil workaround since we don't have a really good system
-    // to save the snooze time for recurring alarms or even retrieve them
-    // from the event. This should change when we have multiple alarms
-    // support.
-    let snoozeObj = {};
-    for (let [name, value] of aItem.properties) {
-      if (name.substr(0, 18) == "X-MOZ-SNOOZE-TIME-") {
-        // We have a snooze time for a recurring event, add it to our object
-        snoozeObj[name.substr(18)] = value;
-      }
-    }
-    if (Object.keys(snoozeObj).length > 0) {
-      snoozeValue = JSON.stringify(snoozeObj);
-    }
-  }
-  // Now save the snooze object in source format as an extended property. Do
-  // so always, since its currently impossible to unset extended properties.
-  addExtendedProperty("X-GOOGLE-SNOOZE-RECUR", snoozeValue, true);
-
-  // recurrence information
-  if (aItem.recurrenceInfo) {
-    itemData.recurrence = [];
-    let recurrenceItems = aItem.recurrenceInfo.getRecurrenceItems({});
-    for (let ritem of recurrenceItems) {
-      let prop = ritem.icalProperty;
-      if (ritem instanceof Ci.calIRecurrenceDate) {
-        // EXDATES require special casing, since they might contain
-        // a TZID. To avoid the need for conversion of TZID strings,
-        // convert to UTC before serialization.
-        prop.valueAsDatetime = ritem.date.getInTimezone(cal.dtz.UTC);
-      }
-      itemData.recurrence.push(prop.icalString.trim());
-    }
-  } else if (aItem.recurrenceId) {
-    itemData.originalStartTime = dateToJSON(aItem.recurrenceId);
-    let parentMeta = getItemMetadata(aOfflineStorage, aItem.parentItem);
-    itemData.recurringEventId = parentMeta ? parentMeta.path : aItem.id.replace("@google.com", "");
-  }
-
-  return itemData;
-}
-
-/**
- * Converts a calITodo to a JS Object that can be serialized to JSON.
- *
- * @param aItem         The item to convert.
- * @return              A JS Object representing the item.
- */
-function TaskToJSON(aItem, aOfflineStorage, aIsImport) {
-  function setIf(data, prop, value) {
-    if (value) {
-      data[prop] = value;
-    }
-  }
-
-  let itemData = {};
-
-  setIf(itemData, "id", aItem.id);
-  setIf(itemData, "title", aItem.title);
-  setIf(itemData, "notes", aItem.getProperty("DESCRIPTION"));
-  setIf(itemData, "position", aItem.getProperty("X-SORTKEY"));
-  itemData.status = aItem.isCompleted ? "completed" : "needsAction";
-
-  if (aItem.dueDate) {
-    let dueDate = aItem.dueDate.getInTimezone(cal.dtz.UTC);
-    dueDate.isDate = false;
-    itemData.due = cal.dtz.toRFC3339(dueDate);
-  }
-  setIf(itemData, "completed", cal.dtz.toRFC3339(aItem.completedDate));
-
-  for (let relation of aItem.getRelations({})) {
-    if (relation.relId && (!relation.relType || relation.relType == "PARENT")) {
-      itemData.parent = relation.relId;
-      break;
-    }
-  }
-
-  let attachments = aItem.getAttachments({});
-  if (attachments.length) {
-    itemData.links = [];
-  }
-  for (let attach of aItem.getAttachments({})) {
-    let attachData = {};
-    attachData.link = attach.uri.spec;
-    attachData.description = attach.getParameter("FILENAME");
-    attachData.type = attach.getParameter("X-TYPE");
-    itemData.links.push(attachData);
-  }
-
-  return itemData;
-}
-
-/**
- * Convenience function to convert any item type (task/event) to its JSON
- * representation
- *
- * @param aItem         The item to convert
- * @return              A JS Object representing the item.
- */
-function ItemToJSON(aItem, aOfflineStorage, aIsImport) {
-  if (cal.item.isEvent(aItem)) {
-    return EventToJSON(aItem, aOfflineStorage, aIsImport);
-  } else if (cal.item.isToDo(aItem)) {
-    return TaskToJSON(aItem, aOfflineStorage, aIsImport);
-  } else {
-    cal.ERROR("[calGoogleCalendar] Invalid item type: " + aItem.icalString);
-    return null;
-  }
-}
-
-/**
- * Sets up the recurrence info on the item
- *
- * @param aItem              The item to setup recurrence for.
- * @param aRecurrence        The JSON entry describing recurrence.
- */
-function setupRecurrence(aItem, aRecurrence, aTimezone) {
-  if (!aRecurrence) {
-    return;
-  }
-
-  if (aItem.recurrenceInfo) {
-    aItem.recurrenceInfo.clearRecurrenceItems();
-  } else {
-    aItem.recurrenceInfo = cal.createRecurrenceInfo(aItem);
-  }
-
-  let rootComp;
-  let vevent = "BEGIN:VEVENT\r\n" + aRecurrence.join("\r\n") + "\r\nEND:VEVENT";
-  try {
-    rootComp = cal.getIcsService().parseICS(vevent, null);
-  } catch (e) {
-    cal.ERROR("[calGoogleCalendar] Unable to parse recurrence item: " + vevent);
-  }
-
-  let hasRecurringRules = false;
-  for (let prop = rootComp.getFirstProperty("ANY"); prop; prop = rootComp.getNextProperty("ANY")) {
-    switch (prop.propertyName) {
-      case "RDATE":
-      case "EXDATE": {
-        let recItem = Cc["@mozilla.org/calendar/recurrence-date;1"].createInstance(
-          Ci.calIRecurrenceDate
-        );
-        try {
-          recItem.icalProperty = prop;
-          aItem.recurrenceInfo.appendRecurrenceItem(recItem);
-          hasRecurringRules = true;
-        } catch (e) {
-          cal.ERROR(
-            "[calGoogleCalendar] Error parsing " +
-              prop.propertyName +
-              " (" +
-              prop.icalString +
-              "):" +
-              e
-          );
-        }
-        break;
-      }
-      case "RRULE": {
-        let recRule = cal.createRecurrenceRule();
-        try {
-          recRule.icalProperty = prop;
-          aItem.recurrenceInfo.appendRecurrenceItem(recRule);
-          hasRecurringRules = true;
-        } catch (e) {
-          cal.ERROR("[calGoogleCalendar] Error parsing RRULE (" + prop.icalString + "):" + e);
-        }
-        break;
-      }
-    }
-  }
-
-  if (!hasRecurringRules) {
-    // If there were no parsable recurrence items, then clear the
-    // recurrence info.
-    aItem.recurrenceInfo = null;
-  }
-}
-
-/**
- * Create an alarm from the JSON reminder entry
- *
- * @param aEntry            The JSON reminder entry.
- * @param aDefault          (optional) If true, this is a default alarm.
- * @return                  The translated calIAlarm.
- */
-function JSONToAlarm(aEntry, aDefault) {
-  const alarmActionMap = {
-    email: "EMAIL",
-    popup: "DISPLAY",
-    sms: "SMS",
-  };
-  let alarm = cal.createAlarm();
-  let alarmOffset = cal.createDuration();
-  alarm.action = alarmActionMap[aEntry.method] || "DISPLAY";
-  alarm.related = Ci.calIAlarm.ALARM_RELATED_START;
-  alarmOffset.inSeconds = -aEntry.minutes * 60;
-  alarmOffset.normalize();
-  alarm.offset = alarmOffset;
-
-  if (aDefault) {
-    alarm.setProperty("X-DEFAULT-ALARM", "TRUE");
-  }
-  return alarm;
-}
-
-/**
- * Converts a JS Object representing the event to a calIEvent.
- *
- * @param aEntry            The JS Object representation of the item.
- * @param aCalendar         The calendar this item will belong to.
- * @param aDefaultReminders An array of default reminders, as a JS Object.
- * @param aMetadata         (optional,out) Item metadata that should be set.
- * @return                  The calIEvent with the item data.
- */
-function JSONToEvent(aEntry, aCalendar, aDefaultReminders, aReferenceItem, aMetadata) {
-  aDefaultReminders = aDefaultReminders || [];
-  aMetadata = aMetadata || {};
-  let item = aReferenceItem || cal.createEvent();
-  item.calendar = aCalendar.superCalendar;
-  let privateProps = ("extendedProperties" in aEntry && aEntry.extendedProperties.private) || {};
-  let sharedProps = ("extendedProperties" in aEntry && aEntry.extendedProperties.shared) || {};
-  let accessRole = aCalendar.getProperty("settings.accessRole");
-
-  LOGverbose("[calGoogleCalendar] Parsing entry:\n" + JSON.stringify(aEntry, null, " ") + "\n");
-
-  if (!aEntry || !("kind" in aEntry) || aEntry.kind != "calendar#event") {
-    cal.ERROR(
-      "[calGoogleCalendar] Attempt to decode invalid event: " +
-        (aEntry && JSON.stringify(aEntry, null, " "))
-    );
-    return null;
-  }
-
-  let tzs = cal.getTimezoneService();
-  let calendarZoneName = aCalendar.getProperty("settings.timeZone");
-  let calendarZone = calendarZoneName ? tzs.getTimezone(calendarZoneName) : cal.dtz.defaultTimezone;
-
-  try {
-    item.id = aEntry.iCalUID || (aEntry.recurringEventId || aEntry.id) + "@google.com";
-    item.recurrenceId = JSONToDate(aEntry.originalStartTime, calendarZone);
-    if (!item.recurrenceId) {
-      // Sometimes recurring event instances don't have recurringEventId
-      // set, but are still instances. work around by detecting the ID.
-      // http://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=3199
-      let hack = aEntry.id.match(/([^_]*)_(\d{8}(T\d{6}Z)?)$/);
-      item.recurrenceId = hack ? cal.createDateTime(hack[2]) : null;
-    }
-    item.status = aEntry.status ? aEntry.status.toUpperCase() : null;
-    item.title = aEntry.summary;
-    if (accessRole == "freeBusyReader") {
-      item.title = getProviderString("busyTitle", aCalendar.name);
-    }
-    item.privacy = aEntry.visibility ? aEntry.visibility.toUpperCase() : null;
-
-    item.setProperty(
-      "URL",
-      aEntry.htmlLink && aCalendar.uri.schemeIs("https")
-        ? aEntry.htmlLink.replace(/^http:/, "https:")
-        : aEntry.htmlLink
-    );
-    item.setProperty(
-      "CREATED",
-      aEntry.created
-        ? cal.dtz.fromRFC3339(aEntry.created, calendarZone).getInTimezone(cal.dtz.UTC)
-        : null
-    );
-    item.setProperty("DESCRIPTION", aEntry.description);
-    item.setProperty("LOCATION", aEntry.location);
-    item.setProperty("TRANSP", aEntry.transparency ? aEntry.transparency.toUpperCase() : null);
-    item.setProperty("SEQUENCE", aEntry.sequence);
-    aMetadata.etag = aEntry.etag;
-    aMetadata.path = aEntry.id;
-
-    // organizer
-    if (aEntry.organizer) {
-      let organizer = cal.createAttendee();
-      if (aEntry.organizer.email) {
-        organizer.id = "mailto:" + aEntry.organizer.email;
-      } else {
-        organizer.id = "urn:id:" + aEntry.organizer.id;
-      }
-      organizer.commonName = aEntry.organizer.displayName;
-      organizer.isOrganizer = true;
-      item.organizer = organizer;
-
-      if (aEntry.organizer.self && aCalendar.session) {
-        // Remember the display name, we found ourselves!
-        aCalendar.setProperty("organizerCN", aEntry.organizer.displayName);
-      }
-    } else {
-      item.organizer = null;
-    }
-
-    // start and end
-    item.startDate = JSONToDate(aEntry.start, calendarZone);
-    item.endDate = JSONToDate(aEntry.end, calendarZone);
-
-    // recurrence
-    setupRecurrence(item, aEntry.recurrence, calendarZone);
-
-    // attendees
-    item.removeAllAttendees();
-    if (aEntry.attendees) {
-      const statusMap = {
-        needsAction: "NEEDS-ACTION",
-        declined: "DECLINED",
-        tentative: "TENTATIVE",
-        accepted: "ACCEPTED",
-      };
-      for (let attendeeEntry of aEntry.attendees) {
-        let attendee = cal.createAttendee();
-        if (attendeeEntry.email) {
-          attendee.id = "mailto:" + attendeeEntry.email;
-        } else {
-          attendee.id = "urn:id:" + attendeeEntry.id;
-        }
-        attendee.commonName = attendeeEntry.displayName;
-
-        if (attendeeEntry.optional) {
-          attendee.role = "OPT-PARTICIPANT";
-        } else {
-          attendee.role = "REQ-PARTICIPANT";
-        }
-
-        attendee.participationStatus = statusMap[attendeeEntry.responseStatus];
-
-        if (attendeeEntry.resource) {
-          attendee.userType = "RESOURCE";
-        } else {
-          attendee.userType = "INDIVIDUAL";
-        }
-
-        item.addAttendee(attendee);
-      }
-    }
-
-    // reminders
-    item.clearAlarms();
-
-    if (aEntry.reminders) {
-      if (aEntry.reminders.useDefault) {
-        aDefaultReminders.forEach(item.addAlarm, item);
-
-        if (aDefaultReminders.length) {
-          item.deleteProperty("X-DEFAULT-ALARM");
-        } else {
-          // Nothing to make clear we are using default reminders.
-          // Set an X-PROP until VALARM extensions are supported
-          item.setProperty("X-DEFAULT-ALARM", "TRUE");
-        }
-      }
-
-      if (aEntry.reminders.overrides) {
-        for (let reminderEntry of aEntry.reminders.overrides) {
-          item.addAlarm(JSONToAlarm(reminderEntry));
-        }
-      }
-    }
-
-    // extendedProperty (alarmLastAck)
-    item.alarmLastAck = cal.dtz.fromRFC3339(privateProps["X-MOZ-LASTACK"], calendarZone);
-
-    // extendedProperty (snooze time)
-    let dtSnoozeTime = cal.dtz.fromRFC3339(privateProps["X-MOZ-SNOOZE-TIME"], calendarZone);
-    let snoozeProperty = dtSnoozeTime ? dtSnoozeTime.icalString : null;
-    item.setProperty("X-MOZ-SNOOZE-TIME", snoozeProperty);
-
-    // extendedProperty (snooze recurring alarms)
-    if (item.recurrenceInfo) {
-      // Transform back the string into our snooze properties
-      let snoozeObj;
-      try {
-        let snoozeString = privateProps["X-GOOGLE-SNOOZE-RECUR"];
-        snoozeObj = JSON.parse(snoozeString);
-      } catch (e) {
-        // Just swallow parsing errors, not so important.
-      }
-
-      if (snoozeObj) {
-        for (let rid in snoozeObj) {
-          item.setProperty("X-MOZ-SNOOZE-TIME-" + rid, snoozeObj[rid]);
-        }
-      }
-    }
-
-    // Google does not support categories natively, but allows us to store
-    // data as an "extendedProperty", and here it's going to be retrieved
-    // again
-    let categories = cal.category.stringToArray(sharedProps["X-MOZ-CATEGORIES"]);
-    item.setCategories(categories.length, categories);
-
-    // updated (This must be set last!)
-    if (aEntry.updated) {
-      let updated = cal.dtz.fromRFC3339(aEntry.updated, calendarZone).getInTimezone(cal.dtz.UTC);
-      item.setProperty("DTSTAMP", updated);
-      item.setProperty("LAST-MODIFIED", updated);
-    }
-  } catch (e) {
-    cal.ERROR(stringException(e));
-    throw e;
-  }
-  return item;
-}
-
-/**
- * Converts a JS Object representing the task to a calITodo.
- *
- * @param aEntry            The JS Object representation of the item.
- * @param aCalendar         The calendar this item will belong to.
- * @param aMetadata         (optional,out) Item metadata that should be set.
- * @return                  The calITodo with the item data.
- */
-function JSONToTask(aEntry, aCalendar, aDefaultReminders, aReferenceItem, aMetadata) {
-  aDefaultReminders = aDefaultReminders || [];
-  aMetadata = aMetadata || {};
-  if (!aEntry || !("kind" in aEntry) || aEntry.kind != "tasks#task") {
-    cal.ERROR(
-      "[calGoogleCalendar] Attempt to decode invalid task: " +
-        (aEntry && JSON.stringify(aEntry, null, " "))
-    );
-    return null;
-  }
-  let item = cal.createTodo();
-  item.calendar = aCalendar.superCalendar;
-
-  let tzs = cal.getTimezoneService();
-  let calendarZoneName = aCalendar.getProperty("settings.timeZone");
-  let calendarZone = calendarZoneName ? tzs.getTimezone(calendarZoneName) : cal.dtz.defaultTimezone;
-
-  try {
-    item.id = aEntry.id;
-    item.title = aEntry.title || "";
-    item.setProperty("DESCRIPTION", aEntry.notes);
-    item.setProperty("X-GOOGLE-SORTKEY", aEntry.position);
-    item.isCompleted = aEntry.status == "completed";
-
-    aMetadata.etag = aEntry.etag;
-    aMetadata.path = aEntry.id;
-
-    // Google Tasks don't have a due time, but still use 0:00 UTC. They
-    // should really be using floating time.
-    item.dueDate = cal.dtz.fromRFC3339(aEntry.due, cal.dtz.floating);
-    if (item.dueDate) {
-      item.dueDate.timezone = cal.dtz.floating;
-      item.dueDate.isDate = true;
-    }
-    item.completedDate = cal.dtz.fromRFC3339(aEntry.completed, calendarZone);
-    if (aEntry.deleted) {
-      item.status = "CANCELLED";
-    } else if (aEntry.status == "needsAction") {
-      item.status = "NEEDS-ACTION";
-    } else {
-      item.status = "COMPLETED";
-    }
-
-    if (aEntry.parent) {
-      let relation = cal.createRelation();
-      relation.relType = "PARENT";
-      relation.relId = aEntry.parent;
-      item.addRelation(relation);
-    }
-
-    if (aEntry.links) {
-      for (let link of aEntry.links) {
-        let attach = cal.createAttachment();
-        attach.uri = Services.io.newURI(link.link);
-        attach.setParameter("FILENAME", link.description);
-        attach.setParameter("X-GOOGLE-TYPE", link.type);
-        item.addAttachment(attach);
-      }
-    }
-
-    // updated (This must be set last!)
-    item.setProperty(
-      "DTSTAMP",
-      cal.dtz.fromRFC3339(aEntry.updated, calendarZone).getInTimezone(cal.dtz.UTC)
-    );
-    item.setProperty(
-      "LAST-MODIFIED",
-      cal.dtz.fromRFC3339(aEntry.updated, calendarZone).getInTimezone(cal.dtz.UTC)
-    );
-  } catch (e) {
-    cal.ERROR("[calGoogleCalendar] Error parsing JSON tasks stream: " + stringException(e));
-    throw e;
-  }
-
-  return item;
-}
-
-/**
- * Convenience function to convert any JSON reply (task/event) to a calendar
- * item.
- *
- * @param aEntry            The JS Object representation of the item.
- * @param aCalendar         The calendar this item will belong to.
- * @param aMetadata         (optional,out) Item metadata that should be set.
- * @return                  The specialized calIItemBase with the item data.
- */
-function JSONToItem(aEntry, aCalendar, aDefaultReminders, aReferenceItem, aMetadata) {
-  aDefaultReminders = aDefaultReminders || [];
-  aMetadata = aMetadata || {};
-  if (aEntry.kind == "tasks#task") {
-    return JSONToTask(...arguments);
-  } else if (aEntry.kind == "calendar#event") {
-    return JSONToEvent(...arguments);
-  } else {
-    cal.ERROR("[calGoogleCalendar] Invalid item type: " + (aEntry ? aEntry.kind : "<no entry>"));
-    return null;
-  }
-}
-
-/**
- * Save items spread over multiple pages to the calendar's offline storage.
- *
- * @param aCalendar     The calendar the events belong to.
- */
-function ItemSaver(aCalendar) {
-  this.calendar = aCalendar;
-  this.offlineStorage = this.calendar.offlineStorage;
-  this.promiseOfflineStorage = cal.async.promisifyCalendar(this.calendar.offlineStorage);
-  this.missingParents = [];
-  this.masterItems = Object.create(null);
-  this.metaData = Object.create(null);
-  this.activity = new ActivityShell(aCalendar);
-}
-ItemSaver.prototype = {
-  masterItems: null,
-  missingParents: null,
-
-  /**
-   * Convenience function to apply a list of items (task/event) in JSON form to
-   * the given calendar.
-   *
-   * @param aData         The JS Object from the list response.
-   * @return              A promise resolved when completed.
-   */
-  parseItemStream: function(aData) {
-    if (aData.kind == "calendar#events") {
-      this.activity.type = "Event";
-      return this.parseEventStream(aData);
-    } else if (aData.kind == "tasks#tasks") {
-      this.activity.type = "Task";
-      return this.parseTaskStream(aData);
-    } else {
-      let message = "Invalid Stream type: " + (aData ? aData.kind || aData.toSource() : null);
-      throw new Components.Exception(message, Cr.NS_ERROR_FAILURE);
-    }
-  },
-
-  /**
-   * Parse the response from Google's list command into tasks and modify the
-   * calendar's offline storage to reflect those changes.
-   *
-   * @param aData         The JS Object from the list response.
-   * @return              A promise resolved when completed.
-   */
-  parseTaskStream: async function(aData) {
-    if (!aData.items || !aData.items.length) {
-      cal.LOG("[calGoogleCalendar] No tasks have been changed on " + this.calendar.name);
-    } else {
-      cal.LOG("[calGoogleCalendar] Parsing " + aData.items.length + " received tasks");
-
-      let total = aData.items.length;
-      let committedUnits = 0;
-      this.activity.addTotal(total);
-
-      for (let cur = 0; cur < total; cur++) {
-        let entry = aData.items[cur];
-        // let metaData = Object.create(null);
-        let metaData = {};
-        let item = JSONToTask(entry, this.calendar, null, null, metaData);
-        this.metaData[item.hashId] = metaData;
-
-        await this.commitItem(item);
-
-        if (await spinEventLoop()) {
-          this.activity.addProgress(cur - committedUnits);
-          committedUnits = cur;
-        }
-      }
-    }
-  },
-
-  /**
-   * Parse the response from Google's list command into events.
-   *
-   * @param aData         The JS Object from the list response.
-   * @return              A promise resolved when completed.
-   */
-  parseEventStream: async function(aData) {
-    if (aData.timeZone) {
-      cal.LOG("[calGoogleCalendar] Timezone for " + this.calendar.name + " is " + aData.timeZone);
-      this.calendar.setProperty("settings.timeZone", aData.timeZone);
-    }
-
-    if (!aData.items || !aData.items.length) {
-      cal.LOG("[calGoogleCalendar] No events have been changed on " + this.calendar.name);
-      return;
-    } else {
-      cal.LOG("[calGoogleCalendar] Parsing " + aData.items.length + " received events");
-    }
-
-    let exceptionItems = [];
-    let defaultReminders = (aData.defaultReminders || []).map(reminder =>
-      JSONToAlarm(reminder, true)
-    );
-
-    // In the first pass, we go through the data and sort into master items and
-    // exception items, as the master item might be after the exception in the
-    // stream.
-
-    let total = aData.items.length;
-    let committedUnits = 0;
-    this.activity.addTotal(total);
-
-    for (let cur = 0; cur < total; cur++) {
-      let entry = aData.items[cur];
-      let metaData = Object.create(null);
-      let item = JSONToEvent(entry, this.calendar, defaultReminders, null, metaData);
-      LOGitem(item);
-
-      this.metaData[item.hashId] = metaData;
-
-      if (item.recurrenceId) {
-        exceptionItems.push(item);
-      } else {
-        this.masterItems[item.id] = item;
-        await this.commitItem(item);
-      }
-
-      if (await spinEventLoop()) {
-        this.activity.addProgress(cur - committedUnits);
-        committedUnits = cur;
-      }
-    }
-
-    // Go through all exceptions and attempt to find the master item in the
-    // item stream. If it can't be found there, the offline storage is asked
-    // for the parent item. If it still can't be found, then we have to do
-    // this at the end.
-    for (let exc of exceptionItems) {
-      // If we have the master item in our cache then use it. Otherwise
-      // attempt to get it from the offline storage.
-      let item;
-      if (exc.id in this.masterItems) {
-        item = this.masterItems[exc.id];
-      } else {
-        item = (await this.promiseOfflineStorage.getItem(exc.id))[0];
-      }
-
-      // If an item was found, we can process this exception. Otherwise
-      // save it for later, maybe its on the next page of the request.
-      if (item) {
-        if (!item.isMutable) {
-          item = item.clone();
-        }
-        await this.processException(exc, item);
-      } else {
-        this.missingParents.push(exc);
-      }
-
-      await this.commitException(exc);
-    }
-  },
-
-  /**
-   * Handle the exception for the given item by committing it to the
-   * calendar.
-   *
-   * @param exc       The exception to process.
-   * @param item      The item the exception belongs to.
-   * @return          A promise resolved when the item is added to the
-   *                    calendar.
-   */
-  processException: function(exc, item) {
-    if (item.status == "CANCELLED") {
-      // Cancelled master items don't have the full amount of
-      // information, specifically no recurrence info. Since they are
-      // cancelled anyway, we can just ignore processing this exception.
-      return Promise.resolve();
-    }
-
-    exc.parentItem = item;
-    if (exc.status == "CANCELLED") {
-      // Canceled means the occurrence is an EXDATE.
-      item.recurrenceInfo.removeOccurrenceAt(exc.recurrenceId);
-    } else {
-      // Not canceled means the occurrence was modified.
-      item.recurrenceInfo.modifyException(exc, true);
-    }
-    this.masterItems[item.id] = item;
-    return this.commitItem(item);
-  },
-
-  /**
-   * Handle final tasks for the exception. This means saving the metadat for the exception.
-   *
-   * @param exc       The exception to process.
-   */
-  commitException: function(exc) {
-    // Make sure we also save the etag of the exception for a future request.
-    if (exc.hashId in this.metaData) {
-      saveItemMetadata(this.offlineStorage, exc.hashId, this.metaData[exc.hashId]);
-    }
-  },
-
-  /**
-   * Handle adding the item to the calendar, or removing it if its a cancelled item.
-   *
-   * @param item      The item to process.
-   * @return          A promise resolved when the process is completed.
-   */
-  commitItem: async function(item) {
-    // This is a normal item. If it was canceled, then it should be
-    // deleted, otherwise it should be either added or modified. The
-    // relaxed mode of the destination calendar takes care of the latter
-    // two cases.
-    if (item.status == "CANCELLED") {
-      await this.promiseOfflineStorage.deleteItem(item);
-    } else {
-      await this.promiseOfflineStorage.modifyItem(item, null);
-    }
-
-    if (item.hashId in this.metaData) {
-      // Make sure the metadata is up to date for the next request
-      saveItemMetadata(this.offlineStorage, item.hashId, this.metaData[item.hashId]);
-    }
-  },
-
-  /**
-   * Complete the item saving, this will take care of all steps required
-   * after the last request.
-   */
-  complete: function() {
-    return this.processRemainingExceptions().then(() => {
-      this.activity.complete();
-    });
-  },
-
-  /**
-   * Handle all remaining exceptions in the item saver. Ensures that any
-   * missing master items are searched for or created.
-   *
-   * @return          A promise resolved on completion
-   */
-  processRemainingExceptions: async function() {
-    for (let exc of this.missingParents) {
-      let item = (await this.promiseOfflineStorage.getItem(exc.id))[0];
-      if (item) {
-        await this.processException(exc, item);
-      } else if (exc.status != "CANCELLED") {
-        // If the item could not be found, it could be that the
-        // user is invited to an instance of a recurring event.
-        // Unless this is a cancelled exception, create a mock
-        // parent item with one positive RDATE.
-        let parent = exc.clone();
-        parent.recurrenceId = null;
-        parent.calendar = this.calendar.superCalendar;
-        parent.startDate = exc.recurrenceId.clone();
-        parent.setProperty("X-MOZ-FAKED-MASTER", "1");
-        if (!parent.id) {
-          // Exceptions often don't have the iCalUID field set,
-          // we need to fake it from the google id.
-          let meta = this.metaData[exc.hashId];
-          parent.id = meta.path + "@google.com";
-        }
-        parent.recurrenceInfo = cal.createRecurrenceInfo(parent);
-        let rdate = Cc["@mozilla.org/calendar/recurrence-date;1"].createInstance(
-          Ci.calIRecurrenceDate
-        );
-        rdate.date = exc.recurrenceId;
-        parent.recurrenceInfo.appendRecurrenceItem(rdate);
-        await this.commitItem(parent);
-      }
-    }
-  },
-};
-
-/**
- * A wrapper for nsIActivity to handle the synchronization process.
- *
- * @param aCalendar     The calendar for this activity.
- */
-function ActivityShell(aCalendar) {
-  this.calendar = aCalendar;
-
-  if ("@mozilla.org/activity-process;1" in Cc) {
-    this.init();
-  }
-}
-
-ActivityShell.prototype = {
-  act: null,
-  actMgr: null,
-  calendar: null,
-  type: null,
-
-  init: function() {
-    this.actMgr = Cc["@mozilla.org/activity-manager;1"].getService(Ci.nsIActivityManager);
-    this.act = Cc["@mozilla.org/activity-process;1"].createInstance(Ci.nsIActivityProcess);
-    this.act.init(getProviderString("syncStatus", this.calendar.name), this);
-    this.act.iconClass = "syncMail";
-    this.act.contextType = "gdata-calendar";
-    this.act.contextObj = this.calendar;
-    this.act.contextDisplayText = this.calendar.name;
-    this.act.state = Ci.nsIActivityProcess.STATE_INPROGRESS;
-
-    this.actMgr.addActivity(this.act);
-  },
-
-  addProgress: function(units) {
-    if (!this.act) {
-      return;
-    }
-    this.setProgress(this.act.workUnitComplete + units, this.act.totalWorkUnits);
-  },
-
-  addTotal: function(units) {
-    if (!this.act) {
-      return;
-    }
-    this.setProgress(this.act.workUnitComplete, this.act.totalWorkUnits + units);
-  },
-
-  setProgress: function(cur, total) {
-    if (!this.act) {
-      return;
-    }
-    let str = getProviderString("syncProgress" + this.type, this.calendar.name, cur, total);
-    this.act.setProgress(str, cur, total);
-  },
-
-  complete: function() {
-    if (!this.act) {
-      return;
-    }
-    let total = this.act.totalWorkUnits;
-    this.act.setProgress("", total, total);
-    this.act.state = Ci.nsIActivityProcess.STATE_COMPLETED;
-    this.actMgr.removeActivity(this.act.id);
-  },
-};
-
-/**
- * Check if the response is a conflict and handle asking the user what to do
- * about it. Will resolve if there is no conflict or with new item data.
- * where status is a conflict status, see the end of this function.
- *
- * @param aOperation        The operation to check.
- * @param aCalendar         The calendar this operation happens in
- * @param aItem             The item that was passed to the server
- * @return                  A promise resolved when the conflict has been resolved
- */
-async function checkResolveConflict(aOperation, aCalendar, aItem) {
-  cal.LOG("[calGoogleCalendar] A conflict occurred for " + aItem.title);
-
-  let method = aOperation.type == aOperation.DELETE ? "delete" : "modify";
-  let overwrite = cal.provider.promptOverwrite(method, aItem);
-  if (overwrite) {
-    // The user has decided to overwrite the server version. Send again
-    // overwriting the server version with If-Match: *
-    cal.LOG("[calGoogleCalendar] Resending " + method + " and ignoring ETag");
-    aOperation.addRequestHeader("If-Match", "*");
-    try {
-      return await aCalendar.session.asyncItemRequest(aOperation);
-    } catch (e) {
-      if (e.result == calGoogleRequest.RESOURCE_GONE && aOperation.type == aOperation.DELETE) {
-        // The item was deleted on the server and locally, we don't need to
-        // notify the user about this.
-        return null;
-      } else {
-        throw e;
-      }
-    }
-  } else {
-    // The user has decided to throw away changes, use our existing
-    // means to update the item locally.
-    cal.LOG("[calGoogleCalendar] Reload requested, cancelling change of " + aItem.title);
-    aCalendar.superCalendar.refresh();
-    throw Components.Exception(null, Ci.calIErrors.OPERATION_CANCELLED);
-  }
-}
-
-/**
- * Get a string from the gdata properties file
- *
- * @param aStringName  The name of the string within the properties file
- * @param ...aParams   Optional parameters to format the string
- * @return             The localized string value.
- */
-function getProviderString(aStringName, ...aParams) {
-  return cal.l10n.getAnyString("gdata-provider", "gdata", aStringName, aParams);
-}
-
-/**
- * Monkey patch the function with the name x on obj and overwrite it with func.
- * The first parameter of this function is the original function that can be
- * called at any time.
- *
- * @param obj           The object the function is on.
- * @param name          The string name of the function.
- * @param func          The function to monkey patch with.
- */
-function monkeyPatch(obj, x, func) {
-  let old = obj[x];
-  obj[x] = function() {
-    let parent = old.bind(obj);
-    let args = Array.from(arguments);
-    args.unshift(parent);
-    try {
-      return func.apply(obj, args);
-    } catch (e) {
-      Cu.reportError(e);
-      throw e;
-    }
-  };
-}
-
-/**
- * Returns a promise that resolves after pending events have been processed.
- */
-function spinEventLoop() {
-  let diff = new Date() - spinEventLoop.lastSpin;
-  if (diff < Services.prefs.getIntPref("calendar.threading.latency", 250)) {
-    return Promise.resolve(false);
-  }
-  spinEventLoop.lastSpin = new Date();
-
-  let deferred = PromiseUtils.defer();
-  Services.tm.currentThread.dispatch(
-    {
-      run: function() {
-        return deferred.resolve(true);
-      },
-    },
-    0
-  );
-  return deferred.promise;
-}
-spinEventLoop.lastSpin = new Date();
deleted file mode 100644
--- a/calendar/providers/gdata/modules/timezoneMap.jsm
+++ /dev/null
@@ -1,142 +0,0 @@
-// Mappings Copyright © 1991-2013 Unicode, Inc. with modifications.
-// http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml
-
-var EXPORTED_SYMBOLS = ["windowsTimezoneMap"];
-
-var windowsTimezoneMap = {
-  "Afghanistan Standard Time": "Asia/Kabul",
-  "Alaskan Standard Time": "America/Anchorage",
-  "Aleutian Standard Time": "America/Adak",
-  "Altai Standard Time": "Asia/Barnaul",
-  "Arab Standard Time": "Asia/Riyadh",
-  "Arabian Standard Time": "Asia/Dubai",
-  "Arabic Standard Time": "Asia/Baghdad",
-  "Argentina Standard Time": "America/Buenos_Aires",
-  "Armenian Standard Time": "Asia/Yerevan",
-  "Astrakhan Standard Time": "Europe/Astrakhan",
-  "Atlantic Standard Time": "America/Halifax",
-  "AUS Central Standard Time": "Australia/Darwin",
-  "Aus Central W. Standard Time": "Australia/Eucla",
-  "AUS Eastern Standard Time": "Australia/Sydney",
-  "Azerbaijan Standard Time": "Asia/Baku",
-  "Azores Standard Time": "Atlantic/Azores",
-  "Bahia Standard Time": "America/Bahia",
-  "Bangkok Standard Time": "Asia/Bangkok",
-  "Bangladesh Standard Time": "Asia/Dhaka",
-  "Belarus Standard Time": "Europe/Minsk",
-  "Bougainville Standard Time": "Pacific/Bougainville",
-  "Canada Central Standard Time": "America/Regina",
-  "Cape Verde Standard Time": "Atlantic/Cape_Verde",
-  "Caucasus Standard Time": "Asia/Yerevan",
-  "Cen. Australia Standard Time": "Australia/Adelaide",
-  "Central America Standard Time": "America/Guatemala",
-  "Central Asia Standard Time": "Asia/Almaty",
-  "Central Brazilian Standard Time": "America/Cuiaba",
-  "Central Europe Standard Time": "Europe/Prague",
-  "Central European Standard Time": "Europe/Warsaw",
-  "Central Pacific Standard Time": "Pacific/Guadalcanal",
-  "Central Standard Time (Mexico)": "America/Mexico_City",
-  "Central Standard Time": "America/Chicago",
-  "Chatham Islands Standard Time": "Pacific/Chatham",
-  "China Standard Time": "Asia/Shanghai",
-  "Cuba Standard Time": "America/Havana",
-  "E. Africa Standard Time": "Africa/Nairobi",
-  "E. Australia Standard Time": "Australia/Brisbane",
-  "E. Europe Standard Time": "Europe/Chisinau",
-  "E. South America Standard Time": "America/Sao_Paulo",
-  "Easter Island Standard Time": "Pacific/Easter",
-  "Eastern Standard Time (Mexico)": "America/Cancun",
-  "Eastern Standard Time": "America/New_York",
-  "Egypt Standard Time": "Africa/Cairo",
-  "Ekaterinburg Standard Time": "Asia/Yekaterinburg",
-  "Fiji Standard Time": "Pacific/Fiji",
-  "FLE Standard Time": "Europe/Helsinki",
-  "Georgian Standard Time": "Asia/Tbilisi",
-  "GFT Standard Time": "Europe/Athens",
-  "GMT Standard Time": "Europe/London",
-  "Greenland Standard Time": "America/Godthab",
-  "Greenwich Standard Time": "Atlantic/Reykjavik",
-  "GTB Standard Time": "Europe/Athens",
-  "Haiti Standard Time": "America/Port-au-Prince",
-  "Hawaiian Standard Time": "Pacific/Honolulu",
-  "India Standard Time": "Asia/Calcutta",
-  "Iran Standard Time": "Asia/Tehran",
-  "Israel Standard Time": "Asia/Jerusalem",
-  "Jordan Standard Time": "Asia/Amman",
-  "Kaliningrad Standard Time": "Europe/Kaliningrad",
-  "Korea Standard Time": "Asia/Seoul",
-  "Libya Standard Time": "Africa/Tripoli",
-  "Line Islands Standard Time": "Pacific/Kiritimati",
-  "Lord Howe Standard Time": "Australia/Lord_Howe",
-  "Magadan Standard Time": "Asia/Magadan",
-  "Magallanes Standard Time": "America/Punta_Arenas",
-  "Marquesas Standard Time": "Pacific/Marquesas",
-  "Mauritius Standard Time": "Indian/Mauritius",
-  "Mexico Standard Time": "America/Mexico_City",
-  "Mid-Atlantic Standard Time": "Atlantic/South_Georgia",
-  "Middle East Standard Time": "Asia/Beirut",
-  "Montevideo Standard Time": "America/Montevideo",
-  "Morocco Standard Time": "Africa/Casablanca",
-  "Mountain Standard Time (Mexico)": "America/Chihuahua",
-  "Mountain Standard Time": "America/Denver",
-  "Myanmar Standard Time": "Asia/Rangoon",
-  "N. Central Asia Standard Time": "Asia/Novosibirsk",
-  "Namibia Standard Time": "Africa/Windhoek",
-  "Nepal Standard Time": "Asia/Katmandu",
-  "New Zealand Standard Time": "Pacific/Auckland",
-  "Newfoundland Standard Time": "America/St_Johns",
-  "Norfolk Standard Time": "Pacific/Norfolk",
-  "North Asia East Standard Time": "Asia/Irkutsk",
-  "North Asia Standard Time": "Asia/Krasnoyarsk",
-  "North Korea Standard Time": "Asia/Pyongyang",
-  "Omsk Standard Time": "Asia/Omsk",
-  "Pacific SA Standard Time": "America/Santiago",
-  "Pacific Standard Time (Mexico)": "America/Tijuana",
-  "Pacific Standard Time": "America/Los_Angeles",
-  "Pakistan Standard Time": "Asia/Karachi",
-  "Paraguay Standard Time": "America/Asuncion",
-  "Romance Standard Time": "Europe/Paris",
-  "Russia Time Zone 10": "Asia/Srednekolymsk",
-  "Russia Time Zone 11": "Asia/Kamchatka",
-  "Russia Time Zone 3": "Europe/Samara",
-  "Russian Standard Time": "Europe/Moscow",
-  "SA Eastern Standard Time": "America/Cayenne",
-  "SA Pacific Standard Time": "America/Bogota",
-  "SA Western Standard Time": "America/La_Paz",
-  "Saint Pierre Standard Time": "America/Miquelon",
-  "Sakhalin Standard Time": "Asia/Sakhalin",
-  "Samoa Standard Time": "Pacific/Apia",
-  "Sao Tome Standard Time": "Africa/Sao_Tome",
-  "Saratov Standard Time": "Europe/Saratov",
-  "Saudi Arabia Standard Time": "Asia/Riyadh",
-  "SE Asia Standard Time": "Asia/Bangkok",
-  "Singapore Standard Time": "Asia/Singapore",
-  "South Africa Standard Time": "Africa/Johannesburg",
-  "Sri Lanka Standard Time": "Asia/Colombo",
-  "Sudan Standard Time": "Africa/Khartoum",
-  "Sydney Standard Time": "Australia/Sydney",
-  "Syria Standard Time": "Asia/Damascus",
-  "Taipei Standard Time": "Asia/Taipei",
-  "Tasmania Standard Time": "Australia/Hobart",
-  "Tocantins Standard Time": "America/Araguaina",
-  "Tokyo Standard Time": "Asia/Tokyo",
-  "Tomsk Standard Time": "Asia/Tomsk",
-  "Tonga Standard Time": "Pacific/Tongatapu",
-  "Transbaikal Standard Time": "Asia/Chita",
-  "Turkey Standard Time": "Europe/Istanbul",
-  "Turks And Caicos Standard Time": "America/Grand_Turk",
-  "Ulaanbaatar Standard Time": "Asia/Ulaanbaatar",
-  "US Eastern Standard Time": "America/Indiana/Indianapolis",
-  "US Mountain Standard Time": "America/Phoenix",
-  "Venezuela Standard Time": "America/Caracas",
-  "Vladivostok Standard Time": "Asia/Vladivostok",
-  "W. Australia Standard Time": "Australia/Perth",
-  "W. Central Africa Standard Time": "Africa/Lagos",
-  "W. Europe Standard Time": "Europe/Berlin",
-  "W. Mongolia Standard Time": "Asia/Hovd",
-  "West Asia Standard Time": "Asia/Tashkent",
-  "West Bank Standard Time": "Asia/Hebron",
-  "West Pacific Standard Time": "Pacific/Port_Moresby",
-  "Western Brazilian Standard Time": "America/Rio_Branco",
-  "Yakutsk Standard Time": "Asia/Yakutsk",
-};
deleted file mode 100644
--- a/calendar/providers/gdata/moz.build
+++ /dev/null
@@ -1,44 +0,0 @@
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-version_parts = CONFIG['MOZ_APP_VERSION'].split('.')
-major_version = version_parts[0]
-DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
-DEFINES['MOZ_APP_MAXVERSION'] = major_version + '.*'
-
-if CONFIG['MOZ_ARTIFACT_BUILDS']:
-    XPI_NAME = 'gdata-provider'
-    export('XPI_NAME')
-else:
-    DIST_SUBDIR = 'extensions/{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}'
-    export('DIST_SUBDIR')
-
-FINAL_TARGET_PP_FILES += ['manifest.json']
-
-EXTRA_JS_MODULES += [
-    'modules/gdataLogging.jsm',
-    'modules/gdataRequest.jsm',
-    'modules/gdataSession.jsm',
-    'modules/gdataUtils.jsm',
-    'modules/OAuth2.jsm',
-    'modules/timezoneMap.jsm',
-]
-
-EXTRA_COMPONENTS += [
-    'components/calGoogleCalendar.js',
-    'components/calGoogleCalendar.manifest',
-]
-
-JAR_MANIFESTS += ['jar.mn']
-
-USE_EXTENSION_MANIFEST = True
-export('USE_EXTENSION_MANIFEST')
-
-JS_PREFERENCE_FILES += [
-    'defaults/preferences.js',
-]
-
-with Files('**'):
-    BUG_COMPONENT = ('Calendar', 'Provider: GData')
deleted file mode 100644
--- a/calendar/test/unit/test_gdata_provider.js
+++ /dev/null
@@ -1,2153 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-(function() {
-  const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-  Services.prefs.setBoolPref("javascript.options.showInConsole", true);
-  Services.prefs.setBoolPref("browser.dom.window.dump.enabled", true);
-  Services.prefs.setBoolPref("calendar.debug.log", true);
-  Services.prefs.setBoolPref("calendar.debug.log.verbose", true);
-
-  let xpiFile;
-  let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
-  if (env.exists("MOZ_FETCHES_DIR")) {
-    let path = env.get("MOZ_FETCHES_DIR");
-    if (AppConstants.platform == "win") {
-      path = path.replace(/\//g, "\\");
-    }
-    xpiFile = new FileUtils.File(path);
-    xpiFile.append("gdata-provider.xpi");
-  } else {
-    xpiFile = Services.dirsvc.get("CurProcD", Ci.nsIFile);
-    xpiFile.append("extensions");
-    xpiFile.append("{a62ef8ec-5fdc-40c2-873c-223b8a6925cc}");
-  }
-
-  dump("Loading " + xpiFile.path + "\n");
-  let manager = Cc["@mozilla.org/component-manager-extra;1"].getService(
-    Ci.nsIComponentManagerExtra
-  );
-  manager.addLegacyExtensionManifestLocation(xpiFile);
-})();
-
-var { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
-var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
-
-var { getGoogleSessionManager } = ChromeUtils.import(
-  "resource://gdata-provider/modules/gdataSession.jsm"
-);
-var { dateToJSON, JSONToDate, monkeyPatch } = ChromeUtils.import(
-  "resource://gdata-provider/modules/gdataUtils.jsm"
-);
-var { MockRegistrar } = ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
-
-var gServer;
-
-var MockConflictPrompt = {
-  _origFunc: null,
-  overwrite: false,
-  register: function() {
-    if (!this._origFunc) {
-      this._origFunc = cal.provider.promptOverwrite;
-      cal.provider.promptOverwrite = (aMode, aItem) => {
-        return this.overwrite;
-      };
-    }
-  },
-
-  unregister: function() {
-    if (this._origFunc) {
-      cal.provider.promptOverwrite = this._origFunc;
-      this._origFunc = null;
-    }
-  },
-};
-
-function MockAlertsService() {}
-
-MockAlertsService.prototype = {
-  showAlertNotification: function() {},
-  QueryInterface: ChromeUtils.generateQI([Ci.nsIAlertsService]),
-};
-
-function replaceAlertsService() {
-  let originalAlertsServiceCID = MockRegistrar.register(
-    "@mozilla.org/alerts-service;1",
-    MockAlertsService
-  );
-  registerCleanupFunction(() => {
-    MockRegistrar.unregister(originalAlertsServiceCID);
-  });
-}
-
-function GDataServer(calendarId, tasksId) {
-  this.server = new HttpServer();
-  this.calendarId = calendarId;
-  this.tasksId = tasksId;
-
-  let encCalendarId = encodeURIComponent(calendarId);
-  let encTasksId = encodeURIComponent(tasksId);
-
-  let events = "/calendar/v3/calendars/" + encCalendarId + "/events";
-  let tasks = "/tasks/v1/lists/" + encTasksId + "/tasks";
-  let calendarList = "/calendar/v3/users/me/calendarList/" + encCalendarId;
-
-  this.server.registerPathHandler(
-    calendarList,
-    this.router.bind(this, this.calendarListRequest.bind(this))
-  );
-  this.server.registerPathHandler(events, this.router.bind(this, this.eventsRequest.bind(this)));
-  this.server.registerPrefixHandler(
-    events + "/",
-    this.router.bind(this, this.eventsRequest.bind(this))
-  );
-  this.server.registerPathHandler(tasks, this.router.bind(this, this.tasksRequest.bind(this)));
-  this.server.registerPrefixHandler(
-    tasks + "/",
-    this.router.bind(this, this.tasksRequest.bind(this))
-  );
-
-  this.resetRequest();
-
-  let sessionMgr = getGoogleSessionManager();
-  this.session = sessionMgr.getSessionById("xpcshell", true);
-  this.session.oauth = {
-    accessToken: "accessToken",
-    refreshToken: "refreshToken",
-    tokenExpires: Number.MAX_VALUE,
-    connect: function(success, failure, withUi, refresh) {
-      this.accessToken = "accessToken";
-      success();
-    },
-  };
-}
-
-GDataServer.prototype = {
-  items: null,
-
-  get baseUri() {
-    return "http://localhost:" + this.server.identity.primaryPort + "/";
-  },
-
-  start: function() {
-    this.server.start(-1);
-    registerCleanupFunction(() => this.server.stop(() => {}));
-  },
-
-  resetClient: function(client) {
-    this.resetRequest();
-    MockConflictPrompt.unregister();
-    cal.getCalendarManager().unregisterCalendar(client);
-  },
-
-  resetRequest: function() {
-    this.events = [];
-    this.tasks = [];
-    this.nextEtag = null;
-    this.syncs = [];
-    this.nextEventStatus = [];
-
-    this.creator = {
-      email: this.calendarId,
-      self: true,
-      displayName: "Eggs P. Seashell",
-    };
-
-    this.eventsData = {
-      kind: "calendar#events",
-      etag: '"1410880601360000"',
-      nextSyncToken: generateID(),
-      updated: "2014-09-16T15:16:41.360Z",
-      accessRole: "owner",
-      summary: "xpcshell",
-      timeZone: "Europe/Berlin",
-      defaultReminders: [],
-      items: [],
-    };
-
-    this.tasksData = {
-      kind: "tasks#tasks",
-      etag: '"1410880601360000"',
-      items: [],
-    };
-
-    this.calendarListData = {
-      kind: "calendar#calendarListEntry",
-      etag: '"1410084814736000"',
-      id: this.calendarId,
-      summary: "xpcshell",
-      timeZone: "Europe/Berlin",
-      colorId: "17",
-      backgroundColor: "#9a9cff",
-      foregroundColor: "#000000",
-      primary: true,
-      selected: true,
-      accessRole: "owner",
-      defaultReminders: [],
-      notificationSettings: {
-        notifications: [
-          { type: "eventCreation", method: "email" },
-          { type: "eventChange", method: "email" },
-          { type: "eventCancellation", method: "email" },
-        ],
-      },
-    };
-  },
-
-  waitForLoad: function(aCalendar) {
-    return new Promise((resolve, reject) => {
-      let observer = cal.createAdapter(Ci.calIObserver, {
-        onLoad: function() {
-          let uncached = aCalendar.wrappedJSObject.mUncachedCalendar.wrappedJSObject;
-          aCalendar.removeObserver(observer);
-
-          if (Components.isSuccessCode(uncached._lastStatus)) {
-            resolve(aCalendar);
-          } else {
-            reject(uncached._lastMessage);
-          }
-        },
-      });
-      aCalendar.addObserver(observer);
-    });
-  },
-
-  getClient: function() {
-    let uri =
-      "googleapi://xpcshell/" +
-      "?testport=" +
-      this.server.identity.primaryPort +
-      (this.calendarId ? "&calendar=" + encodeURIComponent(this.calendarId) : "") +
-      (this.tasksId ? "&tasks=" + encodeURIComponent(this.tasksId) : "");
-    let calmgr = cal.getCalendarManager();
-    let client = calmgr.createCalendar("gdata", Services.io.newURI(uri));
-    let uclient = client.wrappedJSObject;
-    client.name = "xpcshell";
-
-    // Make sure we catch the last error message in case sync fails
-    monkeyPatch(uclient, "replayChangesOn", (protofunc, aListener) => {
-      protofunc({
-        onResult: function(operation, detail) {
-          uclient._lastStatus = operation.status;
-          uclient._lastMessage = detail;
-          aListener.onResult(operation, detail);
-        },
-      });
-    });
-
-    calmgr.registerCalendar(client);
-    uclient.mThrottleLimits = {};
-    MockConflictPrompt.register();
-
-    let cachedCalendar = calmgr.getCalendarById(client.id);
-    return this.waitForLoad(cachedCalendar);
-  },
-
-  router: function(nextHandler, request, response) {
-    try {
-      let method = request.hasHeader("X-HTTP-Method-Override")
-        ? request.getHeader("X-HTTP-Method-Override")
-        : request.method;
-      let parameters = new Map(request.queryString.split("&").map(part => part.split("=", 2)));
-
-      let body;
-      try {
-        body = JSON.parse(
-          NetUtil.readInputStreamToString(
-            request.bodyInputStream,
-            request.bodyInputStream.available()
-          )
-        );
-      } catch (e) {
-        // Don't bail if json parsing failed.
-      }
-
-      this.lastMethod = method;
-      return nextHandler(request, response, method, parameters, body);
-    } catch (e) {
-      info("Server Error: " + e.fileName + ":" + e.lineNumber + ": " + e + "\n");
-      return null;
-    }
-  },
-
-  calendarListRequest: function(request, response, method, parameters, body) {
-    let data = this.calendarListData;
-    response.write(JSON.stringify(data));
-  },
-
-  eventsRequest: function(request, response, method, parameters, body) {
-    if (method == "GET") {
-      let data = this.eventsData;
-      if (request.hasHeader("timeZone")) {
-        data.timeZone = request.getHeader("timeZone");
-      }
-
-      // The fakeserver doesn't support both pagination and sync tokens
-      // for sake of simplicity.
-      if (this.syncs.length) {
-        let syncToken = parameters.get("syncToken") || this.syncs[0].token;
-        let sync = this.syncs.shift();
-        let nextSyncToken = this.syncs[0] ? this.syncs[0].token : "last";
-
-        if (!sync || syncToken != sync.token) {
-          do_throw("Request in wrong order or not enough syncs");
-        }
-        if (sync.reset) {
-          response.setStatusLine(null, 410, "Gone");
-          return;
-        }
-        data.nextSyncToken = nextSyncToken;
-        data.items = sync.events;
-      } else {
-        this.paginateRequest(parameters, this.events, data);
-      }
-      response.write(JSON.stringify(data));
-    } else if (method == "POST") {
-      // Add an event
-      let isImport = request.path.endsWith("/events/import");
-      let data = this.processAddEvent(body, isImport);
-      this.events.push(data);
-      response.setStatusLine(null, 201, "Created");
-      response.write(JSON.stringify(data));
-    } else if (
-      (method == "PUT" || method == "PATCH") &&
-      request.path.match(/\/events\/([a-z0-9_TZ]+)$/)
-    ) {
-      // Modify an event
-      let eventId = RegExp.$1;
-      this.handleModify(
-        request,
-        response,
-        body,
-        this.events,
-        eventId,
-        this.processModifyEvent.bind(this)
-      );
-    } else if (method == "DELETE" && request.path.match(/\/events\/([a-z0-9_TZ]+)$/)) {
-      let eventId = RegExp.$1;
-      this.handleDelete(request, response, this.events, eventId);
-    }
-  },
-
-  tasksRequest: function(request, response, method, parameters, body) {
-    if (method == "GET") {
-      let data = this.tasksData;
-
-      this.paginateRequest(parameters, this.tasks, data);
-      delete data.nextSyncToken;
-
-      response.write(JSON.stringify(data));
-    } else if (method == "POST") {
-      let data = this.processAddTask(body);
-      this.tasks.push(data);
-      response.setStatusLine(null, 201, "Created");
-      response.write(JSON.stringify(data));
-    } else if (method == "PUT" && request.path.match(/\/tasks\/([A-Za-z0-9]+)$/)) {
-      let taskId = RegExp.$1;
-      this.handleModify(
-        request,
-        response,
-        body,
-        this.tasks,
-        taskId,
-        this.processModifyTask.bind(this)
-      );
-    } else if (method == "DELETE" && request.path.match(/\/tasks\/([A-Za-z0-9]+)$/)) {
-      let taskId = RegExp.$1;
-      this.handleDelete(request, response, this.tasks, taskId);
-    }
-  },
-
-  paginateRequest: function(parameters, items, data) {
-    let maxResults = parameters.has("maxResults") ? parseInt(parameters.get("maxResults"), 10) : 50;
-    let offset = parameters.has("pageToken") ? parseInt(parameters.get("pageToken"), 10) || 0 : 0;
-    let nextOffset = offset + maxResults;
-    if (nextOffset > items.length) {
-      delete data.nextPageToken;
-      data.nextSyncToken = "next-sync-token";
-    } else {
-      delete data.nextSyncToken;
-      data.nextPageToken = nextOffset;
-    }
-
-    data.items = items.slice(offset, offset + maxResults);
-  },
-
-  handleModify: function(request, response, body, items, itemId, modifyFunc) {
-    // Modify an event
-    let [foundIndex, foundItem] = findKey(items, "id", itemId);
-
-    let matchTag = request.hasHeader("If-Match") ? request.getHeader("If-Match") : null;
-
-    if (foundIndex != -1) {
-      if (!matchTag || matchTag == "*" || foundItem.etag == matchTag) {
-        items[foundIndex] = modifyFunc(body, itemId);
-        response.write(JSON.stringify(items[foundIndex]));
-      } else {
-        response.setStatusLine(null, 412, "Precondition Failed");
-      }
-    } else if (matchTag == "*") {
-      let data = modifyFunc(body, itemId);
-      items.push(data);
-      response.write(JSON.stringify(data));
-    } else if (body.recurringEventId) {
-      // Special case for events, won't happen on tasks.  This is an
-      // exception that doesn't exist yet. Allow creation in this case.
-      let [, foundParent] = findKey(items, "id", body.recurringEventId);
-      if (!matchTag || foundParent.etag == matchTag) {
-        let data = modifyFunc(body, itemId);
-        items.push(data);
-        response.write(JSON.stringify(data));
-      } else {
-        response.setStatusLine(null, 412, "Precondition Failed");
-      }
-    } else if (matchTag) {
-      response.setStatusLine(null, 412, "Precondition Failed");
-    } else {
-      response.setStatusLine(null, 404, "Not Found");
-    }
-  },
-
-  handleDelete: function(request, response, items, itemId) {
-    // eslint-disable-next-line array-bracket-spacing
-    let [foundIndex] = findKey(items, "id", itemId);
-
-    let matchTag = request.hasHeader("If-Match") ? request.getHeader("If-Match") : null;
-
-    if (foundIndex != -1) {
-      if (!matchTag || matchTag == "*" || items[foundIndex].etag == matchTag) {
-        items.splice(foundIndex, 1);
-        response.setStatusLine(null, 204, "No Content");
-      } else {
-        response.setStatusLine(null, 412, "Precondition Failed");
-      }
-    } else if (matchTag == "*") {
-      response.setStatusLine(null, 410, "Gone");
-    } else if (matchTag) {
-      response.setStatusLine(null, 412, "Precondition Failed");
-    } else {
-      response.setStatusLine(null, 404, "Not Found");
-    }
-  },
-
-  processAddEvent: function(jsonData, isImport) {
-    jsonData.kind = "calendar#event";
-    jsonData.etag = this.nextEtag || '"' + new Date().getTime() + '"';
-    jsonData.id = generateID();
-    if (!isImport) {
-      jsonData.htmlLink = this.baseUri + "/calendar/event?eid=" + jsonData.id;
-    }
-    if (!isImport || !jsonData.iCalUID) {
-      jsonData.iCalUID = jsonData.id + "@google.com";
-    }
-    if (!isImport || !jsonData.created) {
-      jsonData.created = cal.dtz.toRFC3339(cal.dtz.now());
-    }
-    if (!isImport || !jsonData.updated) {
-      jsonData.updated = cal.dtz.toRFC3339(cal.dtz.now());
-    }
-    if (!isImport || !jsonData.creator) {
-      jsonData.creator = this.creator;
-    }
-    if (!isImport || !jsonData.organizer) {
-      jsonData.organizer = this.creator;
-    }
-    this.nextEtag = null;
-    return jsonData;
-  },
-
-  processModifyEvent: function(jsonData, id) {
-    jsonData.kind = "calendar#event";
-    jsonData.etag = this.nextEtag || '"' + new Date().getTime() + '"';
-    jsonData.updated = cal.dtz.toRFC3339(cal.dtz.now());
-    jsonData.id = id;
-    jsonData.iCalUID = (jsonData.recurringEventId || jsonData.id) + "@google.com";
-    if (!jsonData.creator) {
-      jsonData.creator = this.creator;
-    }
-    if (!jsonData.organizer) {
-      jsonData.organizer = this.creator;
-    }
-
-    this.nextEtag = null;
-    return jsonData;
-  },
-
-  processAddTask: function(jsonData) {
-    jsonData.kind = "tasks#task";
-    jsonData.etag = this.nextEtag || '"' + new Date().getTime() + '"';
-    jsonData.id = generateID();
-    jsonData.position = generateID(); // Not a real position, but we don't really use this at the moment
-    if (!jsonData.status) {
-      jsonData.status = "needsAction";
-    }
-    if (!jsonData.updated) {
-      jsonData.updated = cal.dtz.toRFC3339(cal.dtz.now());
-    }
-
-    this.nextEtag = null;
-    return jsonData;
-  },
-
-  processModifyTask: function(jsonData) {
-    jsonData.kind = "tasks#task";
-    jsonData.etag = this.nextEtag || '"' + new Date().getTime() + '"';
-    jsonData.updated = cal.dtz.toRFC3339(cal.dtz.now());
-    if (!jsonData.status) {
-      jsonData.status = "needsAction";
-    }
-    if (!jsonData.updated) {
-      jsonData.updated = cal.dtz.toRFC3339(cal.dtz.now());
-    }
-
-    this.nextEtag = null;
-    return jsonData;
-  },
-};
-
-function findKey(container, key, searchKey) {
-  let foundIndex = -1;
-  for (let i = 0; i < container.length; i++) {
-    if (container[i][key] == searchKey) {
-      foundIndex = i;
-      break;
-    }
-  }
-
-  let foundItem = foundIndex == -1 ? null : container[foundIndex];
-  return [foundIndex, foundItem];
-}
-
-function generateID() {
-  let chars = "abcdefghijklmnopqrstuvwxyz0123456789";
-  let str = "";
-  for (let i = 26; i; i--) {
-    str += chars[Math.floor(Math.random() * chars.length)];
-  }
-  return str;
-}
-
-function getAllMeta(calendar) {
-  let keys = {},
-    values = {};
-  calendar.getAllMetaData({}, keys, values);
-  return new Map(keys.value.map((k, i) => [k, values.value[i]]));
-}
-
-function run_test() {
-  replaceAlertsService();
-
-  // TODO: make do_calendar_startup to work with this test and replace the startup code here
-  do_get_profile();
-  do_test_pending();
-  cal.getCalendarManager().startup({
-    onResult: function() {
-      gServer = new GDataServer("xpcshell@example.com", "tasksId");
-      gServer.start();
-      cal.getTimezoneService().startup({
-        onResult: function() {
-          run_next_test();
-          do_test_finished();
-        },
-      });
-    },
-  });
-}
-
-add_task(async function test_migrate_cache() {
-  let uriString = "googleapi://xpcshell/?calendar=xpcshell%40example.com";
-  let uri = Services.io.newURI(uriString);
-  let client = cal.getCalendarManager().createCalendar("gdata", uri);
-  let unwrapped = client.wrappedJSObject;
-  let migrateStorageCache = unwrapped.migrateStorageCache.bind(unwrapped);
-
-  monkeyPatch(unwrapped, "resetSync", protofunc => {
-    return Promise.resolve();
-  });
-
-  // No version, should not reset
-  equal(await migrateStorageCache(), false);
-  equal(client.getProperty("cache.version"), 3);
-
-  // Check migrate 1 -> 2
-  unwrapped.CACHE_DB_VERSION = 2;
-  client.setProperty("cache.version", 1);
-  equal(await migrateStorageCache(), true);
-  equal(client.getProperty("cache.version"), 2);
-
-  // Check migrate 2 -> 3 normal calendar
-  unwrapped.CACHE_DB_VERSION = 3;
-  client.setProperty("cache.version", 2);
-  equal(await migrateStorageCache(), false);
-
-  // Check migrate 2 -> 3 birthday calendar
-  unwrapped.CACHE_DB_VERSION = 3;
-  uri = "googleapi://xpcshell/?calendar=%23contacts%40group.v.calendar.google.com";
-  unwrapped.uri = Services.io.newURI(uri);
-  client.setProperty("cache.version", 2);
-  equal(await migrateStorageCache(), true);
-});
-
-add_test(function test_migrate_uri() {
-  function checkMigrate(fromUri, session, calendarId, tasksId) {
-    let uri = Services.io.newURI(fromUri);
-    let client = cal.getCalendarManager().createCalendar("gdata", uri);
-
-    if (session) {
-      let target = (
-        "googleapi://" +
-        session +
-        "/?" +
-        (calendarId ? "&calendar=" + encodeURIComponent(calendarId) : "") +
-        (tasksId ? "&tasks=" + encodeURIComponent(tasksId) : "")
-      ).replace("?&", "?");
-      equal(client.getProperty("uri"), target);
-    } else {
-      equal(client.getProperty("uri"), null);
-    }
-  }
-
-  checkMigrate(
-    "http://www.google.com/calendar/feeds/example%40example.com/public/full",
-    "example@example.com",
-    "example@example.com",
-    null
-  );
-
-  checkMigrate(
-    "webcal://www.google.com/calendar/feeds/example%40example.com/public/full",
-    "example@example.com",
-    "example@example.com",
-    null
-  );
-
-  Services.prefs.setStringPref(
-    "calendar.google.calPrefs.example@example.com.googleUser",
-    "example@example.com"
-  );
-  checkMigrate(
-    "http://www.google.com/calendar/feeds/example%40example.com/public/full",
-    "example@example.com",
-    "example@example.com",
-    "@default"
-  );
-
-  checkMigrate("ehmwtf://www.google.com/calendar/feeds/example%40example.com/public/full");
-  checkMigrate("googleapi://session/?calendar=calendarId&tasksId=tasksId");
-
-  run_next_test();
-});
-
-add_task(async function test_dateToJSON() {
-  function _createDateTime(tzid, offset = 0) {
-    let offsetFrom = offset <= 0 ? "-0" + (offset - 1) : "+0" + (offset - 1) + "00";
-    let offsetTo = "+0" + offset + "00";
-    let ics = [
-      "BEGIN:VCALENDAR",
-      "BEGIN:VTIMEZONE",
-      "TZID:ThirdPartyZone",
-      "BEGIN:STANDARD",
-      "DTSTART:20071104T020000",
-      "RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU;INTERVAL=1",
-      "TZOFFSETFROM:" + offsetFrom,
-      "TZOFFSETTO:" + offsetTo,
-      "TZNAME:TPT",
-      "END:STANDARD",
-      "BEGIN:DAYLIGHT",
-      "DTSTART:20070311T020000",
-      "RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU;INTERVAL=1",
-      "TZOFFSETFROM:" + offsetTo,
-      "TZOFFSETTO:" + offsetFrom,
-      "TZNAME:TPDT",
-      "END:DAYLIGHT",
-      "END:VTIMEZONE",
-      "BEGIN:VEVENT",
-      "UID:123",
-      "DTSTART;TZID=" + tzid + ":20150130T120000",
-      "END:VEVENT",
-      "END:VCALENDAR",
-    ].join("\r\n");
-
-    let parser = Cc["@mozilla.org/calendar/ics-parser;1"].createInstance(Ci.calIIcsParser);
-    parser.parseString(ics);
-    let items = parser.getItems({});
-    return items[0].startDate;
-  }
-
-  let date;
-
-  // no timezone
-  date = _createDateTime(cal.dtz.floating);
-  deepEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00-00:00" });
-
-  // valid non-Olson tz name
-  date = _createDateTime("Eastern Standard Time");
-  deepEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00", timeZone: "America/New_York" });
-
-  // valid continent/city Olson tz
-  date = _createDateTime("America/New_York");
-  deepEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00", timeZone: "America/New_York" });
-
-  // valid continent/region/city Olson tz
-  date = _createDateTime("America/Argentina/Buenos_Aires");
-  deepEqual(dateToJSON(date), {
-    dateTime: "2015-01-30T12:00:00",
-    timeZone: "America/Argentina/Buenos_Aires",
-  });
-
-  // ical.js and libical currently have slightly different timezone handling.
-  if (Services.prefs.getBoolPref("calendar.icaljs", false)) {
-    // unknown but formal valid Olson tz. ical.js assumes floating
-    date = _createDateTime("Unknown/Olson/Timezone");
-    deepEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00-00:00" });
-
-    // Etc with offset. ical.js doesn't understand third party zones and uses floating
-    date = _createDateTime("ThirdPartyZone", 5);
-    deepEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00-00:00" });
-
-    // Etc with zero offset. ical.js doesn't understand third party zones and uses floating
-    date = _createDateTime("ThirdPartyZone", 0);
-    deepEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00-00:00" });
-  } else {
-    // This causes an assertion failure.
-    if (!mozinfo.debug) {
-      // unknown but formal valid Olson tz
-      date = _createDateTime("Unknown/Olson/Timezone");
-      deepEqual(dateToJSON(date), {
-        dateTime: "2015-01-30T12:00:00",
-        timeZone: "Unknown/Olson/Timezone",
-      });
-    }
-
-    // Etc with offset
-    date = _createDateTime("ThirdPartyZone", 5);
-    deepEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00", timeZone: "Etc/GMT-5" });
-
-    // Etc with zero offset
-    date = _createDateTime("ThirdPartyZone", 0);
-    deepEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00Z", timeZone: "UTC" });
-  }
-
-  // This causes an assertion failure.
-  if (!mozinfo.debug) {
-    // invalid non-Olson tz
-    date = _createDateTime("InvalidTimeZone");
-    notEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00", timeZone: "InvalidTimeZone" });
-  }
-
-  // Zone with 0 offset but not UTC
-  date = _createDateTime("Europe/London");
-  deepEqual(dateToJSON(date), { dateTime: "2015-01-30T12:00:00", timeZone: "Europe/London" });
-
-  // date only
-  date.isDate = true;
-  deepEqual(dateToJSON(date), { date: "2015-01-30" });
-});
-
-add_task(async function test_JSONToDate() {
-  function convert(aEntry, aTimezone = "Europe/Berlin") {
-    let tzs = cal.getTimezoneService();
-    let calendarTz = tzs.getTimezone(aTimezone);
-    let date = JSONToDate(aEntry, calendarTz);
-    return date ? date.icalString + " in " + date.timezone.tzid : null;
-  }
-
-  // A date, using the passed in default timezone
-  equal(convert({ date: "2015-01-02" }), "20150102 in Europe/Berlin");
-
-  // A date, with a timezone that has zero offset
-  equal(convert({ date: "2015-01-02", timeZone: "Africa/Accra" }), "20150102 in Africa/Accra");
-
-  // A date, using a timezone with a nonzero offset that is not the default timezone
-  equal(convert({ date: "2015-01-02", timeZone: "Asia/Baku" }), "20150102 in Asia/Baku");
-
-  // UTC date with and without timezone specified, with a calendar in a timezone without DST
-  equal(
-    convert({ dateTime: "2015-01-02T03:04:05Z", timeZone: "UTC" }, "Africa/Accra"),
-    "20150102T030405Z in UTC"
-  );
-  equal(
-    convert({ dateTime: "2015-01-02T03:04:05Z" }, "Africa/Accra"),
-    "20150102T030405 in Africa/Accra"
-  );
-
-  // An America/Los_Angeles date-time viewed in Europe/Berlin
-  equal(
-    convert({ dateTime: "2015-12-01T21:13:14+01:00", timeZone: "America/Los_Angeles" }),
-    "20151201T121314 in America/Los_Angeles"
-  );
-  equal(
-    convert({ dateTime: "2015-07-01T21:13:14+02:00", timeZone: "America/Los_Angeles" }),
-    "20150701T121314 in America/Los_Angeles"
-  );
-
-  // A timezone that is sometimes in GMT, get ready for: Europe/London!
-  equal(
-    convert({ dateTime: "2015-12-01T12:13:14Z", timeZone: "Europe/London" }, "Europe/London"),
-    "20151201T121314 in Europe/London"
-  );
-  equal(
-    convert({ dateTime: "2015-07-01T12:13:14+01:00", timeZone: "Europe/London" }, "Europe/London"),
-    "20150701T121314 in Europe/London"
-  );
-
-  // An event in Los Angeles, with a calendar set to Asia/Baku
-  equal(
-    convert(
-      { dateTime: "2015-07-01T12:13:14+05:00", timeZone: "America/Los_Angeles" },
-      "Asia/Baku"
-    ),
-    "20150701T001314 in America/Los_Angeles"
-  );
-  equal(
-    convert(
-      { dateTime: "2015-12-01T12:13:14+04:00", timeZone: "America/Los_Angeles" },
-      "Asia/Baku"
-    ),
-    "20151201T001314 in America/Los_Angeles"
-  );
-
-  // An event without specified timezone, with a calendar set to Asia/Baku
-  equal(
-    convert({ dateTime: "2015-07-01T12:13:14+04:00" }, "Asia/Baku"),
-    "20150701T121314 in Asia/Baku"
-  );
-
-  // An offset matching the passed in calendar timezone. This should NOT be Africa/Algiers
-  equal(convert({ dateTime: "2015-01-02T03:04:05+01:00" }), "20150102T030405 in Europe/Berlin");
-
-  // An offset that doesn't match the calendar timezone, will use the first timezone in that offset
-  info(
-    "The following warning is expected: 2015-01-02T03:04:05+04:00 does not match timezone offset for Europe/Berlin"
-  );
-  equal(convert({ dateTime: "2015-01-02T03:04:05+05:00" }), "20150102T030405 in Antarctica/Mawson");
-});
-
-add_task(async function test_organizerCN() {
-  gServer.events = [];
-  let client = await gServer.getClient();
-  equal(client.getProperty("organizerCN"), null);
-  gServer.resetClient(client);
-
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"2299601498276000"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-    },
-  ];
-  client = await gServer.getClient();
-  equal(client.getProperty("organizerCN"), gServer.creator.displayName);
-  gServer.resetClient(client);
-});
-
-add_task(async function test_always_readOnly() {
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"2299601498276000"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-    },
-  ];
-  gServer.calendarListData.accessRole = "freeBusyReader";
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client);
-  ok(client.readOnly);
-  client.readOnly = false;
-  ok(client.readOnly);
-
-  let items = await pclient.getAllItems();
-  equal(items.length, 1);
-  notEqual(items[0].title, "New Event");
-  gServer.resetClient(client);
-
-  gServer.calendarListData.accessRole = "reader";
-  client = await gServer.getClient();
-  ok(client.readOnly);
-  client.readOnly = false;
-  ok(client.readOnly);
-  gServer.resetClient(client);
-});
-
-add_task(async function test_reset_sync() {
-  gServer.tasks = [
-    {
-      kind: "tasks#task",
-      id: "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU",
-      etag: '"Lck7VNWFJuXdzMtOmrYPx0KFV2s/LTIwNjA4MDcyNDM"',
-      title: "New Task",
-      updated: "2014-09-08T16:30:27.000Z",
-      selfLink:
-        gServer.baseUri +
-        "/tasks/v1/lists/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDow/tasks/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU",
-      position: "00000000000000130998",
-      status: "needsAction",
-    },
-    {
-      kind: "tasks#task",
-      id: "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo5OTU0Mjk2MzQ",
-      etag: '"Lck7VNWFJuXdzMtOmrYPx0KFV2s/LTQyNTY0MjUwOQ"',
-      title: "New Task 2",
-      updated: "2014-09-08T16:30:27.000Z",
-      selfLink:
-        gServer.baseUri +
-        "/tasks/v1/lists/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDow/tasks/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo5OTU0Mjk2MzQ",
-      position: "00000000000000130993",
-      status: "needsAction",
-    },
-  ];
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"1"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-    },
-    {
-      kind: "calendar#event",
-      etag: '"2"',
-      id: "fepf8uf6n7n04w7feukucs9n8e",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event 2",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "fepf8uf6n7n04w7feukucs9n8e@google.com",
-    },
-  ];
-  let client = await gServer.getClient();
-  let uncached = client.wrappedJSObject.mUncachedCalendar.wrappedJSObject;
-  let pclient = cal.async.promisifyCalendar(client);
-
-  let items = await pclient.getAllItems();
-  equal(items.length, 4);
-
-  notEqual(client.getProperty("syncToken.events"), "");
-  notEqual(client.getProperty("lastUpdated.tasks"), "");
-
-  await uncached.resetSync();
-  items = await pclient.getAllItems();
-  equal(items.length, 0);
-
-  equal(client.getProperty("syncToken.events"), "");
-  equal(client.getProperty("lastUpdated.tasks"), "");
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_basicItems() {
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"2299601498276000"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      status: "confirmed",
-      htmlLink: gServer.baseUri + "/calendar/event?eid=eventhash",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event",
-      description: "description",
-      location: "Hard Drive",
-      colorId: 17,
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      transparency: "transparent",
-      visibility: "private",
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-      sequence: 1,
-      reminders: {
-        useDefault: false,
-        overrides: [
-          {
-            method: "email",
-            minutes: 20,
-          },
-        ],
-      },
-      attendees: [
-        {
-          displayName: "attendee name",
-          email: "attendee@example.com",
-          optional: true,
-          responseStatus: "tentative",
-        },
-      ],
-
-      extendedProperties: {
-        shared: { "X-MOZ-CATEGORIES": "foo,bar" },
-        private: {
-          "X-MOZ-LASTACK": "2014-01-01T01:01:01Z",
-          "X-MOZ-SNOOZE-TIME": "2014-01-01T02:02:02Z",
-        },
-      },
-    },
-  ];
-
-  gServer.tasks = [
-    {
-      kind: "tasks#task",
-      id: "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU",
-      etag: '"Lck7VNWFJuXdzMtOmrYPx0KFV2s/LTIwNjA4MDcyNDM"',
-      title: "New Task",
-      updated: "2014-09-08T16:30:27.000Z",
-      selfLink:
-        gServer.baseUri +
-        "/tasks/v1/lists/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDow/tasks/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU",
-      position: "00000000000000130998",
-      status: "completed",
-      due: "2014-09-04T00:00:00.000Z",
-      completed: "2014-09-01T17:00:00.000Z",
-      notes: "description",
-      parent: "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo4MDIzOTU2NDc",
-      links: [
-        {
-          link: "mailto:something@example.com",
-          description: "link description",
-          type: "email",
-        },
-      ],
-    },
-  ];
-
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client);
-
-  let items = await pclient.getAllItems();
-  equal(items.length, 2);
-
-  let event = cal.item.isEvent(items[0]) ? items[0] : items[1];
-  equal(event.id, "go6ijb0b46hlpbu4eeu92njevo@google.com");
-  equal(event.getProperty("STATUS"), "CONFIRMED");
-  equal(event.getProperty("URL"), gServer.baseUri + "/calendar/event?eid=eventhash");
-  equal(event.getProperty("CREATED").icalString, "20060608T210452Z");
-  equal(event.getProperty("LAST-MODIFIED").icalString, "20060608T210549Z");
-  equal(event.title, "New Event");
-  equal(event.getProperty("DESCRIPTION"), "description");
-  equal(event.getProperty("LOCATION"), "Hard Drive");
-  equal(event.organizer.id, "mailto:xpcshell@example.com");
-  equal(event.organizer.commonName, "Eggs P. Seashell");
-  ok(event.organizer.isOrganizer);
-  equal(event.startDate.icalString, "20060610T180000");
-  equal(event.startDate.timezone.tzid, "Europe/Berlin");
-  equal(event.endDate.icalString, "20060610T200000");
-  equal(event.getProperty("TRANSP"), "TRANSPARENT");
-  equal(event.privacy, "PRIVATE");
-  equal(event.getProperty("SEQUENCE"), 1);
-  let alarms = event.getAlarms({});
-  equal(alarms.length, 1);
-  equal(alarms[0].action, "EMAIL");
-  equal(alarms[0].related, alarms[0].ALARM_RELATED_START);
-  equal(alarms[0].offset.icalString, "-PT20M");
-  equal(alarms[0].getProperty("X-DEFAULT-ALARM"), null);
-  let attendees = event.getAttendees({});
-  equal(attendees.length, 1);
-  equal(attendees[0].id, "mailto:attendee@example.com");
-  equal(attendees[0].commonName, "attendee name");
-  equal(attendees[0].role, "OPT-PARTICIPANT");
-  equal(attendees[0].participationStatus, "TENTATIVE");
-  equal(event.getCategories({}), "foo,bar");
-  equal(event.alarmLastAck.icalString, "20140101T010101Z");
-  equal(event.getProperty("X-MOZ-SNOOZE-TIME"), "20140101T020202Z");
-
-  let task = cal.item.isToDo(items[0]) ? items[0] : items[1];
-  equal(task.id, "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU");
-  equal(task.title, "New Task");
-  equal(task.getProperty("LAST-MODIFIED").icalString, "20140908T163027Z");
-  equal(task.getProperty("X-GOOGLE-SORTKEY"), "00000000000000130998");
-  ok(task.isCompleted);
-  equal(task.dueDate.icalString, "20140904");
-  equal(task.completedDate.icalString, "20140901T170000Z");
-  equal(task.getProperty("DESCRIPTION"), "description");
-  let relations = task.getRelations({});
-  equal(relations.length, 1);
-  equal(relations[0].relType, "PARENT");
-  equal(relations[0].relId, "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo4MDIzOTU2NDc");
-  let attachments = task.getAttachments({});
-  equal(attachments.length, 1);
-  equal(attachments[0].uri.spec, "mailto:something@example.com");
-  equal(attachments[0].getParameter("X-GOOGLE-TYPE"), "email");
-  equal(attachments[0].getParameter("FILENAME"), "link description");
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_addModifyDeleteItem() {
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-  equal(gServer.events.length, 0);
-  equal(gServer.tasks.length, 0);
-
-  let event = cal.createEvent(
-    [
-      "BEGIN:VEVENT",
-      "CREATED:20060608T210452Z",
-      "LAST-MODIFIED:20060608T210549Z",
-      "DTSTAMP:20060608T210549Z",
-      "SUMMARY:New Event",
-      "STATUS:CONFIRMED",
-      "ORGANIZER;CN=Eggs P. Seashell:mailto:xpcshell@example.com",
-      "ATTENDEE;CN=attendee name;PARTSTAT=TENTATIVE;CUTYPE=INDIVIDUAL;ROLE=OPT-PA",
-      " RTICIPANT:mailto:attendee@example.com",
-      "CATEGORIES:foo",
-      "CATEGORIES:bar",
-      "X-MOZ-LASTACK:20140101T010101Z",
-      "DTSTART:20060610T180000Z",
-      "DTEND:20060610T200000Z",
-      "CLASS:PRIVATE",
-      "URL:http://eventlocation",
-      "DESCRIPTION:description",
-      "LOCATION:Hard Drive",
-      "TRANSP:TRANSPARENT",
-      "SEQUENCE:1",
-      "X-MOZ-SNOOZE-TIME:20140101T020202Z",
-      "BEGIN:VALARM",
-      "ACTION:EMAIL",
-      "TRIGGER;VALUE=DURATION:-PT20M",
-      "SUMMARY:Default Mozilla Summary",
-      "DESCRIPTION:Default Mozilla Description",
-      "END:VALARM",
-      "END:VEVENT",
-    ].join("\r\n")
-  );
-
-  let task = cal.createTodo(
-    [
-      "BEGIN:VTODO",
-      "SUMMARY:New Task",
-      "DESCRIPTION:description",
-      "X-SORTKEY:00000000000000130998",
-      "STATUS:COMPLETED",
-      "DUE;VALUE=DATE:20140904",
-      "COMPLETED:20140901T170000Z",
-      "RELATED-TO;RELTYPE=PARENT:MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo4MDIzOTU2NDc",
-      'ATTACH;FILENAME="link description";X-GOOGLE-TYPE=email:mailto:something@example.com',
-      "END:VTODO",
-    ].join("\r\n")
-  );
-
-  // Add an event
-  let addedEvent = await pclient.adoptItem(event);
-  notEqual(addedEvent.id, null);
-  equal(addedEvent.organizer.id, "mailto:xpcshell@example.com");
-
-  let items = await pclient.getAllItems();
-  equal(items.length, 1);
-  equal(items[0].id, addedEvent.id);
-  equal(items[0].organizer.id, "mailto:xpcshell@example.com");
-
-  equal(gServer.events.length, 1);
-  equal(gServer.tasks.length, 0);
-
-  // Add a task
-  let addedTask = await pclient.adoptItem(task);
-  notEqual(addedTask.id, null);
-
-  items = await pclient.getAllItems();
-  equal(items.length, 2);
-  equal(items[1].id, addedTask.id);
-
-  equal(gServer.events.length, 1);
-  equal(gServer.tasks.length, 1);
-
-  // Modify an event
-  let newEvent = items[0].clone();
-  newEvent.title = "changed";
-
-  let modifiedEvent = await pclient.modifyItem(newEvent, items[0]);
-  equal(modifiedEvent.title, "changed");
-  notEqual(modifiedEvent.getProperty("LAST-MODIFIED"), addedEvent.getProperty("LAST-MODIFIED"));
-  items = await pclient.getAllItems();
-  equal(items.length, 2);
-  equal(items[0].title, "changed");
-  equal(items[0].id, addedEvent.id);
-  equal(items[0].getProperty("LAST-MODIFIED"), modifiedEvent.getProperty("LAST-MODIFIED"));
-  equal(gServer.events.length, 1);
-  equal(gServer.tasks.length, 1);
-
-  // Modify a task
-  let newTask = items[1].clone();
-  newTask.title = "changed";
-
-  let modifiedTask = await pclient.modifyItem(newTask, items[1]);
-  equal(modifiedTask.title, "changed");
-  notEqual(modifiedTask.getProperty("LAST-MODIFIED"), addedTask.getProperty("LAST-MODIFIED"));
-  items = await pclient.getAllItems();
-  equal(items.length, 2);
-  equal(items[1].title, "changed");
-  equal(items[1].id, addedTask.id);
-  equal(items[1].getProperty("LAST-MODIFIED"), modifiedTask.getProperty("LAST-MODIFIED"));
-  equal(gServer.events.length, 1);
-  equal(gServer.tasks.length, 1);
-
-  // Delete an event
-  await pclient.deleteItem(modifiedEvent);
-  items = await pclient.getAllItems();
-  equal(items.length, 1);
-  equal(gServer.events.length, 0);
-  equal(gServer.tasks.length, 1);
-
-  // Delete a task
-  await pclient.deleteItem(modifiedTask);
-  items = await pclient.getAllItems();
-  equal(items.length, 0);
-  equal(gServer.events.length, 0);
-  equal(gServer.tasks.length, 0);
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_recurring_event() {
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-
-  let event = cal.createEvent(
-    [
-      "BEGIN:VEVENT",
-      "SUMMARY:Recurring Event",
-      "DTSTART:20060610T180000Z",
-      "DTEND:20060610T200000Z",
-      "RRULE:FREQ=WEEKLY",
-      "END:VEVENT",
-    ].join("\r\n")
-  );
-
-  event = await pclient.addItem(event);
-  equal(gServer.events.length, 1);
-  equal(gServer.events[0].recurrence.length, 1);
-  equal(gServer.events[0].recurrence[0], "RRULE:FREQ=WEEKLY");
-
-  let occ = event.recurrenceInfo.getNextOccurrence(event.startDate);
-  let changedOcc = occ.clone();
-  changedOcc.title = "changed";
-  event.recurrenceInfo.modifyException(occ, true);
-
-  event = await pclient.modifyItem(changedOcc, occ);
-  occ = event.recurrenceInfo.getNextOccurrence(event.startDate);
-  equal(occ.title, "changed");
-  equal(gServer.events.length, 2);
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_recurring_exception() {
-  gServer.syncs = [
-    {
-      token: "1",
-      events: [
-        {
-          kind: "calendar#event",
-          etag: '"1"',
-          id: "go6ijb0b46hlpbu4eeu92njevo",
-          created: "2006-06-08T21:04:52.000Z",
-          updated: "2006-06-08T21:05:49.138Z",
-          summary: "New Event",
-          creator: gServer.creator,
-          organizer: gServer.creator,
-          start: { dateTime: "2006-06-10T18:00:00+02:00" },
-          end: { dateTime: "2006-06-10T20:00:00+02:00" },
-          iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-          recurrence: ["RRULE:FREQ=WEEKLY"],
-        },
-        {
-          kind: "calendar#event",
-          etag: '"2"',
-          id: "go6ijb0b46hlpbu4eeu92njevo_20060617T160000Z",
-          summary: "New Event changed",
-          start: { dateTime: "2006-06-17T18:00:00+02:00" },
-          end: { dateTime: "2006-06-17T20:00:00+02:00" },
-          recurringEventId: "go6ijb0b46hlpbu4eeu92njevo",
-          originalStartTime: { dateTime: "2006-06-17T18:00:00+02:00" },
-        },
-      ],
-    },
-    {
-      // This sync run tests an exception where the master item is not part
-      // of the item stream.
-      token: "2",
-      events: [
-        {
-          kind: "calendar#event",
-          etag: '"3"',
-          id: "go6ijb0b46hlpbu4eeu92njevo_20060617T160000Z",
-          summary: "New Event changed",
-          start: { dateTime: "2006-06-17T18:00:00+02:00" },
-          end: { dateTime: "2006-06-17T20:00:00+02:00" },
-          status: "cancelled",
-          recurringEventId: "go6ijb0b46hlpbu4eeu92njevo",
-          originalStartTime: { dateTime: "2006-06-17T18:00:00+02:00" },
-        },
-      ],
-    },
-  ];
-
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-
-  let items = await pclient.getAllItems();
-  equal(items.length, 1);
-
-  let exIds = items[0].recurrenceInfo.getExceptionIds({});
-  equal(exIds.length, 1);
-
-  let ex = items[0].recurrenceInfo.getExceptionFor(exIds[0]);
-  equal(ex.title, "New Event changed");
-
-  client.refresh();
-  await gServer.waitForLoad(client);
-
-  items = await pclient.getAllItems();
-  equal(items.length, 1);
-
-  exIds = items[0].recurrenceInfo.getExceptionIds({});
-  equal(exIds.length, 0);
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_recurring_cancelled_exception() {
-  gServer.syncs = [
-    {
-      token: "1",
-      events: [
-        {
-          kind: "calendar#event",
-          etag: '"1"',
-          id: "go6ijb0b46hlpbu4eeu92njevo",
-          status: "cancelled",
-        },
-        {
-          kind: "calendar#event",
-          etag: '"2"',
-          id: "go6ijb0b46hlpbu4eeu92njevo_20060617T160000Z",
-          status: "cancelled",
-          recurringEventId: "go6ijb0b46hlpbu4eeu92njevo",
-          originalStartTime: { dateTime: "2006-06-17T18:00:00+02:00" },
-        },
-      ],
-    },
-  ];
-
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-
-  let items = await pclient.getAllItems();
-  equal(items.length, 0);
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_import_invitation() {
-  Services.prefs.setBoolPref("calendar.google.enableAttendees", true);
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-  let event = cal.createEvent(
-    [
-      "BEGIN:VEVENT",
-      "UID:xpcshell-import",
-      "CREATED:20060608T210452Z",
-      "LAST-MODIFIED:20060608T210549Z",
-      "DTSTAMP:20060608T210549Z",
-      "SUMMARY:New Event",
-      "STATUS:CONFIRMED",
-      "ORGANIZER;CN=Omlettte B. Clam:mailto:ombclam@example.com",
-      "ATTENDEE;CN=Omlettte B. Clam;PARTSTAT=ACCEPTED;CUTYPE=INDIVIDUAL;",
-      " ROLE=REQ-PARTICIPANT:mailto:ombclam@example.com",
-      "ATTENDEE;CN=Eggs P. Seashell;PARTSTAT=TENTATIVE;CUTYPE=INDIVIDUAL;",
-      " ROLE=REQ-PARTICIPANT:mailto:xpcshell@example.com",
-      "DTSTART:20060610T180000Z",
-      "DTEND:20060610T200000Z",
-      "SEQUENCE:1",
-      "END:VEVENT",
-    ].join("\r\n")
-  );
-
-  let addedItem = await pclient.adoptItem(event);
-  equal(gServer.events.length, 1);
-  equal(addedItem.icalString, event.icalString);
-  gServer.resetClient(client);
-  Services.prefs.setBoolPref("calendar.google.enableAttendees", false);
-});
-
-add_task(async function test_modify_invitation() {
-  Services.prefs.setBoolPref("calendar.google.enableAttendees", true);
-  let organizer = {
-    displayName: "organizer name",
-    email: "organizer@example.com",
-    organizer: true,
-    responseStatus: "tentative",
-  };
-  let attendee = Object.assign({}, gServer.creator);
-  attendee.responseStatus = "needsAction";
-
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"2299601498276000"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      status: "confirmed",
-      htmlLink: gServer.baseUri + "/calendar/event?eid=eventhash",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event",
-      description: "description",
-      location: "Hard Drive",
-      colorId: 17,
-      creator: organizer,
-      organizer: organizer,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      transparency: "transparent",
-      visibility: "private",
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-      sequence: 1,
-      attendees: [organizer, attendee],
-    },
-  ];
-
-  // Case #1: User is attendee
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-
-  let items = await pclient.getAllItems();
-  equal(items.length, 1);
-
-  let item = items[0];
-  let att = cal.itip.getInvitedAttendee(item);
-  let newItem = item.clone();
-
-  notEqual(att, null);
-  equal(att.id, "mailto:" + attendee.email);
-  equal(att.participationStatus, "NEEDS-ACTION");
-
-  newItem.removeAttendee(att);
-  att = att.clone();
-  att.participationStatus = "ACCEPTED";
-  newItem.addAttendee(att);
-
-  await pclient.modifyItem(newItem, items[0]);
-  equal(gServer.lastMethod, "PATCH");
-
-  // Case #2: User is organizer
-  let events = gServer.events;
-  gServer.resetClient(client);
-  gServer.events = events;
-
-  organizer = Object.assign({}, gServer.creator);
-  organizer.responseStatus = "accepted";
-  organizer.organizer = true;
-  attendee = {
-    displayName: "attendee name",
-    email: "attendee@example.com",
-    responseStatus: "tentative",
-  };
-
-  gServer.events[0].organizer = gServer.creator;
-  gServer.events[0].creator = gServer.creator;
-  gServer.events[0].attendees = [organizer, attendee];
-
-  client = await gServer.getClient();
-  pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-
-  items = await pclient.getAllItems();
-  equal(items.length, 1);
-
-  item = items[0];
-  let org = item.getAttendeeById("mailto:" + organizer.email);
-  newItem = item.clone();
-
-  notEqual(org, null);
-  equal(org.id, "mailto:" + organizer.email);
-  equal(org.participationStatus, "ACCEPTED");
-
-  newItem.removeAttendee(org);
-  org = org.clone();
-  org.participationStatus = "TENTATIVE";
-  newItem.addAttendee(org);
-
-  modifiedItem = await pclient.modifyItem(newItem, items[0]);
-  equal(gServer.lastMethod, "PUT");
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_metadata() {
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"1"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-    },
-  ];
-  gServer.tasks = [
-    {
-      kind: "tasks#task",
-      id: "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU",
-      etag: '"2"',
-      title: "New Task",
-      updated: "2014-09-08T16:30:27.000Z",
-      selfLink:
-        gServer.baseUri +
-        "/tasks/v1/lists/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDow/tasks/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU",
-      notes: "description",
-    },
-  ];
-
-  let client = await gServer.getClient();
-  let offline = client.wrappedJSObject.mCachedCalendar;
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-
-  // Check initial metadata
-  let items = await pclient.getAllItems();
-  let meta = getAllMeta(offline);
-  let [event, task] = items;
-  ok(cal.item.isEvent(event));
-  ok(cal.item.isToDo(task));
-  equal(meta.size, 2);
-  equal(meta.get(event.hashId), ['"1"', "go6ijb0b46hlpbu4eeu92njevo", false].join("\u001A"));
-  equal(
-    meta.get(task.hashId),
-    ['"2"', "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU", false].join("\u001A")
-  );
-
-  // Modify an event
-  gServer.nextEtag = '"3"';
-  let newEvent = event.clone();
-  newEvent.title = "changed";
-  await pclient.modifyItem(newEvent, event);
-
-  items = await pclient.getAllItems();
-  meta = getAllMeta(offline);
-  [event, task] = items;
-  ok(cal.item.isEvent(event));
-  ok(cal.item.isToDo(task));
-  equal(meta.size, 2);
-  equal(meta.get(event.hashId), ['"3"', "go6ijb0b46hlpbu4eeu92njevo", false].join("\u001A"));
-  equal(
-    meta.get(task.hashId),
-    ['"2"', "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU", false].join("\u001A")
-  );
-
-  // Modify a task
-  gServer.nextEtag = '"4"';
-  let newTask = task.clone();
-  newTask.title = "changed";
-  await pclient.modifyItem(newTask, task);
-
-  items = await pclient.getAllItems();
-  meta = getAllMeta(offline);
-  [event, task] = items;
-  equal(meta.size, 2);
-  equal(meta.get(event.hashId), ['"3"', "go6ijb0b46hlpbu4eeu92njevo", false].join("\u001A"));
-  equal(
-    meta.get(task.hashId),
-    ['"4"', "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU", false].join("\u001A")
-  );
-
-  // Delete an event
-  await pclient.deleteItem(event);
-  meta = getAllMeta(offline);
-  equal(meta.size, 1);
-  equal(
-    meta.get(task.hashId),
-    ['"4"', "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU", false].join("\u001A")
-  );
-
-  // Delete a task
-  await pclient.deleteItem(task);
-  meta = getAllMeta(offline);
-  equal(meta.size, 0);
-
-  // Add an event
-  gServer.nextEtag = '"6"';
-  newEvent = await pclient.addItem(event);
-  meta = getAllMeta(offline);
-  equal(meta.size, 1);
-  equal(gServer.events.length, 1);
-  equal(meta.get(newEvent.hashId), ['"6"', gServer.events[0].id, false].join("\u001A"));
-
-  // Add a task
-  gServer.nextEtag = '"7"';
-  newTask = await pclient.addItem(task);
-  meta = getAllMeta(offline);
-  equal(meta.size, 2);
-  equal(gServer.events.length, 1);
-  equal(gServer.tasks.length, 1);
-  equal(meta.get(newEvent.hashId), ['"6"', gServer.events[0].id, false].join("\u001A"));
-  equal(meta.get(newTask.hashId), ['"7"', gServer.tasks[0].id, false].join("\u001A"));
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_metadata_recurring() {
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"1"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-      recurrence: ["RRULE:FREQ=WEEKLY"],
-    },
-    {
-      kind: "calendar#event",
-      etag: '"2"',
-      id: "go6ijb0b46hlpbu4eeu92njevo_20060610T160000Z",
-      summary: "New Event changed",
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      recurringEventId: "go6ijb0b46hlpbu4eeu92njevo",
-      originalStartTime: { dateTime: "2006-06-10T18:00:00+02:00" },
-    },
-    {
-      kind: "calendar#event",
-      etag: '"3"',
-      id: "go6ijb0b46hlpbu4eeu92njevo_20060617T160000Z",
-      summary: "New Event next week",
-      start: { dateTime: "2006-06-17T18:00:00+02:00" },
-      end: { dateTime: "2006-06-17T20:00:00+02:00" },
-      recurringEventId: "go6ijb0b46hlpbu4eeu92njevo",
-      originalStartTime: { dateTime: "2006-06-17T18:00:00+02:00" },
-    },
-  ];
-
-  let client = await gServer.getClient();
-  let offline = client.wrappedJSObject.mCachedCalendar;
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-  let items = await pclient.getAllItems();
-
-  let meta = getAllMeta(offline);
-  equal(meta.size, 3);
-  equal(meta.get(items[0].hashId), ['"1"', "go6ijb0b46hlpbu4eeu92njevo", false].join("\u001A"));
-
-  // The exception metadata should also exist
-  let exIds = items[0].recurrenceInfo.getExceptionIds({});
-  equal(exIds.length, 2);
-  let ex = items[0].recurrenceInfo.getExceptionFor(exIds[0]);
-  equal(
-    meta.get(ex.hashId),
-    ['"2"', "go6ijb0b46hlpbu4eeu92njevo_20060610T160000Z", false].join("\u001A")
-  );
-
-  // Changing an exception should retain the metadata entries
-  let newEx = ex.clone();
-  newEx.title = "New Event changed again";
-  gServer.nextEtag = '"4"';
-  await pclient.modifyItem(newEx, ex);
-  meta = getAllMeta(offline);
-  equal(meta.size, 3);
-  equal(
-    meta.get(newEx.hashId),
-    ['"4"', "go6ijb0b46hlpbu4eeu92njevo_20060610T160000Z", false].join("\u001A")
-  );
-
-  // Deleting an exception should delete the metadata, as it turns into an EXDATE
-  let newItem = items[0].clone();
-  newItem.recurrenceInfo.removeOccurrenceAt(exIds[0]);
-  await pclient.modifyItem(newItem, items[0]);
-
-  meta = getAllMeta(offline);
-  equal(meta.size, 2);
-
-  // Deleting the master item should remove all metadata entries
-  await pclient.deleteItem(items[0]);
-  meta = getAllMeta(offline);
-  equal(meta.size, 0);
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_conflict_modify() {
-  // TODO task/event conflicts are handled in the same way so I'm going to
-  // skip adding tests for tasks here, but it probably wouldn't hurt to
-  // create them at some point.
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"1"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-    },
-  ];
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-  let item = (await pclient.getAllItems())[0];
-
-  // Case #1: Modified on server, modify locally, overwrite conflict
-  MockConflictPrompt.overwrite = true;
-  let newItem = item.clone();
-  newItem.title = "local change";
-  gServer.events[0].etag = '"2"';
-  gServer.events[0].summary = "remote change";
-  let modifiedItem = await pclient.modifyItem(newItem, item);
-  item = (await pclient.getAllItems())[0];
-  equal(gServer.events[0].summary, "local change");
-  notEqual(gServer.events[0].etag, '"2"');
-  equal(item.title, "local change");
-  equal(modifiedItem.title, "local change");
-  equal(gServer.events.length, 1);
-
-  // Case #2: Modified on server, modify locally, don't overwrite conflict
-  MockConflictPrompt.overwrite = false;
-  gServer.events[0].etag = '"3"';
-  gServer.events[0].summary = "remote change";
-  try {
-    modifiedItem = await pclient.modifyItem(newItem, item);
-    do_throw("Expected modifyItem to be cancelled");
-  } catch (e) {
-    // Swallow cancelling the request
-    if (e != Ci.calIErrors.OPERATION_CANCELLED) {
-      throw e;
-    }
-  }
-
-  await gServer.waitForLoad(client);
-
-  item = (await pclient.getAllItems())[0];
-  equal(gServer.events[0].summary, "remote change");
-  equal(gServer.events[0].etag, '"3"');
-  equal(item.title, "remote change");
-
-  // Case #3: Modified on server, delete locally, don't overwrite conflict
-  MockConflictPrompt.overwrite = false;
-  gServer.events[0].etag = '"4"';
-  gServer.events[0].summary = "remote change";
-  try {
-    await pclient.deleteItem(item);
-    do_throw("Expected deleteItem to be cancelled");
-  } catch (e) {
-    // Swallow cancelling the request
-    if (e != Ci.calIErrors.OPERATION_CANCELLED) {
-      throw e;
-    }
-  }
-
-  await gServer.waitForLoad(client);
-
-  item = (await pclient.getAllItems())[0];
-  equal(gServer.events[0].summary, "remote change");
-  equal(gServer.events[0].etag, '"4"');
-  equal(item.title, "remote change");
-
-  // Case #4: Modified on server, delete locally, overwrite conflict
-  MockConflictPrompt.overwrite = true;
-  gServer.events[0].etag = '"5"';
-  gServer.events[0].summary = "remote change";
-  await pclient.deleteItem(item);
-  item = (await pclient.getAllItems())[0];
-  equal(gServer.events.length, 0);
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_conflict_delete() {
-  // TODO task/event conflicts are handled in the same way so I'm going to
-  // skip adding tests for tasks here, but it probably wouldn't hurt to
-  // create them at some point.
-  let coreEvent = {
-    kind: "calendar#event",
-    etag: '"2"',
-    id: "go6ijb0b46hlpbu4eeu92njevo",
-    created: "2006-06-08T21:04:52.000Z",
-    updated: "2006-06-08T21:05:49.138Z",
-    summary: "New Event",
-    creator: gServer.creator,
-    organizer: gServer.creator,
-    start: { dateTime: "2006-06-10T18:00:00+02:00" },
-    end: { dateTime: "2006-06-10T20:00:00+02:00" },
-    iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-  };
-
-  // Load initial event to server
-  gServer.events = [coreEvent];
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-  let item = (await pclient.getAllItems())[0];
-
-  // Case #1: Deleted on server, modify locally, overwrite conflict
-  MockConflictPrompt.overwrite = true;
-  gServer.events = [];
-  let newItem = item.clone();
-  newItem.title = "local change";
-  let modifiedItem = await pclient.modifyItem(newItem, item);
-  item = (await pclient.getAllItems())[0];
-  equal(gServer.events[0].summary, "local change");
-  notEqual(gServer.events[0].etag, '"2"');
-  equal(item.title, "local change");
-  equal(modifiedItem.title, "local change");
-  equal(gServer.events.length, 1);
-
-  // Case #2: Deleted on server, modify locally, don't overwrite conflict
-  MockConflictPrompt.overwrite = false;
-  gServer.events = [];
-  try {
-    modifiedItem = await pclient.modifyItem(newItem, item);
-    do_throw("Expected modifyItem to be cancelled");
-  } catch (e) {
-    // Swallow cancelling the request
-    if (e != Ci.calIErrors.OPERATION_CANCELLED) {
-      throw e;
-    }
-  }
-  // The next synchronize should cause the event to be deleted locally.
-  coreEvent.status = "cancelled";
-  gServer.events = [coreEvent];
-
-  await gServer.waitForLoad(client);
-
-  let items = await pclient.getAllItems();
-  equal(items.length, 0);
-  equal(gServer.events.length, 1);
-
-  // Put the event back in the calendar for the next run
-  delete gServer.events[0].status;
-  client.refresh();
-  await gServer.waitForLoad(client);
-  items = await pclient.getAllItems();
-  equal(items.length, 1);
-
-  // Case #3: Deleted on server, delete locally, don't overwrite conflict
-  MockConflictPrompt.overwrite = false;
-  gServer.events = [];
-  try {
-    await pclient.deleteItem(item);
-    do_throw("Expected deleteItem to be cancelled");
-  } catch (e) {
-    // Swallow cancelling the request
-    if (e != Ci.calIErrors.OPERATION_CANCELLED) {
-      throw e;
-    }
-  }
-  // The next synchronize should cause the event to be deleted locally.
-  coreEvent.status = "cancelled";
-  gServer.events = [coreEvent];
-  await gServer.waitForLoad(client);
-
-  items = await pclient.getAllItems();
-  equal(items.length, 0);
-
-  // Put the event back in the calendar for the next run
-  delete gServer.events[0].status;
-  client.refresh();
-  await gServer.waitForLoad(client);
-  items = await pclient.getAllItems();
-  equal(items.length, 1);
-
-  // Case #4: Deleted on server, delete locally, overwrite conflict
-  MockConflictPrompt.overwrite = true;
-  gServer.events = [];
-  await pclient.deleteItem(item);
-  items = await pclient.getAllItems();
-  equal(items.length, 0);
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_default_alarms() {
-  let defaultReminders = [{ method: "popup", minutes: 10 }, { method: "email", minutes: 20 }];
-  gServer.calendarListData.defaultReminders = defaultReminders;
-  gServer.eventsData.defaultReminders = defaultReminders;
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"2"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "Default Reminder",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-      reminders: { useDefault: true },
-    },
-  ];
-
-  // Case #1: read default alarms from event stream
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-  equal(client.getProperty("settings.defaultReminders"), JSON.stringify(defaultReminders));
-
-  let item = (await pclient.getAllItems())[0];
-  let alarms = item.getAlarms({});
-
-  equal(alarms.length, 2);
-  ok(alarms.every(x => x.getProperty("X-DEFAULT-ALARM") == "TRUE"));
-  equal(alarms[0].action, "DISPLAY");
-  equal(alarms[0].offset.icalString, "-PT10M");
-  equal(alarms[1].action, "EMAIL");
-  equal(alarms[1].offset.icalString, "-PT20M");
-
-  // Case #2: add an item with only default alarms
-  let event = cal.createEvent(
-    [
-      "BEGIN:VEVENT",
-      "SUMMARY:Default Alarms",
-      "DTSTART:20060610T180000Z",
-      "DTEND:20060610T200000Z",
-      "BEGIN:VALARM",
-      "X-DEFAULT-ALARM:TRUE",
-      "ACTION:DISPLAY",
-      "TRIGGER;VALUE=DURATION:PT0S",
-      "DESCRIPTION:Description",
-      "END:VALARM",
-      "END:VEVENT",
-    ].join("\r\n")
-  );
-
-  await pclient.addItem(event);
-  ok(gServer.events[1].reminders.useDefault);
-  equal(gServer.events[1].reminders.overrides.length, 0);
-
-  // Case #3: Mixed default/non-default alarms. Not sure this will happen
-  event = cal.createEvent(
-    [
-      "BEGIN:VEVENT",
-      "SUMMARY:Default Alarms",
-      "DTSTART:20060610T180000Z",
-      "DTEND:20060610T200000Z",
-      "BEGIN:VALARM",
-      "ACTION:DISPLAY",
-      "X-DEFAULT-ALARM:TRUE",
-      "TRIGGER;VALUE=DURATION:-PT1M",
-      "DESCRIPTION:Description",
-      "END:VALARM",
-      "BEGIN:VALARM",
-      "ACTION:DISPLAY",
-      "TRIGGER;VALUE=DURATION:-PT5M",
-      "DESCRIPTION:Description",
-      "END:VALARM",
-      "END:VEVENT",
-    ].join("\r\n")
-  );
-
-  await pclient.addItem(event);
-  ok(gServer.events[2].reminders.useDefault);
-  equal(gServer.events[2].reminders.overrides.length, 1);
-  equal(gServer.events[2].reminders.overrides[0].minutes, 5);
-
-  gServer.resetClient(client);
-
-  // Case #4a: Empty default alarms
-  gServer.calendarListData.defaultReminders = [];
-  gServer.eventsData.defaultReminders = [];
-  client = await gServer.getClient();
-  pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-
-  event = cal.createEvent(
-    [
-      "BEGIN:VEVENT",
-      "SUMMARY:Default Alarms Empty",
-      "DTSTART:20060610T180000Z",
-      "DTEND:20060610T200000Z",
-      "X-DEFAULT-ALARM:TRUE",
-      "END:VEVENT",
-    ].join("\r\n")
-  );
-
-  await pclient.addItem(event);
-  ok(gServer.events[0].reminders.useDefault);
-  equal(gServer.events[0].reminders.overrides, undefined);
-
-  let events = gServer.events;
-  gServer.resetClient(client);
-
-  // Case #4b: Read an item with empty default alarms
-  gServer.events = events;
-  client = await gServer.getClient();
-  pclient = cal.async.promisifyCalendar(client.wrappedJSObject);
-
-  item = (await pclient.getAllItems())[0];
-  equal(item.getProperty("X-DEFAULT-ALARM"), "TRUE");
-
-  gServer.resetClient(client);
-});
-
-add_task(async function test_paginate() {
-  gServer.events = [
-    {
-      kind: "calendar#event",
-      etag: '"1"',
-      id: "go6ijb0b46hlpbu4eeu92njevo",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-    },
-    {
-      kind: "calendar#event",
-      etag: '"2"',
-      id: "fepf8uf6n7n04w7feukucs9n8e",
-      created: "2006-06-08T21:04:52.000Z",
-      updated: "2006-06-08T21:05:49.138Z",
-      summary: "New Event 2",
-      creator: gServer.creator,
-      organizer: gServer.creator,
-      start: { dateTime: "2006-06-10T18:00:00+02:00" },
-      end: { dateTime: "2006-06-10T20:00:00+02:00" },
-      iCalUID: "fepf8uf6n7n04w7feukucs9n8e@google.com",
-    },
-  ];
-
-  gServer.tasks = [
-    {
-      kind: "tasks#task",
-      id: "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU",
-      etag: '"Lck7VNWFJuXdzMtOmrYPx0KFV2s/LTIwNjA4MDcyNDM"',
-      title: "New Task",
-      updated: "2014-09-08T16:30:27.000Z",
-      selfLink:
-        gServer.baseUri +
-        "/tasks/v1/lists/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDow/tasks/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo0MDI1NDg2NjU",
-      position: "00000000000000130998",
-      status: "needsAction",
-    },
-    {
-      kind: "tasks#task",
-      id: "MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo5OTU0Mjk2MzQ",
-      etag: '"Lck7VNWFJuXdzMtOmrYPx0KFV2s/LTQyNTY0MjUwOQ"',
-      title: "New Task 2",
-      updated: "2014-09-08T16:30:27.000Z",
-      selfLink:
-        gServer.baseUri +
-        "/tasks/v1/lists/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDow/tasks/MTEyMDE2MDE5NzE0NjYzMDk4ODI6MDo5OTU0Mjk2MzQ",
-      position: "00000000000000130993",
-      status: "needsAction",
-    },
-  ];
-
-  Services.prefs.setIntPref("calendar.google.maxResultsPerRequest", 1);
-
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client);
-
-  // Make sure all pages were requested
-  equal(gServer.eventsData.nextPageToken, null);
-  equal(gServer.tasksData.nextPageToken, null);
-
-  // ...and we have all items. Not checking props
-  // because the other tests do this sufficiently.
-  let items = await pclient.getAllItems();
-  equal(items.length, 4);
-
-  equal(client.getProperty("syncToken.events"), "next-sync-token");
-
-  Services.prefs.clearUserPref("calendar.google.maxResultsPerRequest");
-  gServer.resetClient(client);
-});
-
-add_task(async function test_incremental_reset() {
-  gServer.syncs = [
-    {
-      token: "1",
-      events: [
-        {
-          kind: "calendar#event",
-          etag: '"1"',
-          id: "go6ijb0b46hlpbu4eeu92njevo",
-          created: "2006-06-08T21:04:52.000Z",
-          updated: "2006-06-08T21:05:49.138Z",
-          summary: "New Event",
-          creator: gServer.creator,
-          organizer: gServer.creator,
-          start: { dateTime: "2006-06-10T18:00:00+02:00" },
-          end: { dateTime: "2006-06-10T20:00:00+02:00" },
-          iCalUID: "go6ijb0b46hlpbu4eeu92njevo@google.com",
-        },
-      ],
-    },
-    {
-      token: "2",
-      reset: true,
-    },
-    {
-      token: "3",
-      events: [
-        {
-          kind: "calendar#event",
-          etag: '"2"',
-          id: "fepf8uf6n7n04w7feukucs9n8e",
-          created: "2006-06-08T21:04:52.000Z",
-          updated: "2006-06-08T21:05:49.138Z",
-          summary: "New Event 2",
-          creator: gServer.creator,
-          organizer: gServer.creator,
-          start: { dateTime: "2006-06-10T18:00:00+02:00" },
-          end: { dateTime: "2006-06-10T20:00:00+02:00" },
-          iCalUID: "fepf8uf6n7n04w7feukucs9n8e@google.com",
-        },
-      ],
-    },
-  ];
-  let client = await gServer.getClient();
-  let pclient = cal.async.promisifyCalendar(client);
-
-  let items = await pclient.getAllItems();
-  equal(items.length, 1);
-  equal(items[0].title, "New Event");
-
-  client.refresh();
-  await gServer.waitForLoad(client);
-
-  items = await pclient.getAllItems();
-  equal(items.length, 1);
-  equal(items[0].title, "New Event 2");
-
-  equal(gServer.syncs.length, 0);
-  equal(client.getProperty("syncToken.events"), "last");
-
-  gServer.resetClient(client);
-});
--- a/calendar/test/unit/xpcshell-libical.ini
+++ b/calendar/test/unit/xpcshell-libical.ini
@@ -1,12 +1,8 @@
 [DEFAULT]
 tags = calendar libical
 head = head_libical.js head_consts.js
 tail =
 dupe-manifest =
 support-files = data/**
 
-[test_gdata_provider.js]
-# See bug 1481180.
-# This had requesttimeoutfactor = 2, but for libical that's unnecessary.
-
 [include:xpcshell-shared.ini]
--- a/mail/app.mozbuild
+++ b/mail/app.mozbuild
@@ -16,17 +16,14 @@ include('/%s/toolkit/toolkit.mozbuild' %
 
 if CONFIG['MOZ_EXTENSIONS']:
     DIRS += ['/%s/extensions' % CONFIG['mozreltopsrcdir']]
 
 DIRS += ['/%s' % CONFIG['MOZ_BRANDING_DIRECTORY']]
 
 
 if CONFIG['MOZ_CALENDAR']:
-    DIRS += [
-        '/%s/calendar/lightning' % CONFIG['commreltopsrcdir'],
-        '/%s/calendar/providers/gdata' % CONFIG['commreltopsrcdir'],
-    ]
+    DIRS += ['/%s/calendar/lightning' % CONFIG['commreltopsrcdir']]
 
 DIRS += [
     '/%s/chat' % CONFIG['commreltopsrcdir'],
     '/%s/mail' % CONFIG['commreltopsrcdir'],
 ]
--- a/mail/testsuite-targets.mk
+++ b/mail/testsuite-targets.mk
@@ -56,11 +56,10 @@ else
 package-tests: stage-mozmill
 endif
 
 stage-mozmill: make-stage-dir
 	$(MAKE) -C $(commtopobjdir)/mail/test/mozmill stage-package
 
 stage-calendar: stage-mozmill
 	$(MAKE) -C $(commtopobjdir)/calendar/lightning stage-package
-	$(MAKE) -C $(commtopobjdir)/calendar/providers/gdata stage-package
 
 .PHONY: stage-mozmill stage-calendar
--- a/taskcluster/ci/test/tests.yml
+++ b/taskcluster/ci/test/tests.yml
@@ -44,18 +44,16 @@ xpcshell:
                     - unittests/thunderbird_extra.py
         extra-options:
             - "--xpcshell-suite=xpcshell"
         requires-signed-builds:
             by-test-platform:
                 windows.*: true
                 default: false
     fetches:
-        build:
-            - gdata-provider.xpi
         toolchain:
             by-test-platform:
                 linux.*:
                     - linux64-node
                 macosx.*:
                     - macosx64-node
                 win.*64.*:
                     - win64-node
--- a/taskcluster/comm_taskgraph/manifests/thunderbird_candidates.yml
+++ b/taskcluster/comm_taskgraph/manifests/thunderbird_candidates.yml
@@ -320,28 +320,16 @@ mapping:
         all_locales: true
         from:
             - mar-signing
         pretty_name: thunderbird-${version}.complete.mar
         checksums_path: update/${path_platform}/${locale}/thunderbird-${version}.complete.mar
         update_balrog_manifest: true
         destinations:
             - ${version}-candidates/build${build_number}/update/${path_platform}
-    gdata-provider.xpi:
-        <<: *default
-        description: "Google data provider XPI (en-US only)"
-        all_locales: false  # Uses default_locale only
-        from:
-            - build
-        only_for_platforms:
-            - linux64-shippable
-        pretty_name: gdata-provider.${locale}.xpi
-        checksums_path: gdata-provider.${locale}.xpi
-        destinations:
-            - ${version}-candidates/build${build_number}
     lightning.xpi:
         <<: *default
         description: "Lightning XPI (en-US only)"
         all_locales: false  # Uses default_locale only
         from:
             - build
         only_for_platforms:
             - linux64-shippable
--- a/taskcluster/comm_taskgraph/manifests/thunderbird_nightly.yml
+++ b/taskcluster/comm_taskgraph/manifests/thunderbird_nightly.yml
@@ -386,30 +386,16 @@ mapping:
             by-locale:
                 en-US:
                     - ${year}/${month}/${upload_date}-${branch}
                     - latest-${branch}
                     - latest-${branch}-l10n
                 default:
                     - ${year}/${month}/${upload_date}-${branch}-l10n
                     - latest-${branch}-l10n
-    gdata-provider.xpi:
-        <<: *default
-        description: "Google data provider XPI (en-US only)"
-        all_locales: false  # Uses default_locale only
-        from:
-            - build
-        only_for_platforms:
-            - linux64-shippable
-        pretty_name: gdata-provider.${locale}.xpi
-        checksums_path: gdata-provider.${locale}.xpi
-        destinations:
-            - ${year}/${month}/${upload_date}-${branch}
-            - latest-${branch}
-            - latest-${branch}-l10n
     lightning.xpi:
         <<: *default
         description: "Lightning XPI (en-US only)"
         all_locales: false  # Uses default_locale only
         from:
             - build
         only_for_platforms:
             - linux64-shippable