--- 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¬ify=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",