Bug 1049591 - Fix lots of Calendar strict warnings. r=redDragon
authorPhilipp Kewisch <mozilla@kewis.ch>
Sat, 09 May 2015 15:05:42 +0200
changeset 22686 ee0620ac1185699823a4665e732b22b96c8c0071
parent 22685 1bf87d31938fd6e6e64b5a78aaaf17c6c0f25a07
child 22687 18c1c077059f48eae410971b26b03a9efffff330
push id1443
push usermbanner@mozilla.com
push dateMon, 10 Aug 2015 18:31:17 +0000
treeherdercomm-beta@8fe07d686c22 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersredDragon
bugs1049591
Bug 1049591 - Fix lots of Calendar strict warnings. r=redDragon
calendar/base/backend/icaljs/calICSService.js
calendar/base/content/calendar-item-editing.js
calendar/base/content/calendar-month-view.xml
calendar/base/content/calendar-multiday-view.xml
calendar/base/content/dialogs/calendar-event-dialog-attendees.js
calendar/base/content/dialogs/calendar-event-dialog.js
calendar/base/content/dialogs/calendar-migration-dialog.js
calendar/base/content/dialogs/calendar-properties-dialog.js
calendar/base/content/widgets/calendar-list-tree.xml
calendar/base/modules/calAlarmUtils.jsm
calendar/base/modules/calAsyncUtils.jsm
calendar/base/modules/calAuthUtils.jsm
calendar/base/modules/calExtract.jsm
calendar/base/modules/calHashedArray.jsm
calendar/base/modules/calItemUtils.jsm
calendar/base/modules/calIteratorUtils.jsm
calendar/base/modules/calItipUtils.jsm
calendar/base/modules/calProviderUtils.jsm
calendar/base/modules/calRecurrenceUtils.jsm
calendar/base/modules/calUtils.jsm
calendar/base/modules/calXMLUtils.jsm
calendar/base/src/calAlarm.js
calendar/base/src/calCalendarManager.js
calendar/base/src/calTimezoneService.js
calendar/base/src/calTransactionManager.js
calendar/base/src/calUtils.js
calendar/providers/caldav/calDavCalendar.js
calendar/providers/composite/calCompositeCalendar.js
calendar/providers/gdata/modules/gdataSession.jsm
calendar/providers/gdata/modules/gdataUtils.jsm
calendar/providers/memory/calMemoryCalendar.js
calendar/providers/storage/calStorageCalendar.js
calendar/providers/storage/calStorageUpgrade.jsm
calendar/providers/wcap/calWcapCalendarItems.js
calendar/providers/wcap/calWcapSession.js
--- a/calendar/base/backend/icaljs/calICSService.js
+++ b/calendar/base/backend/icaljs/calICSService.js
@@ -44,19 +44,19 @@ calIcalProperty.prototype = {
         if (this.innerObject.type == "text") {
             this.innerObject.setValue(val);
             return val;
         }
         return this.valueAsIcalString = val;
     },
 
     get valueAsIcalString() {
-        let type = this.innerObject.type;
-        function stringifyValue(x) ICAL.stringify.value(x.toString(), type);
-        return this.innerObject.getValues().map(stringifyValue).join(",");
+        return this.innerObject.getValues().map(v => {
+            return ICAL.stringify.value(v.toString(), this.innerObject.type);
+        }).join(",");
     },
     set valueAsIcalString(val) {
         var icalval = ICAL.parse._parseValue(val, this.innerObject.type);
         this.innerObject.setValue(icalval);
         return val;
     },
 
     get valueAsDatetime() {
@@ -102,41 +102,43 @@ calIcalProperty.prototype = {
     },
     setParameter: function(n, v) {
         // Similar problems for setting the value parameter. Lightning code
         // expects setting the value parameter to just change the value type
         // and attempt to use the previous value as the new one. To do this in
         // ICAL.js we need to save the value, reset the type and then try to
         // set the value again.
         if (n == "VALUE") {
-            function stringifyValue(x) ICAL.stringify.value(x.toString(), type);
-            function reparseValue(x) ICAL.parse._parseValue(stringifyValue(x), v);
+            let oldValues;
             let type = this.innerObject.type;
 
-            let oldValue;
             let wasMultiValue = this.innerObject.isMultiValue;
             if (wasMultiValue) {
-                oldValue = this.innerObject.getValues();
+                oldValues = this.innerObject.getValues();
             } else {
-                oldValue = [this.innerObject.getFirstValue()];
+                oldValues = [this.innerObject.getFirstValue()];
             }
+
             this.innerObject.resetType(v.toLowerCase());
             try {
-                oldValue = oldValue.map(reparseValue);
+                oldValues = oldValues.map(oldValue => {
+                    let strvalue = ICAL.stringify.value(oldValue.toString(), type);
+                    return ICAL.parse._parseValue(strvalue, v)
+                });
             } catch (e) {
                 // If there was an error reparsing the value, then just keep it
                 // empty.
-                oldValue = null;
+                oldValues = null;
             }
 
-            if (oldValue) {
+            if (oldValues) {
                 if (wasMultiValue && this.innerObject.isMultiValue) {
-                    this.innerObject.setValues(oldValue);
-                } else if (oldValue) {
-                    this.innerObject.setValue(oldValue.join(","));
+                    this.innerObject.setValues(oldValues);
+                } else {
+                    this.innerObject.setValue(oldValues.join(","));
                 }
             }
         } else {
             this.innerObject.setParameter(n.toLowerCase(), v);
         }
     },
     removeParameter: function(n) {
         // Again, VALUE needs special handling. Removing the value parameter is
--- a/calendar/base/content/calendar-item-editing.js
+++ b/calendar/base/content/calendar-item-editing.js
@@ -394,29 +394,28 @@ function openEventDialog(calendarItem, c
 
     // Filter out calendars that don't support the given calendar item
     calendars = calendars.filter(isItemSupported);
 
     // Filter out calendar/items that we cannot write to/modify
     if (mode == "new") {
         calendars = calendars.filter(userCanAddItemsToCalendar);
     } else { /* modify */
-        function calendarCanModifyItems(aCalendar) {
+        calendars = calendars.filter((aCalendar) => {
             /* If the calendar is the item calendar, we check that the item
              * can be modified. If the calendar is NOT the item calendar, we
              * check that the user can remove items from that calendar and
              * add items to the current one.
              */
             return (((calendarItem.calendar != aCalendar)
                      && userCanDeleteItemsFromCalendar(calendarItem.calendar)
                      && userCanAddItemsToCalendar(aCalendar))
                     || ((calendarItem.calendar == aCalendar)
                         && userCanModifyItem(calendarItem)));
-        }
-        calendars = calendars.filter(calendarCanModifyItems);
+        });
     }
 
     if (mode == "new"
         && (!isCalendarWritable(calendar)
             || !userCanAddItemsToCalendar(calendar)
             || !isItemSupported(calendar))) {
         if (calendars.length < 1) {
             // There are no writable calendars or no calendar supports the given
--- a/calendar/base/content/calendar-month-view.xml
+++ b/calendar/base/content/calendar-month-view.xml
@@ -744,66 +744,65 @@
             if (finished) {
               row.setAttribute("collapsed", true);
               continue;
             } else {
               row.removeAttribute("collapsed");
             }
             for (var j = 0; j < row.childNodes.length; j++) {
               var daybox = row.childNodes[j];
-              var date = dateList[dateBoxes.length];
+              var dt = dateList[dateBoxes.length];
 
               // Remove the attribute "relation" for all the column headers.
               // Consider only the first row index otherwise it will be
               // removed again afterwards the correct setting.
               if (i == 0) {
                   this.labeldaybox.childNodes[j].removeAttribute("relation");
               }
 
               daybox.setAttribute("context", this.getAttribute("context"));
               daybox.setAttribute("item-context", this.getAttribute("item-context") || this.getAttribute("context"));
 
               // Set the box-class depending on if this box displays a day in
               // the month being currently shown or not.
               var boxClass;
               if (this.showFullMonth) {
-                  boxClass = "calendar-month-day-box-" + 
-                             (mainMonth == date.month ? "current-month" : "other-month");
+                  boxClass = "calendar-month-day-box-" +
+                             (mainMonth == dt.month ? "current-month" : "other-month");
               } else {
                   boxClass = "calendar-month-day-box-current-month";
               }
-              function matchesDayOff(dayOffNum) { return dayOffNum == date.weekday; }
-              if (this.mDaysOffArray.some(matchesDayOff)) {
+              if (this.mDaysOffArray.some(dayOffNum => dayOffNum == dt.weekday)) {
                 boxClass = "calendar-month-day-box-day-off " + boxClass;
               }
 
               // Set up date relations
-              switch (date.compare(today)) {
+              switch (dt.compare(today)) {
                   case -1:
                       daybox.setAttribute("relation", "past");
                       break;
                   case 0:
                       daybox.setAttribute("relation", "today");
                       this.labeldaybox.childNodes[j].setAttribute("relation", "today");
                       break;
                   case 1:
                       daybox.setAttribute("relation", "future");
                       break;
               }
 
               daybox.setAttribute("class", boxClass);
 
-              daybox.setDate(date);
-              if (date.day == 1 || date.day == date.endOfMonth.day) {
+              daybox.setDate(dt);
+              if (dt.day == 1 || dt.day == dt.endOfMonth.day) {
                 daybox.showMonthLabel = true;
               } else {
                 daybox.showMonthLabel = false;
               }
               daybox.calendarView = this;
-              daybox.date = date;
+              daybox.date = dt;
               dateBoxes.push(daybox);
 
               // If we've now assigned all of our dates, set this to true so we
               // know we can just collapse the rest of the rows.
               if (dateBoxes.length == dateList.length) {
                 finished = true;
               }
             }
--- a/calendar/base/content/calendar-multiday-view.xml
+++ b/calendar/base/content/calendar-multiday-view.xml
@@ -483,30 +483,27 @@
 
       <method name="internalDeleteEvent">
         <parameter name="aOccurrence"/>
         <body><![CDATA[
            var itemIndex = -1;
            var occ;
            for (var i in this.mEventInfos) {
                occ = this.mEventInfos[i].event;
-               if (occ.hashId == aOccurrence.hashId)
-               {
+               if (occ.hashId == aOccurrence.hashId) {
                    itemIndex = i;
                    break;
                }
            }
 
            if (itemIndex != -1) {
                delete this.mSelectedItemIds[occ.hashId];
-               function isNotItem(a) {
-                  return !a.occurrence || (a.occurrence.hashId != aOccurrence.hashId);
-               }
-               this.mSelectedChunks = this.mSelectedChunks.filter(isNotItem);
-
+               this.mSelectedChunks = this.mSelectedChunks.filter((item) => {
+                   return !item.occurrence || (item.occurrence.hashId != aOccurrence.hashId);
+               });
                this.mEventInfos.splice(itemIndex, 1);
                return true;
            } else {
                return false;
            }
         ]]></body>
       </method>
 
@@ -3615,21 +3612,20 @@
 
       <method name="doDeleteItem">
         <parameter name="aEvent"/>
         <body><![CDATA[
           var cols = this.findColumnsForItem(aEvent);
           if (!cols.length)
               return;
 
-          function isNotItem(a) {
-              return (a.hashId != aEvent.hashId);
-          }
           var oldLength = this.mSelectedItems.length;
-          this.mSelectedItems = this.mSelectedItems.filter(isNotItem);
+          this.mSelectedItems = this.mSelectedItems.filter((item) => {
+              return item.hashId != aEvent.hashId;
+          });
 
           for each (let col in cols) {
               let column = col.column;
               let header = col.header;
 
               let estart = aEvent.startDate || aEvent.entryDate || aEvent.dueDate;
               if (estart.isDate) {
                   header.deleteEvent(aEvent);
--- a/calendar/base/content/dialogs/calendar-event-dialog-attendees.js
+++ b/calendar/base/content/dialogs/calendar-event-dialog-attendees.js
@@ -993,18 +993,15 @@ function calFreeBusyListener(aFbElement,
     this.mFbElement = aFbElement;
     this.mBinding = aBinding;
 }
 
 calFreeBusyListener.prototype = {
     onResult: function cFBL_onResult(aRequest, aEntries) {
         if (aRequest && !aRequest.isPending) {
             // Find request in list of pending requests and remove from queue:
-            function neq(aOp) {
-                return (aRequest.id != aOp.id);
-            }
-            this.mBinding.mPendingRequests = this.mBinding.mPendingRequests.filter(neq);
+            this.mBinding.mPendingRequests = this.mBinding.mPendingRequests.filter(aOp => aRequest.id != aOp.id);
         }
         if (aEntries) {
             this.mFbElement.onFreeBusy(aEntries);
         }
     }
 };
--- a/calendar/base/content/dialogs/calendar-event-dialog.js
+++ b/calendar/base/content/dialogs/calendar-event-dialog.js
@@ -3355,68 +3355,65 @@ function updateDateTime() {
  * This function initializes the following controls:
  * - 'timezone-starttime'
  * - 'timezone-endtime'
  * the timezone-links show the corrosponding names of the
  * start/end times. If 'cmd_timezone' is not checked
  * the links will be collapsed.
  */
 function updateTimezone() {
+    function updateTimezoneElement(aTimezone, aId, aDateTime) {
+        let element = document.getElementById(aId);
+        if (!element) {
+            return;
+        }
+
+        if (aTimezone) {
+            element.removeAttribute('collapsed');
+            element.value = aTimezone.displayName || aTimezone.tzid;
+            if (!aDateTime || !aDateTime.isValid || gIsReadOnly || aDateTime.isDate) {
+                if (element.hasAttribute('class')) {
+                    element.setAttribute('class-on-enabled',
+                                         element.getAttribute('class'));
+                    element.removeAttribute('class');
+                }
+                if (element.hasAttribute('onclick')) {
+                    element.setAttribute('onclick-on-enabled',
+                                         element.getAttribute('onclick'));
+                    element.removeAttribute('onclick');
+                }
+                element.setAttribute('disabled', 'true');
+            } else {
+                if (element.hasAttribute('class-on-enabled')) {
+                    element.setAttribute('class',
+                                         element.getAttribute('class-on-enabled'));
+                    element.removeAttribute('class-on-enabled');
+                }
+                if (element.hasAttribute('onclick-on-enabled')) {
+                    element.setAttribute('onclick',
+                                         element.getAttribute('onclick-on-enabled'));
+                    element.removeAttribute('onclick-on-enabled');
+                }
+                element.removeAttribute('disabled');
+            }
+        } else {
+            element.setAttribute('collapsed', 'true');
+        }
+    }
+
     let timezonesEnabled = document.getElementById('cmd_timezone')
                                    .getAttribute('checked') == 'true';
     // convert to default timezone if the timezone option
     // is *not* checked, otherwise keep the specific timezone
     // and display the labels in order to modify the timezone.
     if (timezonesEnabled) {
-        let startTimezone = gStartTimezone;
-        let endTimezone = gEndTimezone;
-
-        function updateTimezoneElement(aTimezone, aId, aDateTime) {
-            let element = document.getElementById(aId);
-            if (!element) {
-                return;
-            }
-
-            if (aTimezone) {
-                element.removeAttribute('collapsed');
-                element.value = aTimezone.displayName || aTimezone.tzid;
-                if (!aDateTime || !aDateTime.isValid || gIsReadOnly || aDateTime.isDate) {
-                    if (element.hasAttribute('class')) {
-                        element.setAttribute('class-on-enabled',
-                                             element.getAttribute('class'));
-                        element.removeAttribute('class');
-                    }
-                    if (element.hasAttribute('onclick')) {
-                        element.setAttribute('onclick-on-enabled',
-                                             element.getAttribute('onclick'));
-                        element.removeAttribute('onclick');
-                    }
-                    element.setAttribute('disabled', 'true');
-                } else {
-                    if (element.hasAttribute('class-on-enabled')) {
-                        element.setAttribute('class',
-                                             element.getAttribute('class-on-enabled'));
-                        element.removeAttribute('class-on-enabled');
-                    }
-                    if (element.hasAttribute('onclick-on-enabled')) {
-                        element.setAttribute('onclick',
-                                             element.getAttribute('onclick-on-enabled'));
-                        element.removeAttribute('onclick-on-enabled');
-                    }
-                    element.removeAttribute('disabled');
-                }
-            } else {
-                element.setAttribute('collapsed', 'true');
-            }
-        }
-
-        updateTimezoneElement(startTimezone,
+        updateTimezoneElement(gStartTimezone,
                               'timezone-starttime',
                               gStartTime);
-        updateTimezoneElement(endTimezone,
+        updateTimezoneElement(gEndTimezone,
                               'timezone-endtime',
                               gEndTime);
     } else {
         document.getElementById('timezone-starttime')
                 .setAttribute('collapsed', 'true');
         document.getElementById('timezone-endtime')
                 .setAttribute('collapsed', 'true');
     }
--- a/calendar/base/content/dialogs/calendar-migration-dialog.js
+++ b/calendar/base/content/dialogs/calendar-migration-dialog.js
@@ -456,85 +456,85 @@ var gDataMigrator = {
         var evoDir = this.dirService.get("Home", Components.interfaces.nsILocalFile);
         evoDir.append(".evolution");
         evoDir.append("calendar");
         evoDir.append("local");
         return (evoDir.exists() ? [new dataMigrator("Evolution", evoMigrate, [evoDir])] : []);
     },
 
     checkWindowsMail: function gdm_windowsMail() {
+        function doMigrate(aCalendarNodes, aMailDir, aCallback) {
+            let calManager = cal.getCalendarManager();
+
+            for (let node of aCalendarNodes) {
+                let name = node.getElementsByTagName("Name")[0].textContent;
+                let color = node.getElementsByTagName("Color")[0].textContent;
+                let enabled = node.getElementsByTagName("Enabled")[0].textContent == "True";
+
+                // The name is quoted, and the color also contains an alpha
+                // value. Lets just ignore the alpha value and take the
+                // color part.
+                name = name.replace(/(^'|'$)/g, "");
+                color = color.replace(/0x[0-9a-fA-F]{2}([0-9a-fA-F]{4})/, "#$1");
+
+                let calfile = aMailDir.clone();
+                calfile.append(name + ".ics");
+
+                if (calfile.exists()) {
+                    let storage = gDataMigrator.importICSToStorage(calfile)
+                    storage.name = name;
+
+                    if (color) {
+                        storage.setProperty("color", color);
+                    }
+                    calManager.registerCalendar(storage);
+
+                    if (enabled) {
+                        getCompositeCalendar().addCalendar(storage);
+                    }
+                }
+            }
+            aCallback();
+        }
 
         if (!this.dirService.has("LocalAppData")) {
             // We are probably not on windows
             return [];
         }
 
         let maildir = this.dirService.get("LocalAppData",
                                           Components.interfaces.nsILocalFile);
 
         maildir.append("Microsoft");
         maildir.append("Windows Calendar");
         maildir.append("Calendars");
 
         let settingsxml = maildir.clone();
         settingsxml.append("Settings.xml");
-        if (!settingsxml || !settingsxml.exists()) {
-            // No Settings.xml, maybe Windows Calendar was never started?
-            return [];
-        }
-        let settingsXmlUri = Services.io.newFileURI(settingsxml);
 
-        let req = new XMLHttpRequest();
-        req.open("GET", settingsXmlUri.spec, false);
-        req.send(null);
-        if (req.status == 0) {
-            // The file was found, it seems we are on windows vista.
-            let doc = req.responseXML;
-            let root = doc.documentElement;
-
-            // Get all calendar property tags and return the migrator.
-            let calendars = doc.getElementsByTagName("VCalendar");
-            function doMigrate(aCallback) {
-                for each (let node in Array.slice(calendars)) {
-                    let name = node.getElementsByTagName("Name")[0].textContent;
-                    let color = node.getElementsByTagName("Color")[0].textContent;
-                    let enabled = node.getElementsByTagName("Enabled")[0].textContent == "True";
+        let migrators = [];
+        if (settingsxml.exists()) {
+            let settingsXmlUri = Services.io.newFileURI(settingsxml);
 
-                    // The name is quoted, and the color also contains an alpha
-                    // value. Lets just ignore the alpha value and take the
-                    // color part.
-                    name = name.replace(/(^'|'$)/g, "");
-                    color = color.replace(/0x[0-9a-fA-F]{2}([0-9a-fA-F]{4})/, "#$1");
-
-                    let calfile = maildir.clone();
-                    calfile.append(name + ".ics");
-
-                    if (calfile.exists()) {
-                        let storage = gDataMigrator.importICSToStorage(calfile)
-
-                        storage.name = name;
+            let req = new XMLHttpRequest();
+            req.open("GET", settingsXmlUri.spec, false);
+            req.send(null);
+            if (req.status == 0) {
+                // The file was found, it seems we are on windows vista.
+                let doc = req.responseXML;
+                let root = doc.documentElement;
 
-                        if (color) {
-                            storage.setProperty("color", color);
-                        }
-                        let calManager = cal.getCalendarManager();
-                        calManager.registerCalendar(storage);
-
-                        if (enabled) {
-                            getCompositeCalendar().addCalendar(storage);
-                        }
-                    }
+                // Get all calendar property tags and return the migrator.
+                let calendars = doc.getElementsByTagName("VCalendar");
+                if (calendars.length > 0) {
+                    migrators = [new dataMigrator("Windows Calendar", doMigrate.bind(null, calendars, maildir))];
                 }
-                aCallback();
-            }
-            if (calendars.length > 0) {
-                return [new dataMigrator("Windows Calendar", doMigrate)];
             }
         }
-        return [];
+        return migrators;
     },
 
     /**
      * Creates and registers a storage calendar and imports the given ics file into it.
      *
      * @param icsFile     The nsI(Local)File to import.
      */
     importICSToStorage: function migrateIcsStorage(icsFile) {
--- a/calendar/base/content/dialogs/calendar-properties-dialog.js
+++ b/calendar/base/content/dialogs/calendar-properties-dialog.js
@@ -124,30 +124,30 @@ function setupEnabledCheckbox() {
 function unsubscribeCalendar() {
     let calmgr =  cal.getCalendarManager();
 
     calmgr.unregisterCalendar(gCalendar);
     window.close();
 }
 
 function initRefreshInterval() {
+    function createMenuItem(minutes) {
+        let menuitem = createXULElement("menuitem");
+        menuitem.setAttribute("value", minutes);
+
+        let everyMinuteString = cal.calGetString("calendar", "calendarPropertiesEveryMinute");
+        let label = PluralForm.get(minutes, everyMinuteString).replace("#1", minutes);
+        menuitem.setAttribute("label", label);
+
+        return menuitem;
+    }
+
     setBooleanAttribute("calendar-refreshInterval-row", "hidden", !gCalendar.canRefresh);
 
     if (gCalendar.canRefresh) {
-        function createMenuItem(minutes) {
-            let menuitem = createXULElement("menuitem");
-            menuitem.setAttribute("value", minutes);
-
-            let everyMinuteString = cal.calGetString("calendar", "calendarPropertiesEveryMinute");
-            let label = PluralForm.get(minutes, everyMinuteString).replace("#1", minutes);
-            menuitem.setAttribute("label", label);
-
-            return menuitem;
-        }
-
         let refreshInterval = gCalendar.getProperty("refreshInterval");
         if (refreshInterval === null) refreshInterval = 30;
 
         let foundValue = false;
         let separator = document.getElementById("calendar-refreshInterval-manual-separator");
         let menulist = document.getElementById("calendar-refreshInterval-menulist");
         for each (let min in [1, 5, 15, 30, 60]) {
             let menuitem = createMenuItem(min);
--- a/calendar/base/content/widgets/calendar-list-tree.xml
+++ b/calendar/base/content/widgets/calendar-list-tree.xml
@@ -637,16 +637,17 @@
           try {
               let rowProps = this.getRowProperties(aRow);
               let colProps = this.getColumnProperties(aCol);
               return rowProps + (rowProps && colProps ? " " : "") + colProps;
           } catch (e) {
               // It seems errors in these functions are not shown, do this
               // explicitly.
               cal.ERROR("Error getting cell props: " + e);
+              return "";
           }
         ]]></body>
       </method>
 
       <method name="getRowProperties">
         <parameter name="aRow"/>
         <body><![CDATA[
           let properties = [];
--- a/calendar/base/modules/calAlarmUtils.jsm
+++ b/calendar/base/modules/calAlarmUtils.jsm
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
 Components.utils.import("resource://gre/modules/Preferences.jsm");
 
-EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
+this.EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
 cal.alarms = {
     /**
      * Read default alarm settings from user preferences and apply them to the
      * event/todo passed in. The item's calendar should be set to ensure the
      * correct alarm type is set.
      *
      * @param aItem     The item to apply the default alarm values to.
      */
--- a/calendar/base/modules/calAsyncUtils.jsm
+++ b/calendar/base/modules/calAsyncUtils.jsm
@@ -5,17 +5,17 @@
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
 Components.utils.import("resource://gre/modules/Promise.jsm");
 Components.utils.import("resource://gre/modules/PromiseUtils.jsm");
 
 /*
  * Asynchronous tools for handling calendar operations.
  */
 
-EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
+this.EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
 const cIOL = Components.interfaces.calIOperationListener;
 const cIC = Components.interfaces.calICalendar;
 
 const promisifyProxyHandler = {
     promiseOperation: function(target, name, args) {
         let deferred = PromiseUtils.defer();
         let listener = cal.async.promiseOperationListener(deferred);
         args.push(listener);
--- a/calendar/base/modules/calAuthUtils.jsm
+++ b/calendar/base/modules/calAuthUtils.jsm
@@ -5,17 +5,17 @@
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/Preferences.jsm");
 
 /*
  * Authentication helper code
  */
 
-EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
+this.EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
 cal.auth = {
     /**
      * Auth prompt implementation - Uses password manager if at all possible.
      */
     Prompt: function calPrompt() {
         this.mWindow = cal.getCalendarWindow();
         this.mReturnedLogins = {};
     },
--- a/calendar/base/modules/calExtract.jsm
+++ b/calendar/base/modules/calExtract.jsm
@@ -1080,17 +1080,17 @@ Extractor.prototype = {
         return alts;
     },
 
     getPositionsFor: function getPositionsFor(s, name, count) {
         let positions = new Array();
         let re = /\%(\d)\$S/g;
         let match;
         let i = 0;
-        while (match = re.exec(s)) {
+        while ((match = re.exec(s))) {
             i++;
             positions[parseInt(match[1], 10)] = i;
         }
 
         // correctness checking
         for (i = 1; i <= count; i++) {
             if (positions[i] === undefined) {
                 Components.utils.reportError("[calExtract] Faulty extraction pattern " + name +
--- a/calendar/base/modules/calHashedArray.jsm
+++ b/calendar/base/modules/calHashedArray.jsm
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
 
-EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
+var EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
 
 /**
  * An unsorted array of hashable items with some extra functions to quickly
  * retrieve the item by its hash id.
  *
  * Performance Considerations:
  *  - Accessing items is fast
  *  - Adding items is fast (they are added to the end)
--- a/calendar/base/modules/calItemUtils.jsm
+++ b/calendar/base/modules/calItemUtils.jsm
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-var EXPORTED_SYMBOLS = ["itemDiff"];
 "use strict";
 
+this.EXPORTED_SYMBOLS = ["itemDiff"];
+
 Components.utils.import("resource://calendar/modules/calHashedArray.jsm");
 
 /**
  * Given two sets of items, find out which items were added, changed or
  * removed.
  *
  * The general flow is to first use load/load1 methods to load the engine with
  * the first set of items, then use difference/difference1 to load the set of
--- a/calendar/base/modules/calIteratorUtils.jsm
+++ b/calendar/base/modules/calIteratorUtils.jsm
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/Preferences.jsm");
 
-EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
+this.EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
 
 /**
  * Iterates an array of items, i.e. the passed item including all
  * overridden instances of a recurring series.
  *
  * @param items array of items
  */
 cal.itemIterator = function cal_itemIterator(items) {
@@ -115,25 +115,26 @@ cal.ical = {
      *  @param aCompType        The type of item to iterate.
      *  @return                 The iterator that yields all items.
      */
     calendarComponentIterator: function cal_ical_calendarComponentIterator(aComponent, aCompType) {
         let compType = (aCompType || "ANY");
         if (aComponent && aComponent.componentType == "VCALENDAR") {
             return cal.ical.subcomponentIterator(aComponent, compType);
         } else if (aComponent && aComponent.componentType == "XROOT") {
-            function calVCALENDARIterator(aWantKeys) {
-                cal.ASSERT(aWantKeys, "Please use for() on the calendar component iterator");
-                for (let calComp in cal.ical.subcomponentIterator(aComponent, "VCALENDAR")) {
-                    for (let itemComp in cal.ical.subcomponentIterator(calComp, compType)) {
-                        yield itemComp;
+            return {
+                __iterator__: function calVCALENDARIterator(aWantKeys) {
+                    cal.ASSERT(aWantKeys, "Please use for() on the calendar component iterator");
+                    for (let calComp in cal.ical.subcomponentIterator(aComponent, "VCALENDAR")) {
+                        for (let itemComp in cal.ical.subcomponentIterator(calComp, compType)) {
+                            yield itemComp;
+                        }
                     }
                 }
             };
-            return { __iterator__: calVCALENDARIterator };
         } else if (aComponent && (compType == "ANY" || compType == aComponent.componentType)) {
             return {
                 __iterator__: function singleItemIterator(aWantKeys) {
                     cal.ASSERT(aWantKeys, "Please use for() on the calendar component iterator");
                     yield aComponent;
                 }
             }
         } else {
--- a/calendar/base/modules/calItipUtils.jsm
+++ b/calendar/base/modules/calItipUtils.jsm
@@ -7,17 +7,17 @@ Components.utils.import("resource://cale
 Components.utils.import("resource://calendar/modules/calAlarmUtils.jsm");
 Components.utils.import("resource://calendar/modules/calIteratorUtils.jsm");
 Components.utils.import("resource://gre/modules/Preferences.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 /**
  * Scheduling and iTIP helper code
  */
-EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
+this.EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
 cal.itip = {
     /**
      * Gets the sequence/revision number, either of the passed item or
      * the last received one of an attendee; see
      * <http://tools.ietf.org/html/draft-desruisseaux-caldav-sched-04#section-7.1>.
      */
      getSequence: function cal_itip_getSequence(item) {
         let seq = null;
@@ -170,26 +170,28 @@ cal.itip = {
      * @param aOperationType  An operation type from calIOperationListener
      * @return                The suggested text.
      */
     getCompleteText: function getCompleteText(aStatus, aOperationType) {
         function _gs(strName, param) {
             return cal.calGetString("lightning", strName, param, "lightning");
         }
 
+        let text = "";
         const cIOL = Components.interfaces.calIOperationListener;
         if (Components.isSuccessCode(aStatus)) {
             switch (aOperationType) {
-                case cIOL.ADD: return _gs("imipAddedItemToCal");
-                case cIOL.MODIFY: return _gs("imipUpdatedItem");
-                case cIOL.DELETE: return _gs("imipCanceledItem");
+                case cIOL.ADD: text = gs("imipAddedItemToCal"); break;
+                case cIOL.MODIFY: text = _gs("imipUpdatedItem"); break;
+                case cIOL.DELETE: text = _gs("imipCanceledItem"); break;
             }
         } else {
-            return _gs("imipBarProcessingFailed", [aStatus.toString(16)]);
+            text = _gs("imipBarProcessingFailed", [aStatus.toString(16)]);
         }
+        return text;
     },
 
     /**
      * Scope: iTIP message receiver
      *
      * Gets a text describing the given itip method. The text is of the form
      * "This Message contains a ... ".
      *
--- a/calendar/base/modules/calProviderUtils.jsm
+++ b/calendar/base/modules/calProviderUtils.jsm
@@ -8,17 +8,17 @@ Components.utils.import("resource://cale
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Preferences.jsm");
 
 /*
  * Provider helper code
  */
 
-EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
+this.EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
 
 /**
  * Prepare HTTP channel with standard request headers and upload
  * data/content-type if needed
  *
  * @param arUri                      Channel Uri, will only be used for a new
  *                                     channel.
  * @param aUploadData                Data to be uploaded, if any. This may be a
--- a/calendar/base/modules/calRecurrenceUtils.jsm
+++ b/calendar/base/modules/calRecurrenceUtils.jsm
@@ -1,28 +1,52 @@
 /* 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/. */
 
 Components.utils.import("resource://gre/modules/PluralForm.jsm");
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
-EXPORTED_SYMBOLS = ["recurrenceRule2String", "splitRecurrenceRules", "checkRecurrenceRule"];
+this.EXPORTED_SYMBOLS = ["recurrenceRule2String", "splitRecurrenceRules", "checkRecurrenceRule"];
 
 /**
  * This function takes the recurrence info passed as argument and creates a
  * literal string representing the repeat pattern in natural language.
  *
  * @param recurrenceInfo    An item's recurrence info to parse.
  * @param startDate         The start date to base rules on.
  * @param endDate           The end date to base rules on.
  * @param allDay            If true, the pattern should assume an allday item.
  * @return                  A human readable string describing the recurrence.
  */
 function recurrenceRule2String(recurrenceInfo, startDate, endDate, allDay) {
-    function getRString(name, args) cal.calGetString("calendar-event-dialog", name, args);
+    function getRString(name, args) {
+        return cal.calGetString("calendar-event-dialog", name, args);
+    }
+    function day_of_week(day) {
+        return Math.abs(day) % 8;
+    }
+    function day_position(day) {
+        return (Math.abs(day) - day_of_week(day)) / 8 * (day < 0 ? -1 : 1);
+    }
+    function nounClass(aDayString, aRuleString) {
+        // Select noun class (grammatical gender) for rule string
+        let nounClass = getRString(aDayString + "Nounclass");
+        return aRuleString + nounClass.substr(0, 1).toUpperCase() +
+               nounClass.substr(1);
+    }
+    function pluralWeekday(aDayString) {
+        let plural = getRString("pluralForWeekdays") == "true";
+        return (plural ? aDayString + "Plural" : aDayString);
+    }
+    function everyWeekDay(aByDay) {
+        // Checks if aByDay contains only values from 1 to 7 with any order.
+        let mask = aByDay.reduce((v, c) => v | (1 << c), 1);
+        return aByDay.length == 7 && mask == Math.pow(2, 8) - 1;
+    }
+
 
     // Retrieve a valid recurrence rule from the currently
     // set recurrence info. Bail out if there's more
     // than a single rule or something other than a rule.
     recurrenceInfo = recurrenceInfo.clone();
     let rrules = splitRecurrenceRules(recurrenceInfo);
     if (rrules[0].length == 1) {
         let rule = cal.wrapInstance(rrules[0][0], Components.interfaces.calIRecurrenceRule);
@@ -32,39 +56,16 @@ function recurrenceRule2String(recurrenc
                                         'BYMINUTE',
                                         //'BYDAY',
                                         'BYHOUR',
                                         //'BYMONTHDAY',
                                         'BYYEARDAY',
                                         'BYWEEKNO',
                                         //'BYMONTH',
                                         'BYSETPOS'])) {
-            function day_of_week(day) {
-                return Math.abs(day) % 8;
-            }
-            function day_position(day) {
-                let dow = day_of_week(day);
-                return (Math.abs(day) - dow) / 8 * (day < 0 ? -1 : 1);
-            }
-            function nounClass(aDayString, aRuleString) {
-                // Select noun class (grammatical gender) for rule string
-                let nounClass = getRString(aDayString + "Nounclass");
-                return aRuleString + nounClass.substr(0, 1).toUpperCase() +
-                       nounClass.substr(1);
-            }
-            function pluralWeekday(aDayString) {
-                let plural = getRString("pluralForWeekdays") == "true";
-                return (plural ? aDayString + "Plural" : aDayString);
-            }
-            function everyWeekDay(aByDay) {
-                // Checks if aByDay contains only values from 1 to 7 with any order.
-                let mask = aByDay.reduce(function(v, c) v | (1 << c), 1);
-                return aByDay.length == 7 && mask == Math.pow(2, 8) - 1;
-            }
-
             let dateFormatter = cal.getDateFormatter();
             let ruleString;
             if (rule.type == 'DAILY') {
                 if (checkRecurrenceRule(rule, ['BYDAY'])) {
                     let days = rule.getComponent("BYDAY", {});
                     let weekdays = [2, 3, 4, 5, 6];
                     if (weekdays.length == days.length) {
                         let i;
--- a/calendar/base/modules/calUtils.jsm
+++ b/calendar/base/modules/calUtils.jsm
@@ -10,17 +10,17 @@ Components.utils.import("resource://gre/
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/Preferences.jsm");
 
 // Usually the backend loader gets loaded via profile-after-change, but in case
 // a calendar component hooks in earlier, its very likely it will use calUtils.
 // Getting the service here will load if its not already loaded
 Components.classes["@mozilla.org/calendar/backend-loader;1"].getService();
 
-EXPORTED_SYMBOLS = ["cal"];
+this.EXPORTED_SYMBOLS = ["cal"];
 let cal = {
     // new code should land here,
     // and more code should be moved from calUtils.js into this object to avoid
     // clashes with other extensions
 
     getDragService: generateServiceAccessor("@mozilla.org/widget/dragservice;1",
                                                 Components.interfaces.nsIDragService),
 
@@ -407,61 +407,55 @@ let cal = {
       b = Number(b);
       return ((a < b) ? -1 :      // avoid underflow problems of subtraction
               (a > b) ?  1 : 0);
     },
 
     sortEntryComparer: function cal_sortEntryComparer(sortType, modifier) {
       switch (sortType) {
         case "number":
-          function compareNumbers(sortEntryA, sortEntryB) {
+          return function compareNumbers(sortEntryA, sortEntryB) {
             let nsA = cal.sortEntryKey(sortEntryA);
             let nsB = cal.sortEntryKey(sortEntryB);
             return cal.compareNumber(nsA, nsB) * modifier;
-          }
-          return compareNumbers;
+          };
         case "date":
-          function compareTimes(sortEntryA, sortEntryB) {
+          return function compareTimes(sortEntryA, sortEntryB) {
             let nsA = cal.sortEntryKey(sortEntryA);
             let nsB = cal.sortEntryKey(sortEntryB);
             return cal.compareNativeTime(nsA, nsB) * modifier;
-          }
-          return compareTimes;
+          };
         case "date_filled":
-          function compareTimesFilled(sortEntryA, sortEntryB) {
+          return function compareTimesFilled(sortEntryA, sortEntryB) {
             let nsA = cal.sortEntryKey(sortEntryA);
             let nsB = cal.sortEntryKey(sortEntryB);
             if (modifier == 1) {
               return cal.compareNativeTimeFilledAsc(nsA, nsB);
             } else {
               return cal.compareNativeTimeFilledDesc(nsA, nsB);
             }
-          }
-          return compareTimesFilled
+          };
         case "string":
-          let collator = cal.createLocaleCollator();
-          function compareStrings(sortEntryA, sortEntryB) {
+          return function compareStrings(sortEntryA, sortEntryB) {
             let sA = cal.sortEntryKey(sortEntryA);
             let sB = cal.sortEntryKey(sortEntryB);
             if (sA.length == 0 || sB.length == 0) {
               // sort empty values to end (so when users first sort by a
               // column, they can see and find the desired values in that
               // column without scrolling past all the empty values).
               return -(sA.length - sB.length) * modifier;
             }
+            let collator = cal.createLocaleCollator();
             let comparison = collator.compareString(0, sA, sB);
             return comparison * modifier;
-          }
-          return compareStrings;
-
+          };
         default:
-          function compareOther(sortEntryA, sortEntryB) {
+          return function compareOther(sortEntryA, sortEntryB) {
             return 0;
-          }
-          return compareOther;
+          };
       }
     },
 
     getItemSortKey: function cal_getItemSortKey(aItem, aKey, aStartTime) {
       switch(aKey) {
         case "priority":
           return aItem.priority || 5;
 
@@ -521,16 +515,18 @@ let cal = {
         case "dueDate":
         case "entryDate":
           return "date_filled";
 
         case "priority":
         case "percentComplete":
         case "status":
           return "number";
+        default:
+          return "unknown";
       }
     },
 
     nativeTimeOrNow: function cal_nativeTimeOrNow(calDateTime, sortStartedTime) {
         // Treat null/0 as 'now' when sort started, so incomplete tasks stay current.
         // Time is computed once per sort (just before sort) so sort is stable.
         if (calDateTime == null) {
             return sortStartedTime.nativeTime;
--- a/calendar/base/modules/calXMLUtils.jsm
+++ b/calendar/base/modules/calXMLUtils.jsm
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /** Helper functions for parsing and serializing XML */
 
 Components.utils.import("resource://calendar/modules/calUtils.jsm");
 
-EXPORTED_SYMBOLS = ["cal"];
+this.EXPORTED_SYMBOLS = ["cal"];
 cal.xml = {} || cal.xml;
 
 /**
  * Evaluate an XPath query for the given node. Be careful with the return value
  * here, as it may be:
  *
  * - null, if there are no results
  * - a number, string or boolean value
--- a/calendar/base/src/calAlarm.js
+++ b/calendar/base/src/calAlarm.js
@@ -618,32 +618,33 @@ calAlarm.prototype = {
         }
     },
 
     get propertyEnumerator() {
         return this.mProperties.enumerator;
     },
 
     toString: function cA_toString(aItem) {
+        function getItemBundleStringName(aPrefix) {
+            if (!aItem || isEvent(aItem)) {
+                return aPrefix + "Event";
+            } else if (isToDo(aItem)) {
+                return aPrefix + "Task";
+            } else {
+                return aPrefix;
+            }
+        }
+
         if (this.related == ALARM_RELATED_ABSOLUTE && this.mAbsoluteDate) {
             // this is an absolute alarm. Use the calendar default timezone and
             // format it.
             let formatter = cal.getDateFormatter();
             let formatDate = this.mAbsoluteDate.getInTimezone(cal.calendarDefaultTimezone());
             return formatter.formatDateTime(formatDate);
         } else if (this.related != ALARM_RELATED_ABSOLUTE && this.mOffset) {
-            function getItemBundleStringName(aPrefix) {
-                if (!aItem || isEvent(aItem)) {
-                    return aPrefix + "Event";
-                } else if (isToDo(aItem)) {
-                    return aPrefix + "Task";
-                } else {
-                    return aPrefix;
-                }
-            }
 
             // Relative alarm length
             let alarmlen = Math.abs(this.mOffset.inSeconds / 60);
             if (alarmlen == 0) {
                 // No need to get the other information if the alarm is at the start
                 // of the event/task.
                 if (this.related == ALARM_RELATED_START) {
                     return calGetString("calendar-alarms",
--- a/calendar/base/src/calCalendarManager.js
+++ b/calendar/base/src/calCalendarManager.js
@@ -447,17 +447,17 @@ calCalendarManager.prototype = {
             if (ex instanceof Components.interfaces.nsIException) {
                 rc = ex.result;
                 uiMessage = ex.message;
             }
             switch (rc) {
                 case Components.interfaces.calIErrors.STORAGE_UNKNOWN_SCHEMA_ERROR:
                     // For now we alert and quit on schema errors like we've done before:
                     this.alertAndQuit();
-                    return;
+                    return null;
                 case Components.interfaces.calIErrors.STORAGE_UNKNOWN_TIMEZONES_ERROR:
                     uiMessage = calGetString("calendar", "unknownTimezonesError", [uri.spec]);
                     break;
                 default:
                     uiMessage = calGetString("calendar", "unableToCreateProvider", [uri.spec]);
                     break;
             }
             // Log the original exception via error console to provide more debug info
@@ -941,73 +941,64 @@ calMgrCalendarObserver.prototype = {
 
         this.storedReadOnly = this.calendar.readOnly;
         var errorCode = calGetString("calendar","errorCode", [errCode]);
         var errorDescription = calGetString("calendar","errorDescription", [message]);
         var summary = errMsg + " " + errorCode + ". " + errorDescription;
 
         // Log warnings in error console.
         // Report serious errors in both error console and in prompt window.
-        var isSerious = (aErrNo == calIErrors.MODIFICATION_FAILED);
-        if (!isSerious) {
-            WARN(summary);
-        } else {
-            // Write error to console.
+        if (aErrNo == calIErrors.MODIFICATION_FAILED) {
             Components.utils.reportError(summary);
-
-            // silently don't do anything if this message already has
-            // been announced without being acknowledged.
-            if (this.announcedMessages.some(
-                function(element, index, array) {
-                    return equalMessage(paramBlock, element);
-                })) {
-                return;
-            }
-
-            // this message hasn't been announced recently, remember the
-            // details of the message for future reference.
-            this.announcedMessages.push(paramBlock);
+            this.announceParamBlock(paramBlock);
+        } else {
+            cal.WARN(summary);
+        }
+    },
 
-            // Display in prompt window.
-            var promptWindow =
-                Services.ww.openWindow
-                    (null, "chrome://calendar/content/calendar-error-prompt.xul",
-                     "_blank", "chrome,dialog=yes,alwaysRaised=yes",
-                     paramBlock);
-            // Will remove paramBlock from announced messages when
-            // promptWindow is closed.  (Closing fires unloaded event, but
-            // promptWindow is also unloaded [to clean it?] before loading,
-            // so wait for detected load event before detecting unload event
-            // that signifies user closed this prompt window.)
-            var observer = this;
-            function awaitLoad(event) {
-                // #2 loaded, remove load listener
-                promptWindow.removeEventListener("load", awaitLoad, false);
-                function awaitUnload(event) {
-                    // #4 unloaded (user closed prompt window),
-                    // remove paramBlock and unload listener.
-                    try {
-                        // remove the message that has been shown from
-                        // the list of all announced messages.
-                        observer.announcedMessages =
-                            observer.announcedMessages.filter(function(msg) {
-                                return !equalMessage(msg, paramBlock);
-                            });
-                        promptWindow.removeEventListener("unload", awaitUnload,
-                                                         false);
-                    } catch (e) {
-                        Components.utils.reportError(e);
-                    }
-                }
-                // #3 add unload listener (wait for user to close promptWindow)
-                promptWindow.addEventListener("unload", awaitUnload, false);
+    announceParamBlock: function(paramBlock) {
+        function awaitLoad(event) {
+            promptWindow.removeEventListener("load", awaitLoad, false);
+            promptWindow.addEventListener("unload", awaitUnload, false);
+        }
+        let awaitUnload = (event) => {
+            promptWindow.removeEventListener("unload", awaitUnload, false);
+            // unloaded (user closed prompt window),
+            // remove paramBlock and unload listener.
+            try {
+                // remove the message that has been shown from
+                // the list of all announced messages.
+                this.announcedMessages = this.announcedMessages.filter((msg) => {
+                    return !equalMessage(msg, paramBlock);
+                });
+            } catch (e) {
+                Components.utils.reportError(e);
             }
-            // #1 add load listener
-            promptWindow.addEventListener("load", awaitLoad, false);
+        };
+
+        // silently don't do anything if this message already has been
+        // announced without being acknowledged.
+        if (this.announcedMessages.some(equalMessage.bind(null, paramBlock))) {
+            return;
         }
+
+        // this message hasn't been announced recently, remember the details of
+        // the message for future reference.
+        this.announcedMessages.push(paramBlock);
+
+        // Will remove paramBlock from announced messages when promptWindow is
+        // closed.  (Closing fires unloaded event, but promptWindow is also
+        // unloaded [to clean it?] before loading, so wait for detected load
+        // event before detecting unload event that signifies user closed this
+        // prompt window.)
+        let promptUrl = "chrome://calendar/content/calendar-error-prompt.xul";
+        let features = "chrome,dialog=yes,alwaysRaised=yes";
+        let promptWindow =  Services.ww.openWindow(null, url, "_blank",
+                                                   features, paramBlock);
+        promptWindow.addEventListener("load", awaitLoad, false);
     }
 };
 
 function calDummyCalendar(type) {
     this.initProviderBase();
     this.type = type;
 }
 calDummyCalendar.prototype = {
--- a/calendar/base/src/calTimezoneService.js
+++ b/calendar/base/src/calTimezoneService.js
@@ -284,16 +284,21 @@ function guessSystemTimezone() {
     const tzNameJun = nameDataJun && nameDataJun[2];
     const tzNameDec = nameDataDec && nameDataDec[2];
     const offsetRegex = /[+-]\d{4}/;
     const offsetJun = dateJun.match(offsetRegex)[0];
     const offsetDec = dateDec.match(offsetRegex)[0];
 
     const tzSvc = cal.getTimezoneService();
 
+    var continent = "Africa|America|Antarctica|Asia|Australia|Europe";
+    var ocean     = "Arctic|Atlantic|Indian|Pacific";
+    var tzRegex   = new RegExp(".*((?:"+continent+"|"+ocean+")"+
+                               "(?:[/][-A-Z_a-z]+)+)");
+
     function getIcalString(component, property) {
         var prop = (component && component.getFirstProperty(property));
         return (prop ? prop.valueAsIcalString : null);
     }
 
     // Check if Olson ZoneInfo timezone matches OS/JSDate timezone properties:
     // * standard offset and daylight/summer offset if present (longitude),
     // * if has summer time, direction of change (northern/southern hemisphere)
@@ -476,16 +481,79 @@ function guessSystemTimezone() {
                     }
                 }
             }
         }
         // no such period found
         return null;
     }
 
+    function environmentVariableValue(varName) {
+        let envSvc = Components.classes["@mozilla.org/process/environment;1"]
+                                .getService(Components.interfaces.nsIEnvironment);
+        let value = envSvc.get(varName);
+        if (!value) return "";
+        if (!value.match(tzRegex)) return "";
+        return varName+"="+value;
+    }
+
+    function symbolicLinkTarget(filepath) {
+        try {
+            let file = Components.classes["@mozilla.org/file/local;1"]
+                                 .createInstance(Components.interfaces.nsILocalFile);
+            file.initWithPath(filepath);
+            file.QueryInterface(Components.interfaces.nsIFile);
+            if (!file.exists()) return "";
+            if (!file.isSymlink()) return "";
+            if (!file.target.match(tzRegex)) return "";
+            return filepath +" -> "+file.target;
+        } catch (ex) {
+            Components.utils.reportError(filepath+": "+ex);
+            return "";
+        }
+    }
+
+    function fileFirstZoneLineString(filepath) {
+        // return first line of file that matches tzRegex (ZoneInfo id),
+        // or "" if no file or no matching line.
+        try {
+            let file = Components.classes["@mozilla.org/file/local;1"]
+                                 .createInstance(Components.interfaces.nsILocalFile);
+            file.initWithPath(filepath);
+            file.QueryInterface(Components.interfaces.nsIFile);
+            if (!file.exists()) return "";
+            let fileInstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
+                                         .createInstance(Components.interfaces.nsIFileInputStream);
+            const PR_RDONLY = 0x1;
+            fileInstream.init(file, PR_RDONLY, 0, 0);
+            fileInstream.QueryInterface(Components.interfaces.nsILineInputStream);
+            try {
+                let line = {}, hasMore = true, MAXLINES = 10;
+                for (let i = 0; hasMore && i < MAXLINES; i++) {
+                    hasMore = fileInstream.readLine(line);
+                    if (line.value && line.value.match(tzRegex)) {
+                        return filepath+": "+line.value;
+                    }
+                }
+                return ""; // not found
+            } finally {
+                fileInstream.close();
+            }
+        } catch (ex) {
+            Components.utils.reportError(filepath+": "+ex);
+            return "";
+        }
+    }
+
+    function weekday(icsDate, tz) {
+        let calDate = cal.createDateTime(icsDate);
+        calDate.timezone = tz;
+        return calDate.jsDate.toLocaleFormat("%a");
+    }
+
     // Try to find a tz that matches OS/JSDate timezone.  If no name match,
     // will use first of probable timezone(s) with highest score.
     var probableTZId = "floating"; // default fallback tz if no tz matches.
     var probableTZScore = 0;
     var probableTZSource = null;
 
     const calProperties = Services.strings.createBundle("chrome://calendar/locale/calendar.properties");
 
@@ -554,84 +622,22 @@ function guessSystemTimezone() {
             // The timezone is set per user via the TZ environment variable.
             // TZ may contain a path that may start with a colon and ends with
             // a ZoneInfo timezone identifier, such as ":America/New_York" or
             // ":/share/lib/zoneinfo/America/New_York".  The others are
             // in the filesystem so they give one timezone for the system;
             // the values are similar (but cannot have a leading colon).
             // (Note: the OS ZoneInfo database may be a different version from
             // the one we use, so still need to check that DST dates match.)
-            var continent = "Africa|America|Antarctica|Asia|Australia|Europe";
-            var ocean     = "Arctic|Atlantic|Indian|Pacific";
-            var tzRegex   = new RegExp(".*((?:"+continent+"|"+ocean+")"+
-                                       "(?:[/][-A-Z_a-z]+)+)");
-            const CC = Components.classes;
-            const CI = Components.interfaces;
-            var envSvc = (CC["@mozilla.org/process/environment;1"]
-                          .getService(Components.interfaces.nsIEnvironment));
-            function environmentVariableValue(varName) {
-                var value = envSvc.get(varName);
-                if (!value) return "";
-                if (!value.match(tzRegex)) return "";
-                return varName+"="+value;
-            }
-            function symbolicLinkTarget(filepath) {
-                try {
-                    var file = (CC["@mozilla.org/file/local;1"]
-                                .createInstance(CI.nsILocalFile));
-                    file.initWithPath(filepath);
-                    file.QueryInterface(CI.nsIFile);
-                    if (!file.exists()) return "";
-                    if (!file.isSymlink()) return "";
-                    if (!file.target.match(tzRegex)) return "";
-                    return filepath +" -> "+file.target;
-                } catch (ex) {
-                    Components.utils.reportError(filepath+": "+ex);
-                    return "";
-                }
-            }
-            function fileFirstZoneLineString(filepath) {
-                // return first line of file that matches tzRegex (ZoneInfo id),
-                // or "" if no file or no matching line.
-                try {
-                    var file = (CC["@mozilla.org/file/local;1"]
-                                .createInstance(CI.nsILocalFile));
-                    file.initWithPath(filepath);
-                    file.QueryInterface(CI.nsIFile);
-                    if (!file.exists()) return "";
-                    var fileInstream =
-                        (CC["@mozilla.org/network/file-input-stream;1"].
-                         createInstance(CI.nsIFileInputStream));
-                    const PR_RDONLY = 0x1;
-                    fileInstream.init(file, PR_RDONLY, 0, 0);
-                    fileInstream.QueryInterface(CI.nsILineInputStream);
-                    try {
-                        var line = {}, hasMore = true, MAXLINES = 10;
-                        for (var i = 0; hasMore && i < MAXLINES; i++) {
-                            hasMore = fileInstream.readLine(line);
-                            if (line.value && line.value.match(tzRegex)) {
-                                return filepath+": "+line.value;
-                            }
-                        }
-                        return ""; // not found
-                    } finally {
-                        fileInstream.close();
-                    }
-                } catch (ex) {
-                    Components.utils.reportError(filepath+": "+ex);
-                    return "";
-                }
-
-            }
             osUserTimeZone = (environmentVariableValue("TZ") ||
                               symbolicLinkTarget("/etc/localtime") ||
                               fileFirstZoneLineString("/etc/TIMEZONE") ||
                               fileFirstZoneLineString("/etc/timezone") ||
                               fileFirstZoneLineString("/etc/sysconfig/clock"));
-            var results = osUserTimeZone.match(tzRegex);
+            let results = osUserTimeZone.match(tzRegex);
             if (results) {
                 zoneInfoIdFromOSUserTimeZone = results[1];
             }
         }
 
         // check how well OS tz matches tz defined in our version of zoneinfo db
         if (zoneInfoIdFromOSUserTimeZone != null) {
             var tzId = zoneInfoIdFromOSUserTimeZone;
@@ -744,30 +750,24 @@ function guessSystemTimezone() {
             var standard = findCurrentTimePeriod(tz, subComp, "STANDARD");
             var standardTZOffset = getIcalString(standard, "TZOFFSETTO");
             var daylight = findCurrentTimePeriod(tz, subComp, "DAYLIGHT");
             var daylightTZOffset = getIcalString(daylight, "TZOFFSETTO");
             var warningDetail;
             if (probableTZScore == 1) {
                 // score 1 means has daylight time,
                 // but transitions start on different weekday from os timezone.
-                function weekday(icsDate) {
-                    var calDate = cal.createDateTime();
-                    calDate.icalString = icsDate;
-                    calDate.timezone = tz;
-                    return cal.dateTimeToJsDate(calDate).toLocaleFormat("%a");
-                }
                 var standardStart = getIcalString(standard, "DTSTART");
-                var standardStartWeekday = weekday(standardStart);
+                var standardStartWeekday = weekday(standardStart, tz);
                 var standardRule  = getIcalString(standard, "RRULE");
                 var standardText =
                     ("  Standard: "+standardStart+" "+standardStartWeekday+"\n"+
                      "            "+standardRule+"\n");
                 var daylightStart = getIcalString(daylight, "DTSTART");
-                var daylightStartWeekday = weekday(daylightStart);
+                var daylightStartWeekday = weekday(daylightStart, tz);
                 var daylightRule  = getIcalString(daylight, "RRULE");
                 var daylightText =
                     ("  Daylight: "+daylightStart+" "+daylightStartWeekday+"\n"+
                      "            "+daylightRule+"\n");
                 warningDetail =
                     ((standardStart < daylightStart
                       ? standardText + daylightText
                       : daylightText + standardText)+
--- a/calendar/base/src/calTransactionManager.js
+++ b/calendar/base/src/calTransactionManager.js
@@ -46,36 +46,24 @@ calTransactionManager.prototype = {
         this.transactionManager.beginBatch(null);
     },
 
     endBatch: function cTM_endBatch() {
         this.transactionManager.endBatch(false);
     },
 
     checkWritable: function cTM_checkWritable(transaction) {
-        if (transaction) {
-            transaction = transaction.wrappedJSObject;
-            if (transaction) {
-                function checkItem(item) {
-                    if (item) {
-                        var calendar = item.calendar;
-                        if (calendar && (!isCalendarWritable(calendar) || !userCanAddItemsToCalendar(calendar))) {
-                            return false;
-                        }
-                    }
-                    return true;
-                }
+        function checkItem(item) {
+            return item && item.calendar &&
+                   isCalendarWritable(item.calendar) &&
+                   userCanAddItemsToCalendar(item.calendar);
+        }
 
-                if (!checkItem(transaction.mItem) ||
-                    !checkItem(transaction.mOldItem)) {
-                    return false;
-                }
-            }
-        }
-        return true;
+        let trans = transaction && transaction.wrappedJSObject;
+        return trans && checkItem(trans.mItem) && checkItem(trans.mOldItem);
     },
 
     undo: function cTM_undo() {
         this.transactionManager.undoTransaction();
     },
 
     canUndo: function cTM_canUndo() {
         return ((this.transactionManager.numberOfUndoItems > 0) &&
--- a/calendar/base/src/calUtils.js
+++ b/calendar/base/src/calUtils.js
@@ -1181,35 +1181,32 @@ calInterfaceBag.prototype = {
     },
 
     get interfaceArray() {
         return this.mInterfaces;
     },
 
     add: function calInterfaceBag_add(iface) {
         if (iface) {
-            var iid = this.mIid;
-            function eq(obj) {
-                return compareObjects(obj, iface, iid);
+            let existing = this.mInterfaces.some(obj => {
+                return compareObjects(obj, iface, this.mIid);
+            });
+            if (!existing) {
+                this.mInterfaces.push(iface);
             }
-            if (!this.mInterfaces.some(eq)) {
-                this.mInterfaces.push(iface);
-                return true;
-            }
+            return !existing;
         }
         return false;
     },
 
     remove: function calInterfaceBag_remove(iface) {
         if (iface) {
-            var iid = this.mIid;
-            function neq(obj) {
-                return !compareObjects(obj, iface, iid);
-            }
-            this.mInterfaces = this.mInterfaces.filter(neq);
+            this.mInterfaces = this.mInterfaces.filter((obj) => {
+                return !compareObjects(obj, iface, this.mIid);
+            });
         }
     },
 
     forEach: function calInterfaceBag_forEach(func) {
         this.mInterfaces.forEach(func);
     }
 };
 
@@ -1282,20 +1279,17 @@ calOperationGroup.prototype = {
     add: function calOperationGroup_add(op) {
         if (op && op.isPending) {
             this.mSubOperations.push(op);
         }
     },
 
     remove: function calOperationGroup_remove(op) {
         if (op) {
-            function filterFunc(op_) {
-                return (op.id != op_.id);
-            }
-            this.mSubOperations = this.mSubOperations.filter(filterFunc);
+            this.mSubOperations = this.mSubOperations.filter(op_ => op.id != op_.id);
         }
     },
 
     get isEmpty() {
         return (this.mSubOperations.length == 0);
     },
 
     notifyCompleted: function calOperationGroup_notifyCompleted(status) {
@@ -1333,20 +1327,19 @@ calOperationGroup.prototype = {
             this.notifyCompleted(status);
             var cancelFunc = this.mCancelFunc;
             if (cancelFunc) {
                 this.mCancelFunc = null;
                 cancelFunc();
             }
             var subOperations = this.mSubOperations;
             this.mSubOperations = [];
-            function forEachFunc(op) {
+            for (let op of subOperations) {
                 op.cancel(Components.interfaces.calIErrors.OPERATION_CANCELLED);
             }
-            subOperations.forEach(forEachFunc);
         }
     }
 };
 
 function sameDay(date1, date2) {
     if (date1 && date2) {
         if ((date1.day == date2.day) &&
             (date1.month == date2.month) &&
--- a/calendar/providers/caldav/calDavCalendar.js
+++ b/calendar/providers/caldav/calDavCalendar.js
@@ -624,23 +624,25 @@ calDavCalendar.prototype = {
             let method = pure ? "notifyPureOperationComplete" : "notifyOperationComplete";
             this[method](aListener, status, cIOL.ADD, aItem.id, detail);
         };
         if (aItem.id == null && aItem.isMutable) {
             aItem.id = cal.getUUID();
         }
 
         if (aItem.id == null) {
-            return notifyListener(Components.results.NS_ERROR_FAILURE,
-                                  "Can't set ID on non-mutable item to addItem");
+            notifyListener(Components.results.NS_ERROR_FAILURE,
+                           "Can't set ID on non-mutable item to addItem");
+            return;
         }
 
         if (!isItemSupported(aItem, this)) {
-            return notifyListener(Components.results.NS_ERROR_FAILURE,
-                                  "Server does not support item type");
+            notifyListener(Components.results.NS_ERROR_FAILURE,
+                           "Server does not support item type");
+            return;
         }
 
         let parentItem = aItem.parentItem;
         parentItem.calendar = this.superCalendar;
 
         let locationPath = this.getItemLocationPath(parentItem);
         let itemUri = this.makeUri(locationPath);
         cal.LOG("CalDAV: itemUri.spec = " + itemUri.spec);
@@ -742,18 +744,19 @@ calDavCalendar.prototype = {
      * @param aIgnoreEtag ignore item etag
      */
     doModifyItem: function caldav_doModifyItem(aNewItem, aOldItem, aListener, aIgnoreEtag){
         let notifyListener = (status, detail, pure=false) => {
             let method = pure ? "notifyPureOperationComplete" : "notifyOperationComplete";
             this[method](aListener, status, cIOL.MODIFY, aNewItem.id, detail);
         };
         if (aNewItem.id == null) {
-            return notifyListener(Components.results.NS_ERROR_FAILURE,
-                                  "ID for modifyItem doesn't exist or is null");
+            notifyListener(Components.results.NS_ERROR_FAILURE,
+                           "ID for modifyItem doesn't exist or is null");
+            return;
         }
 
         let wasInboxItem = this.mItemInfoCache[aNewItem.id].isInboxItem;
 
         let newItem_ = aNewItem;
         aNewItem = aNewItem.parentItem.clone();
         if (newItem_.parentItem != newItem_) {
             aNewItem.recurrenceInfo.modifyException(newItem_, false);
@@ -866,33 +869,35 @@ calDavCalendar.prototype = {
      * */
     doDeleteItem: function caldav_doDeleteItem(aItem, aListener, aIgnoreEtag, aFromInbox, aUri){
         let notifyListener = (status, detail, pure=false) => {
             let method = pure ? "notifyPureOperationComplete" : "notifyOperationComplete";
             this[method](aListener, status, cIOL.DELETE, aItem.id, detail);
         };
 
         if (aItem.id == null) {
-            return notifyListener(Components.results.NS_ERROR_FAILURE,
-                                  "ID doesn't exist for deleteItem");
+            notifyListener(Components.results.NS_ERROR_FAILURE,
+                           "ID doesn't exist for deleteItem");
+            return;
         }
 
         var eventUri;
         if (aUri) {
             eventUri = aUri;
         } else if (aFromInbox || this.mItemInfoCache[aItem.id].isInboxItem) {
             eventUri = this.makeUri(this.mItemInfoCache[aItem.id].locationPath, this.mInboxUrl);
         } else {
             eventUri = this.makeUri(this.mItemInfoCache[aItem.id].locationPath);
         }
 
         if (eventUri.path == this.calendarUri.path) {
-            return notifyListener(Components.results.NS_ERROR_FAILURE,
-                                  "eventUri and calendarUri paths are the same, " +
-                                  "will not go on to delete entire calendar");
+            notifyListener(Components.results.NS_ERROR_FAILURE,
+                           "eventUri and calendarUri paths are the same, " +
+                           "will not go on to delete entire calendar");
+            return;
         }
 
         var thisCalendar = this;
 
         let delListener = {
             onStreamComplete: function caldav_dDI_del_onStreamComplete(aLoader, aContext, aStatus, aResultLength, aResult) {
                 let request = aLoader.request.QueryInterface(Components.interfaces.nsIHttpChannel);
                 let listenerStatus = Components.results.NS_OK;
@@ -933,17 +938,17 @@ calDavCalendar.prototype = {
                     cal.LOG("CalDAV: Item has been modified on server, checking if it has been deleted");
                     thisCalendar.sendHttpRequest(eventUri, null, null, null, (channel) => {
                         channel.requestMethod = "HEAD";
                         return delListener2;
                     }, () => {
                         notifyListener(Components.results.NS_ERROR_NOT_AVAILABLE,
                                        "Error preparing http channel");
                     });
-                    return
+                    return;
                 } else if (responseStatus >= 500 && responseStatus <= 510) {
                     listenerStatus = Components.results.NS_ERROR_NOT_AVAILABLE;
                     listenerDetail = "Server Replied with " + responseStatus;
                 } else if (responseStatus) {
                     cal.ERROR("CalDAV: Unexpected status deleting item from " +
                               thisCalendar.name + ": " + responseStatus + "\n" +
                               "uri: " + eventUri.spec);
 
@@ -1390,23 +1395,25 @@ calDavCalendar.prototype = {
             function safeRefresh_safeRefresh_onStreamComplete(aLoader, aContext, aStatus, aResultLength, aResult) {
             let request = aLoader.request.QueryInterface(Components.interfaces.nsIHttpChannel);
             try {
                 cal.LOG("CalDAV: Status " + request.responseStatus +
                         " checking ctag for calendar " + thisCalendar.name);
             } catch (ex) {
                 cal.LOG("CalDAV: Error without status on checking ctag for calendar " +
                         thisCalendar.name);
-                return notifyListener(Components.results.NS_OK);
+                notifyListener(Components.results.NS_OK);
+                return;
             }
 
             if (request.responseStatus == 404) {
                 cal.LOG("CalDAV: Disabling calendar " + thisCalendar.name +
                         " due to 404");
-                return notifyListener(Components.results.NS_ERROR_FAILURE);
+                notifyListener(Components.results.NS_ERROR_FAILURE);
+                return;
             } else if (request.responseStatus == 207 && thisCalendar.mDisabled) {
                 // Looks like the calendar is there again, check its resource
                 // type first.
                 thisCalendar.setupAuthentication(aChangeLogListener);
                 return;
              }
 
             let str = cal.convertByteArray(aResult, aResultLength);
@@ -1417,17 +1424,18 @@ calDavCalendar.prototype = {
                 cal.LOG("CalDAV: recv: " + str);
             }
 
             try {
                 var multistatus = cal.xml.parseString(str);
             } catch (ex) {
                 cal.LOG("CalDAV: Failed to get ctag from server for calendar " +
                         thisCalendar.name);
-                return notifyListener(Components.results.NS_OK);
+                notifyListener(Components.results.NS_OK);
+                return;
             }
 
             let ctag = caldavXPathFirst(multistatus, "/D:multistatus/D:response/D:propstat/D:prop/CS:getctag/text()");
             if (!ctag || ctag != thisCalendar.mCtag) {
                 // ctag mismatch, need to fetch calendar-data
                 thisCalendar.mProposedCtag = ctag;
                 thisCalendar.getUpdatedItems(thisCalendar.calendarUri,
                                              aChangeLogListener);
@@ -1634,26 +1642,24 @@ calDavCalendar.prototype = {
 
             if (this.oauth.accessToken) {
                 authSuccess();
             } else {
                 // 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.
-                function postpone() {
+                setTimeout(function postpone() {
                     let win = cal.getCalendarWindow();
                     if (!win || win.document.readyState != "complete") {
                         setTimeout(postpone, 0);
                     } else {
                         connect();
                     }
-                }
-
-                setTimeout(postpone, 0);
+                }, 0);
             }
         } else {
             authSuccess();
         }
     },
 
     /**
      * Checks that the calendar URI exists and is a CalDAV calendar.
@@ -2188,37 +2194,37 @@ calDavCalendar.prototype = {
             }
 
             let homeSets = caldavXPath(multistatus, "/D:multistatus/D:response/D:propstat/D:prop/C:calendar-home-set/D:href/text()");
             function homeSetMatches(homeSet) {
                 let normalized = homeSet.replace(/([^\/])$/, "$1/");
                 let chs = thisCalendar.mCalHomeSet;
                 return normalized == chs.path || normalized == chs.spec;
             }
+            function createBoxUrl(path) {
+                let url = thisCalendar.mUri.clone();
+                url.path = thisCalendar.ensureDecodedPath(path);
+                // Make sure the uri has a / at the end, as we do with the calendarUri.
+                if (url.path.charAt(url.path.length - 1) != '/') {
+                    url.path += "/";
+                }
+                return url;
+            }
 
             // If there are multiple home sets, we need to match the email addresses for scheduling.
             // If there is only one, assume its the right one.
             // TODO with multiple address sets, we should just use the ACL manager.
             if (homeSets && (homeSets.length == 1 || homeSets.some(homeSetMatches))) {
                 let cuaSets = caldavXPath(multistatus, "/D:multistatus/D:response/D:propstat/D:prop/C:calendar-user-address-set/D:href/text()");
                 for each (let addr in cuaSets) {
                     if (addr.match(/^mailto:/i)) {
                         thisCalendar.mCalendarUserAddress = addr;
                     }
                 }
 
-                function createBoxUrl(path) {
-                    let url = thisCalendar.mUri.clone();
-                    url.path = thisCalendar.ensureDecodedPath(path);
-                    // Make sure the uri has a / at the end, as we do with the calendarUri.
-                    if (url.path.charAt(url.path.length - 1) != '/') {
-                        url.path += "/";
-                    }
-                    return url;
-                }
 
                 let inboxPath = caldavXPathFirst(multistatus, "/D:multistatus/D:response/D:propstat/D:prop/C:schedule-inbox-URL/D:href/text()");
                 if (!inboxPath) {
                     // most likely this is a Kerio server that omits the "href"
                     inboxPath = caldavXPathFirst(multistatus, "/D:multistatus/D:response/D:propstat/D:prop/C:schedule-inbox-URL/text()");
                 }
                 thisCalendar.mInboxUrl = createBoxUrl(inboxPath);
 
@@ -2777,17 +2783,17 @@ calDavCalendar.prototype = {
                         cal.LOG("CalDAV: Failed to parse iTIP response for" +
                                 thisCalendar.name);
                     }
 
                     try {
                         var responseXML = cal.xml.parseString(str);
                     } catch (ex) {
                         cal.LOG("CalDAV: Could not parse multistatus response: " + ex + "\n" + str);
-                        return false;
+                        return;
                     }
 
                     var remainingAttendees = [];
                     // TODO The following XPath expressions are currently
                     // untested code, as I don't have a caldav-sched server
                     // available. If you find someone who does, please test!
                     let responses = caldavXPath(responseXML, "/C:schedule-response/C:response");
                     for each (let response in responses) {
--- a/calendar/providers/composite/calCompositeCalendar.js
+++ b/calendar/providers/composite/calCompositeCalendar.js
@@ -93,21 +93,16 @@ calCompositeCalendar.prototype = {
     classInfo: XPCOMUtils.generateCI({
         classID: calCompositeCalendarClassID,
         contractID: "@mozilla.org/calendar/calendar;1?type=composite",
         classDescription: "Composite Calendar Provider",
         interfaces: calCompositeCalendarInterfaces,
     }),
 
     //
-    // private members
-    //
-    mDefaultCalendar: null,
-
-    //
     // calICalendarProvider interface
     //
     get prefChromeOverlay() null,
     get displayName() cal.calGetString("calendar", "compositeName"),
 
     createCalendar: function comp_createCal() {
         throw NS_ERROR_NOT_IMPLEMENTED;
     },
@@ -385,17 +380,17 @@ calCompositeCalendar.prototype = {
         // If there are no calendars, then we just call onOperationComplete
         let enabledCalendars = this.enabledCalendars;
         if (enabledCalendars.length == 0) {
             aListener.onOperationComplete (this,
                                            Components.results.NS_OK,
                                            calIOperationListener.GET,
                                            null,
                                            null);
-            return;
+            return null;
         }
         if (this.mStatusObserver) {
             if (this.mStatusObserver.spinning == Components.interfaces.calIStatusObserver.NO_PROGRESS) {
                 this.mStatusObserver.startMeteors(Components.interfaces.calIStatusObserver.UNDETERMINED_PROGRESS, -1);
             }
         }
         let cmpListener = new calCompositeGetListenerHelper(this, aListener, aCount);
 
@@ -451,30 +446,28 @@ calCompositeGetListenerHelper.prototype 
     mOpGroup: null,
     mReceivedCompletes: 0,
     mFinished: false,
     mMaxItems: 0,
     mItemsReceived: 0,
 
     get opGroup() {
         if (!this.mOpGroup) {
-            let this_ = this;
-            function cancelFunc() { // operation group has been cancelled
-                let listener = this_.mRealListener;
-                this_.mRealListener = null;
+            this.mOpGroup = new cal.calOperationGroup(() => {
+                let listener = this.mRealListener;
+                this.mRealListener = null;
                 if (listener) {
                     listener.onOperationComplete(
-                        this_, Components.interfaces.calIErrors.OPERATION_CANCELLED,
+                        this, Components.interfaces.calIErrors.OPERATION_CANCELLED,
                         calIOperationListener.GET, null, null);
-                    if (this_.mCompositeCalendar.statusDisplayed) {
-                        this_.mCompositeCalendar.mStatusObserver.stopMeteors();
+                    if (this.mCompositeCalendar.statusDisplayed) {
+                        this.mCompositeCalendar.mStatusObserver.stopMeteors();
                     }
                 }
-            }
-            this.mOpGroup = new cal.calOperationGroup(cancelFunc);
+            });
         }
         return this.mOpGroup;
     },
 
     QueryInterface: function (aIID) {
         if (!aIID.equals(Components.interfaces.nsISupports) &&
             !aIID.equals(Components.interfaces.calIOperationListener))
         {
--- a/calendar/providers/gdata/modules/gdataSession.jsm
+++ b/calendar/providers/gdata/modules/gdataSession.jsm
@@ -285,25 +285,24 @@ calGoogleSession.prototype = {
                 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.
-                function postpone() {
+                setTimeout(function postpone() {
                     let win = cal.getCalendarWindow();
                     if (!win || win.document.readyState != "complete") {
                         setTimeout(postpone, 400);
                     } else {
                         connect();
                     }
-                }
-                setTimeout(postpone, 0);
+                }, 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(function(accessToken) {
             this.mLoginPromise = null;
--- a/calendar/providers/gdata/modules/gdataUtils.jsm
+++ b/calendar/providers/gdata/modules/gdataUtils.jsm
@@ -257,23 +257,24 @@ function EventToJSON(aItem, aOfflineStor
 
     // Google does not support categories natively, but allows us to store data
     // as an "extendedProperty", so we do here
     let categories = cal.categoriesArrayToString(aItem.getCategories({}));
     addExtendedProperty("X-MOZ-CATEGORIES", categories);
 
     // Only parse attendees if they are enabled, due to bug 407961
     if (Preferences.get("calendar.google.enableAttendees", false)) {
-        const statusMap = {
-            "NEEDS-ACTION": "needsAction",
-            "DECLINED": "declined",
-            "TENTATIVE": "tentative",
-            "ACCEPTED": "accepted"
-        };
-        function createAttendee(attendee) {
+        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:")) {
@@ -282,17 +283,18 @@ function EventToJSON(aItem, aOfflineStor
 
             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 attendees = aItem.getAttendees({});
         let attendeeData = [ createAttendee(a) for each (a in attendees) ];
 
         if (aItem.organizer) {
             itemData.organizer = createAttendee(aItem.organizer);
             if (needsOrganizer) {
                 attendeeData.push(itemData.organizer);
--- a/calendar/providers/memory/calMemoryCalendar.js
+++ b/calendar/providers/memory/calMemoryCalendar.js
@@ -463,16 +463,17 @@ calMemoryCalendar.prototype = {
                        cal.checkIfInRange(item, aRangeStart, aRangeEnd)) {
                 // This needs fixing for recurring items, e.g. DTSTART of parent may occur before aRangeStart.
                 // This will be changed with bug 416975.
                 itemsFound.push(item);
             }
             if (aCount && itemsFound.length >= aCount) {
                 return cal.forEach.BREAK;
             }
+            return cal.forEach.CONTINUE;
         }, () => {
             aListener.onGetResult(this.superCalendar,
                                   Components.results.NS_OK,
                                   typeIID,
                                   null,
                                   itemsFound.length,
                                   itemsFound);
             this.notifyOperationComplete(aListener,
--- a/calendar/providers/storage/calStorageCalendar.js
+++ b/calendar/providers/storage/calStorageCalendar.js
@@ -273,17 +273,17 @@ calStorageCalendar.prototype = {
             try {
                 /**
                  * Helper function to migrate all tables from one id to the next
                  *
                  * @param db        The database to use
                  * @param newCalId  The new calendar id to set
                  * @param oldCalId  The old calendar id to look for
                  */
-                function migrateTables(db, newCalId, oldCalId) {
+                let migrateTables = function(db, newCalId, oldCalId) {
                     for each (let tbl in ["cal_alarms", "cal_attachments",
                                           "cal_attendees", "cal_events",
                                           "cal_metadata", "cal_properties",
                                           "cal_recurrence", "cal_relations",
                                           "cal_todos"]) {
                         let stmt;
                         try {
                             stmt = db.createStatement("UPDATE " + tbl +
@@ -296,17 +296,17 @@ calStorageCalendar.prototype = {
                             // Pass error through to enclosing try/catch block
                             throw e;
                         } finally {
                             if (stmt) {
                                 stmt.reset();
                             }
                         }
                     }
-                }
+                };
 
                 let id = 0;
                 let path = this.uri.path;
                 let pos = path.indexOf("?id=");
 
                 if (pos != -1) {
                     // There is an "id" parameter in the uri. This calendar
                     // has not been migrated to using the uuid as its cal_id.
@@ -1556,17 +1556,17 @@ calStorageCalendar.prototype = {
         } catch (e) {
             this.logError("Error selecting events with recurrence!", e);
         } finally {
             this.mSelectEventsWithRecurrence.reset();
         }
 
         try {
             this.prepareStatement(this.mSelectTodosWithRecurrence);
-            sp = this.mSelectTodosWithRecurrence.params;
+            let sp = this.mSelectTodosWithRecurrence.params;
             while (this.mSelectTodosWithRecurrence.executeStep()) {
                 var row = this.mSelectTodosWithRecurrence.row;
                 var item = this.getTodoFromRow(row, {});
                 this.mRecTodoCache[item.id] = item;
                 this.mRecTodoCacheOfflineFlags[item.id] = row.offline_journal || null;
             }
         } catch (e) {
             this.logError("Error selecting todos with recurrence!", e);
--- a/calendar/providers/storage/calStorageUpgrade.jsm
+++ b/calendar/providers/storage/calStorageUpgrade.jsm
@@ -249,49 +249,41 @@ function setDbVersionAndCommit(db, versi
 /**
  * Creates a function that calls the given function |funcName| on it's passed
  * database. In addition, if no database is passed, the call is ignored.
  *
  * @param funcName      The function name to delegate.
  * @return              The delegate function for the passed named function.
  */
 function createDBDelegate(funcName) {
-    let func = function(db /* , ... */) {
+    return function(db, ...args) {
         if (db) {
-            let args = Array.slice(arguments);
-            args.shift();
             try {
-                return db[funcName].apply(db, args);
+                return db[funcName](...args);
             } catch (e) {
                 cal.ERROR("Error calling '" + funcName + "' db error: '" +
                           lastErrorString(db) + "'.\nException: " + e);
                 cal.WARN(cal.STACK(10));
             }
         }
     };
-
-    func.name = "dbDelegate_" + funcName;
-    return func;
 }
 
 /**
  * Creates a delegate function for a database getter. Returns a function that
  * can be called to get the specified attribute, if a database is passed. If no
  * database is passed, no error is thrown but null is returned.
  *
  * @param getterAttr        The getter to delegate.
  * @return                  The function that delegates the getter.
  */
 function createDBDelegateGetter(getterAttr) {
-    let func = function(db) {
+    return function(db) {
         return (db ? db[getterAttr] : null);
     }
-
-    func.name = "dbDelegate_get_" + getterAttr;
-    return func;
 }
 
 // These functions use the db delegate to allow easier calling of common
 // database functions.
 var beginTransaction = createDBDelegate("beginTransaction");
 var commitTransaction = createDBDelegate("commitTransaction");
 var rollbackTransaction = createDBDelegate("rollbackTransaction");
 var createStatement = createDBDelegate("createStatement");
@@ -736,16 +728,21 @@ upgrade.v2 = upgrade.v1 = function upgra
 
 /**
  * Upgrade to version 3.
  * Bug 293707, updates to storage provider; calendar manager database locked
  * fix, r=shaver, p=vlad
  * p=vlad
  */
 upgrade.v3 = function upgrade_v3(db, version) {
+    function updateSql(tbl, field) {
+        executeSimpleSQL(db, "UPDATE " + tbl + " SET " + field + "_tz='UTC'" +
+                             " WHERE " + field + " IS NOT NULL");
+    }
+
     let tbl = upgrade.v2(version < 2 && db, version);
     LOGdb(db, "Storage: Upgrading to v3");
 
     beginTransaction(db);
     try {
 
         copyTable(tbl, "cal_items", "cal_events", db, "item_type = 0");
         copyTable(tbl, "cal_items", "cal_todos", db, "item_type = 1");
@@ -783,21 +780,16 @@ upgrade.v3 = function upgrade_v3(db, ver
 
         // The change between 2 and 3 includes the splitting of cal_items into
         // cal_events and cal_todos, and the addition of columns for
         // event_start_tz, event_end_tz, todo_entry_tz, todo_due_tz.
         // These need to default to "UTC" if their corresponding time is
         // given, since that's what the default was for v2 calendars
 
         // Fix up the new timezone columns
-        function updateSql(tbl, field) {
-            executeSimpleSQL(db, "UPDATE " + tbl + " SET " + field + "_tz='UTC'" +
-                                 " WHERE " + field + " IS NOT NULL");
-        }
-
         updateSql("cal_events", "event_start");
         updateSql("cal_events", "event_end");
         updateSql("cal_todos", "todo_entry");
         updateSql("cal_todos", "todo_due");
         updateSql("cal_todos", "todo_completed");
 
         setDbVersionAndCommit(db, 3);
     } catch (e) {
@@ -1530,16 +1522,17 @@ upgrade.v22 = function upgrade_v22(db, v
         });
         migrateToIcalString(tbl, "cal_attendees", "translateAttendee",
                             ["attendee_id", "common_name", "rsvp", "role",
                              "status", "type", "is_organizer", "properties"], db);
 
         // Update recurrence table to using icalString directly
         createFunction(db, "translateRecurrence", 17, {
             onFunctionCall: function translateRecurrence(storArgs) {
+                function parseInt10(x) parseInt(x, 10);
                 try {
                     let [aIndex, aType, aIsNegative, aDates, aCount,
                          aEndDate, aInterval, aSecond, aMinute, aHour,
                          aDay, aMonthday, aYearday, aWeekno, aMonth,
                          aSetPos, aTmpFlags] = mapStorageArgs(storArgs);
 
                     let ritem;
                     if (aType == "x-date") {
@@ -1580,17 +1573,16 @@ upgrade.v22 = function upgrade_v22(db, v
                             DAY: aDay,
                             MONTHDAY: aMonthday,
                             YEARDAY: aYearday,
                             WEEKNO: aWeekno,
                             MONTH: aMonth,
                             SETPOS: aSetPos
                         };
 
-                        function parseInt10(x) parseInt(x, 10);
                         for (let rtype in rtypes) {
                             if (rtypes[rtype]) {
                                 let comp = "BY" + rtype;
                                 let rstr = rtypes[rtype].toString()
                                 let rarray = rstr.split(",").map(parseInt10);
                                 ritem.setComponent(comp, rarray.length, rarray);
                             }
                         }
--- a/calendar/providers/wcap/calWcapCalendarItems.js
+++ b/calendar/providers/wcap/calWcapCalendarItems.js
@@ -152,17 +152,17 @@ function calWcapCalendar_getAlarmParams(
             // cs does not support explicit RELATED=END when
             // both start|entry and end|due are written
             let dur = item.duration;
             if (dur) { // both given
                 alarmStart = alarmStart.clone();
                 alarmStart.addDuration(dur);
             } // else only end|due is set, alarm makes little sense though
         }
-        
+
         let emails = "";
         if (item.hasProperty("alarmEmailAddress")) {
             emails = encodeURIComponent(item.getProperty("alarmEmailAddress"));
         } else {
             emails = this.session.getDefaultAlarmEmails({}).map(encodeURIComponent).join(";");
         }
         if (emails.length > 0) {
             params = ("&alarmStart=" + alarmStart.icalString);
@@ -274,16 +274,61 @@ function diffProperty(newItem, oldItem, 
 const METHOD_PUBLISH = 1;
 const METHOD_REQUEST = 2;
 const METHOD_REPLY   = 4;
 const METHOD_CANCEL  = 8;
 const METHOD_UPDATE  = 256;
 
 calWcapCalendar.prototype.storeItem =
 function calWcapCalendar_storeItem(bAddItem, item, oldItem, request) {
+    function getOrgId(item) {
+        return (item && item.organizer && item.organizer.id ? item.organizer.id : null);
+    }
+    function encodeAttendees(atts) {
+        function attendeeSort(one, two) {
+            one = one.id;
+            two = two.id;
+            if (one == two) {
+                return 0;
+            }
+            return (one < two ? -1 : 1);
+        }
+        atts = atts.concat([]);
+        atts.sort(attendeeSort);
+        return atts.map(this_.encodeAttendee, this_).join(";");
+    }
+    function encodeCategories(cats) {
+        cats = cats.concat([]);
+        cats.sort();
+        return cats.join(";");
+    }
+    function getPrivacy(item) {
+        return ((item.privacy && item.privacy != "") ? item.privacy : "PUBLIC");
+    }
+    function getAttachments(item) {
+        var ret;
+        var attachments = item.attachments;
+        if (attachments) {
+            var strings = [];
+            for each (var att in attachements) {
+                let wrappedAtt = cal.wrapInstance(att, Components.interfaces.calIAttachment);
+                if (typeof(att) == "string") {
+                    strings.push(encodeURIComponent(att));
+                } else if (wrappedAtt && wrappedAtt.uri) {
+                    strings.push(encodeURIComponent(wrappedAtt.uri.spec));
+                } else { // xxx todo
+                    logError("only URLs supported as attachment, not: " + att, this_);
+                }
+            }
+            strings.sort();
+            ret = strings.join(";");
+        }
+        return ret || "";
+    }
+
     var this_ = this;
     var bIsEvent = isEvent(item);
     var bIsParent = isParent(item);
 
     var method = METHOD_PUBLISH;
     var bNoSmtpNotify = false;
     var params = "";
 
@@ -353,44 +398,28 @@ function calWcapCalendar_storeItem(bAddI
         }
         if (bIsParent) {
             var recParams = this.encodeRecurrenceParams(item, oldItem, !bAddItem /* exclude EXDATEs */);
             if (recParams.length > 0) {
                 oldItem = null; // recurrence/exceptions hack: write whole master
                 params += recParams;
             }
         }
-        
-        function getOrgId(item) {
-            return (item && item.organizer && item.organizer.id ? item.organizer.id : null);
-        }
+
         var orgCalId = getCalId(item.organizer);
         if (!orgCalId) { // new events yet don't have X-S1CS-CALID set on ORGANIZER or this is outbound iTIP
             var orgId = getOrgId(item);
             if (!orgId || (orgId.toLowerCase().replace(/^mailto:/, "") == this.ownerId.toLowerCase())) {
                 orgCalId = calId; // own event
             } // else outbound
         }
-        
+
         var attendees = item.getAttendees({});
         if (attendees.length > 0) {
             // xxx todo: why ever, X-S1CS-EMAIL is unsupported though documented for calprops... WTF.
-            function encodeAttendees(atts) {
-                function attendeeSort(one, two) {
-                    one = one.id;
-                    two = two.id;
-                    if (one == two) {
-                        return 0;
-                    }
-                    return (one < two ? -1 : 1);
-                }
-                atts = atts.concat([]);
-                atts.sort(attendeeSort);
-                return atts.map(this_.encodeAttendee, this_).join(";");
-            }
             var attParam = encodeAttendees(attendees);
             if (!oldItem || attParam != encodeAttendees(oldItem.getAttendees({}))) {
                 params += ("&attendees=" + attParam);
             }
 
             if (orgCalId == calId) {
                 method = METHOD_REQUEST;
             } else {
@@ -414,21 +443,16 @@ function calWcapCalendar_storeItem(bAddI
         }
 
         var val = item.title;
         if (!oldItem || val != oldItem.title) {
             params += ("&summary=" + encodeURIComponent(val));
         }
 
         let categories = item.getCategories({});
-        function encodeCategories(cats) {
-            cats = cats.concat([]);
-            cats.sort();
-            return cats.join(";");
-        }
         let catParam = encodeCategories(categories);
         if (!oldItem || catParam != encodeCategories(oldItem.getCategories({}))) {
             params += ("&categories=" + catParam);
         }
 
         val = diffProperty(item, oldItem, "DESCRIPTION");
         if (val !== null) {
             params += ("&desc=" + encodeURIComponent(val));
@@ -442,19 +466,16 @@ function calWcapCalendar_storeItem(bAddI
             params += ("&icsUrl=" + encodeURIComponent(val));
         }
         // xxx todo: default prio is 0 (5 in sjs cs)
         val = item.priority;
         if (!oldItem || val != oldItem.priority) {
             params += ("&priority=" + encodeURIComponent(val));
         }
 
-        function getPrivacy(item) {
-            return ((item.privacy && item.privacy != "") ? item.privacy : "PUBLIC");
-        }
         var icsClass = getPrivacy(item);
         if (!oldItem || icsClass != getPrivacy(oldItem)) {
             params += ("&icsClass=" + icsClass);
         }
 
         if (!oldItem || item.status != oldItem.status) {
             switch (item.status) {
                 case "CONFIRMED":    params += "&status=0"; break;
@@ -491,42 +512,22 @@ function calWcapCalendar_storeItem(bAddI
                 params += ("&percent=" + item.percentComplete.toString(10));
             }
             if (!oldItem || !equalDatetimes(item.completedDate, oldItem.completedDate)) {
                 params += ("&completed=" + getIcalUTC(item.completedDate));
             }
         }
 
         // attachment urls:
-        function getAttachments(item) {
-            var ret = "";
-            var attachments = item.attachments;
-            if (attachments) {
-                var strings = [];
-                for each (var att in attachements) {
-                    let wrappedAtt = cal.wrapInstance(att, Components.interfaces.calIAttachment);
-                    if (typeof(att) == "string") {
-                        strings.push(encodeURIComponent(att));
-                    } else if (wrappedAtt && wrappedAtt.uri) {
-                        strings.push(encodeURIComponent(wrappedAtt.uri.spec));
-                    } else { // xxx todo
-                        logError("only URLs supported as attachment, not: " + att, this_);
-                    }
-                }
-                strings.sort();
-                ret += strings.join(";");
-            }
-            return ret;
-        }
         var val = getAttachments(item);
         if (!oldItem || val != getAttachments(oldItem)) {
             params += ("&attachments=" + val);
         }
     } // PUBLISH, REQUEST
-    
+
     var alarmParams = this.getAlarmParams(item);
     if (!oldItem || (this.getAlarmParams(oldItem) != alarmParams)) {
         if ((method == METHOD_REQUEST) && params.length == 0) {
             // assure no email notifications about this change:
             bNoSmtpNotify = true;
         }
         params += alarmParams;
     }
@@ -561,38 +562,38 @@ function calWcapCalendar_storeItem(bAddI
         } else {
             params += ("&mod=1&rid=" + getIcalUTC(ensureDateTime(item.recurrenceId))); // THIS INSTANCE
         }
 
         params += ("&method=" + method);
         if (bNoSmtpNotify) {
             params += "&smtp=0&smtpNotify=0&notify=0";
         }
-        params += "&replace=1"; // (update) don't append to any lists    
+        params += "&replace=1"; // (update) don't append to any lists
         params += "&fetch=1&relativealarm=1&compressed=1&recurring=1";
         params += "&emailorcalid=1&fmt-out=text%2Fcalendar";
 
-        function netRespFunc(err, icalRootComp) {
+        let netRespFunc = (err, icalRootComp) => {
             if (err) {
                 throw err;
             }
-            var items = this_.parseItems(icalRootComp, calICalendar.ITEM_FILTER_ALL_ITEMS,
-                                         0, null, null, true /* bLeaveMutable */);
+            var items = this.parseItems(icalRootComp, calICalendar.ITEM_FILTER_ALL_ITEMS,
+                                        0, null, null, true /* bLeaveMutable */);
             if (items.length != 1) {
-                this_.notifyError(NS_ERROR_UNEXPECTED,
-                                  "unexpected number of items: " + items.length);
+                this.notifyError(NS_ERROR_UNEXPECTED,
+                                 "unexpected number of items: " + items.length);
             }
             var newItem = items[0];
-            this_.tunnelXProps(newItem, item);
+            this.tunnelXProps(newItem, item);
             newItem.makeImmutable();
             // invalidate cached results:
-            delete this_.m_cachedResults;
+            delete this.m_cachedResults;
             // xxx todo: may log request status
             request.execRespFunc(null, newItem);
-        }
+        };
         this.issueNetworkRequest(request, netRespFunc, stringToIcal,
                                  bIsEvent ? "storeevents" : "storetodos", params,
                                  calIWcapCalendar.AC_COMP_READ |
                                  calIWcapCalendar.AC_COMP_WRITE);
     }
 };
 
 calWcapCalendar.prototype.tunnelXProps =
@@ -939,17 +940,17 @@ calWcapCalendar.prototype.parseItems = f
             parent.calendar = this.superCalendar;
             parent.setProperty("DTSTART", item.recurrenceId);
             parent.setProperty("X-MOZ-FAKED-MASTER", "1"); // this tag might be useful in the future
             parent.recurrenceInfo = createRecurrenceInfo(parent);
             fakedParents[item.id] = true;
             uid2parent[item.id] = parent;
             items.push(parent);
         }
-        if (item.id in fakedParents) { 
+        if (item.id in fakedParents) {
             let rdate = Components.classes["@mozilla.org/calendar/recurrence-date;1"]
                                   .createInstance(Components.interfaces.calIRecurrenceDate);
             rdate.date = item.recurrenceId;
             parent.recurrenceInfo.appendRecurrenceItem(rdate);
         }
 
         let recStartDate = parent.recurrenceStartDate;
         if (recStartDate && recStartDate.isDate && !item.recurrenceId.isDate) {
@@ -1058,36 +1059,36 @@ function calWcapCalendar_getItem(id, lis
     try {
         if (!id) {
             throw new Components.Exception("no item id!");
         }
         var params = "&relativealarm=1&compressed=1&recurring=1";
         params += "&emailorcalid=1&fmt-out=text%2Fcalendar&uid=";
         params += encodeURIComponent(id);
 
-        function notifyResult(icalRootComp) {
-            var items = this_.parseItems(icalRootComp, calICalendar.ITEM_FILTER_ALL_ITEMS, 0, null, null);
-            if (items.length < 1) {
-                throw new Components.Exception("no such item!");
-            }
-            if (items.length > 1) {
-                this_.notifyError(NS_ERROR_UNEXPECTED,
-                                  "unexpected number of items: " + items.length);
-            }
-            if (listener) {
-                listener.onGetResult(this_.superCalendar, NS_OK,
-                                     calIItemBase, log("getItem(): success. id=" + id, this_),
-                                     items.length, items);
-            }
-            request.execRespFunc(null, items[0]);
-        };
         // most common: try events first
         this.issueNetworkRequest(
             request,
             function fetchEventById_resp(err, icalRootComp) {
+                function notifyResult(icalRootComp) {
+                    var items = this_.parseItems(icalRootComp, calICalendar.ITEM_FILTER_ALL_ITEMS, 0, null, null);
+                    if (items.length < 1) {
+                        throw new Components.Exception("no such item!");
+                    }
+                    if (items.length > 1) {
+                        this_.notifyError(NS_ERROR_UNEXPECTED,
+                                          "unexpected number of items: " + items.length);
+                    }
+                    if (listener) {
+                        listener.onGetResult(this_.superCalendar, NS_OK,
+                                             calIItemBase, log("getItem(): success. id=" + id, this_),
+                                             items.length, items);
+                    }
+                    request.execRespFunc(null, items[0]);
+                };
                 if (err) {
                     if (!checkErrorCode(err, calIWcapErrors.WCAP_FETCH_EVENTS_BY_ID_FAILED) &&
                         !checkErrorCode(err, calIWcapErrors.WCAP_COMPONENT_NOT_FOUND)) {
                         throw err;
                     }
                     // try todos:
                     this_.issueNetworkRequest(
                         request,
@@ -1143,32 +1144,32 @@ function getItemFilterParams(itemFilter)
 }
 
 calWcapCalendar.prototype.getItems =
 function calWcapCalendar_getItems(itemFilter, maxResults, rangeStart, rangeEnd, listener) {
     rangeStart = ensureDateTime(rangeStart);
     rangeEnd = ensureDateTime(rangeEnd);
     var zRangeStart = getIcalUTC(rangeStart);
     var zRangeEnd = getIcalUTC(rangeEnd);
-    
+
     var this_ = this;
     var request = new calWcapRequest(
         function getItems_resp(request, err, data) {
             log("getItems() complete: " + errorToString(err), this_);
             this_.notifyOperationComplete(listener,
                                           getResultCode(err),
                                           calIOperationListener.GET,
                                           null,
                                           err);
         },
         log("getItems():\n\titemFilter=0x" + itemFilter.toString(0x10) +
             ",\n\tmaxResults=" + maxResults +
             ",\n\trangeStart=" + zRangeStart +
             ",\n\trangeEnd=" + zRangeEnd, this));
-    
+
     if (this.aboutToBeUnregistered) {
         // limiting the amount of network traffic while unregistering
         log("being unregistered, no results.", this);
         request.execRespFunc(null, []);
         return request;
     }
 
     // m_cachedResults holds the last data revtrieval. This is expecially useful when
--- a/calendar/providers/wcap/calWcapSession.js
+++ b/calendar/providers/wcap/calWcapSession.js
@@ -1053,25 +1053,26 @@ calWcapSession.prototype = {
             Services.obs.removeObserver(this, "quit-application");
         }
     },
 
     // calICalendarManagerObserver:
 
     // called after the calendar is registered
     onCalendarRegistered: function calWcapSession_onCalendarRegistered(aCalendar) {
+        function assureDefault(pref, val) {
+            if (aCalendar.getProperty(pref) === null) {
+                aCalendar.setProperty(pref, val);
+            }
+        }
+
         try {
             // make sure the calendar belongs to this session:
             if (this.belongsTo(aCalendar)) {
 
-                function assureDefault(pref, val) {
-                    if (aCalendar.getProperty(pref) === null) {
-                        aCalendar.setProperty(pref, val);
-                    }
-                }
 
                 assureDefault("shared_context", this.m_contextId);
                 assureDefault("name", aCalendar.name);
 
                 const s_colors = ["#FFCCCC", "#FFCC99", "#FFFF99", "#FFFFCC", "#99FF99",
                                   "#99FFFF", "#CCFFFF", "#CCCCFF", "#FFCCFF", "#FF6666",
                                   "#FF9966", "#FFFF66", "#FFFF33", "#66FF99", "#33FFFF",
                                   "#66FFFF", "#9999FF", "#FF99FF", "#FF0000", "#FF9900",