From e0f26d60fc97e29b191fb8aa90f87f6ee8ed8958 Mon Sep 17 00:00:00 2001 From: "mozilla%kewis.ch" Date: Thu, 26 Apr 2007 13:38:26 +0000 Subject: [PATCH] Fix bug 362648. r=dbo git-svn-id: svn://10.0.0.236/trunk@225088 18797224-902f-48f8-a5cc-f745e15eee43 --- .../gdata/components/calGoogleCalendar.js | 22 ++- .../gdata/components/calGoogleUtils.js | 146 +++++++++++++++++- 2 files changed, 159 insertions(+), 9 deletions(-) diff --git a/mozilla/calendar/providers/gdata/components/calGoogleCalendar.js b/mozilla/calendar/providers/gdata/components/calGoogleCalendar.js index 16b439d0df5..64c78675b46 100644 --- a/mozilla/calendar/providers/gdata/components/calGoogleCalendar.js +++ b/mozilla/calendar/providers/gdata/components/calGoogleCalendar.js @@ -84,6 +84,7 @@ calGoogleCalendar.prototype = { }, /* Member Variables */ + mID: null, mSession: null, mObservers: null, mReadOnly: false, @@ -104,6 +105,19 @@ calGoogleCalendar.prototype = { return this.mCalendarName; }, + /** + * readonly attribute isDefaultCalendar + * Returns true if this is the default calendar of the user. + */ + get isDefaultCalendar() { + // If there is no session, use the non-default calendar identifier as a + // fallback. + return ((this.mSession && + this.mCalendarName == this.mSession.googleUser) || + (!this.mSession && + this.mCalendarName.indexOf("group.calendar.google.com") < 0)); + }, + /** * attribute session * An calGoogleSession Object that handles the session requests. @@ -178,13 +192,13 @@ calGoogleCalendar.prototype = { * implement calICalendar */ // attribute AUTF8String id; - mID: null, get id() { return this.mID; }, + set id(id) { if (this.mID) - throw Components.results.NS_ERROR_ALREADY_INITIALIZED; + throw Cr.NS_ERROR_ALREADY_INITIALIZED; return (this.mID = id); }, @@ -678,7 +692,7 @@ calGoogleCalendar.prototype = { // Parse all tags for each (var entry in xml.entry) { - var item = XMLEntryToItem(entry, timezone); + var item = XMLEntryToItem(entry, timezone, this); if (item) { var itemReturnOccurrences = @@ -765,7 +779,7 @@ calGoogleCalendar.prototype = { var timezone = getPrefSafe("calendar.timezone.local"); // Parse the Item with the given timezone - var item = XMLEntryToItem(xml, timezone); + var item = XMLEntryToItem(xml, timezone, this); LOGitem(item); item.calendar = this; diff --git a/mozilla/calendar/providers/gdata/components/calGoogleUtils.js b/mozilla/calendar/providers/gdata/components/calGoogleUtils.js index 60effb30778..671261ee622 100644 --- a/mozilla/calendar/providers/gdata/components/calGoogleUtils.js +++ b/mozilla/calendar/providers/gdata/components/calGoogleUtils.js @@ -489,6 +489,74 @@ function ItemToXMLEntry(aItem, aAuthorEmail, aAuthorName) { entry.gd::when.@endTime = toRFC3339(aItem.endDate); } + // gd:reminder + if (aItem.alarmOffset) { + var gdReminder = ; + var alarmOffset = aItem.alarmOffset.clone(); + if (aItem.alarmRelated == Ci.calIItemBase.ALARM_RELATED_END) { + // Google always uses an alarm offset related to the start time + alarmOffset.addDuration(duration); + } + + // Google only accepts certain alarm values. Snap to them. See + // http://code.google.com/p/google-gdata/issues/detail?id=55 + var alarmValues = [ 300, 600, 900, 1200, 1500, 1800, 2700, 3600, 7200, + 10800, 86400, 172800, 604800 ]; + var discreteValue = alarmValues[alarmValues.length - 1] / 60; + + for (var i = 0; i < alarmValues.length; i++) { + if (-aItem.alarmOffset.inSeconds <= alarmValues[i]) { + discreteValue = alarmValues[i] / 60; + break; + } + } + + gdReminder.@minutes = discreteValue; + entry.gd::when.gd::reminder += gdReminder; + + if (!aItem.calendar.isDefaultCalendar) { + // On non-default calendars, alarms do not work as expected. This is + // an error on Google's side. We are going to work around with an + // extended property. After Google crippled alarm support, + // non-default calendars will work even better regarding alarms - at + // least in sunbird/lightning. See + // http://code.google.com/p/google-gdata/issues/detail?id=20 + + var gdExtendedReminder = ; + var alarmTime = aItem.startDate.clone(); + alarmTime.addDuration(aItem.alarmOffset); + + gdExtendedReminder.@name = "X-MOZ-ALARM-WORKAROUND"; + gdExtendedReminder.@value = toRFC3339(alarmTime); + + entry.gd::extendedProperty += gdExtendedReminder; + } + } + + // XXX Google currently only supports one reminder. Nevertheless, according + // to the Google Calendar API docs, snoozed events should be implemented by + // a second gd:reminder element with an absolute time. This issue is tracked + // at http://code.google.com/p/google-gdata/issues/detail?id=44 + + // gd:extendedProperty (alarmLastAck) + var gdAlarmLastAck = ; + gdAlarmLastAck.@name = "X-MOZ-LASTACK"; + gdAlarmLastAck.@value = toRFC3339(aItem.alarmLastAck); + entry.gd::extendedProperty += gdAlarmLastAck; + + // gd:extendedProperty (snooze time) + var gdAlarmSnoozeTime = ; + var itemSnoozeTime = aItem.getProperty("X-MOZ-SNOOZE-TIME"); + var icalSnoozeTime = createDateTime(); + if (itemSnoozeTime) { + // The propery is saved as a string, translate back to calIDateTime. + icalSnoozeTime.icalString = itemSnoozeTime; + icalSnoozeTime.normalize(); + } + gdAlarmSnoozeTime.@name = "X-MOZ-SNOOZE-TIME"; + gdAlarmSnoozeTime.@value = toRFC3339(icalSnoozeTime); + entry.gd::extendedProperty += gdAlarmSnoozeTime; + // gd:visibility var privacy = aItem.privacy || "default"; entry.gd::visibility.@value = kEVENT_SCHEMA + privacy.toLowerCase(); @@ -504,7 +572,6 @@ function ItemToXMLEntry(aItem, aAuthorEmail, aAuthorName) { // TODO gd:recurrenceException: Enhancement tracked in bug 362650 // TODO gd:comments: Enhancement tracked in bug 362653 // TODO gd:who Enhancement tracked in bug 355226 - // TODO gd:reminder: Enhancement tracked in bug 362648 // XXX Google currently has no priority support. See // http://code.google.com/p/google-gdata/issues/detail?id=52 @@ -531,8 +598,16 @@ function relevantFieldsMatch(a, b) { return false; } + function compareNotNull(prop) { + var ap = a[prop]; + var bp = b[prop]; + return (ap && !bp || !ap && bp || ap && bp && ap.compare(bp)); + } + // Object flat values - if ( + if (compareNotNull("alarmOffset") || + compareNotNull("alarmLastAck") || + /* Compare startDate and endDate */ (a.startDate && a.startDate.compare(b.startDate)) || (a.endDate && a.endDate.compare(b.endDate)) || (a.startDate.isDate != b.startDate.isDate) || @@ -542,7 +617,7 @@ function relevantFieldsMatch(a, b) { // Properties const kPROPERTIES = ["DESCRIPTION", "TRANSP", "X-GOOGLE-EDITURL", - "LOCATION", "CATEGORIES"]; + "LOCATION", "CATEGORIES", "X-MOZ-SNOOZE-TIME"]; for each (var p in kPROPERTIES) { // null and an empty string should be handled as non-relevant @@ -578,9 +653,10 @@ function getItemEditURI(aItem) { * * @param aXMLEntry The xml data of the item * @param aTimezone The timezone the event is most likely in + * @param aCalendar The calendar the event will be added to. Can be null. * @return The calIEvent with the item data. */ -function XMLEntryToItem(aXMLEntry, aTimezone) { +function XMLEntryToItem(aXMLEntry, aTimezone, aCalendar) { if (aXMLEntry == null) { throw new Components.Exception("", Cr.NS_ERROR_DOM_SYNTAX_ERR); @@ -647,8 +723,66 @@ function XMLEntryToItem(aXMLEntry, aTimezone) { item.endDate = item.startDate.clone(); } } + + // gd:reminder + var alarmOffset = Cc["@mozilla.org/calendar/duration;1"] + .createInstance(Ci.calIDuration); + if (aXMLEntry.gd::originalEvent.toString().length > 0) { + // If the item is an occurrence, we cannot change it until bug + // 362650 has been fixed. For now, don't set alarms on + // occurrences. + continue; + } else if (when.gd::reminder.@absoluteTime.toString()) { + var absolute = fromRFC3339(when.gd::reminder.@absoluteTime, + aTimezone); + alarmOffset = startDate.subtractDate(absolute); + } else if (when.gd::reminder.@days.toString()) { + alarmOffset.days = -when.gd::reminder.@days; + } else if (when.gd::reminder.@hours.toString()) { + alarmOffset.hours = -when.gd::reminder.@hours; + } else if (when.gd::reminder.@minutes.toString()) { + // There is a bug in the Google API that always sets an alarm, + // even if you didn't specify it. The value is always -1. See + // http://code.google.com/p/google-gdata/issues/detail?id=43 + // As a workaround, ignore such reminders + if (when.gd::reminder.@minutes == "-1") { + continue; + } + alarmOffset.minutes = -when.gd::reminder.@minutes; + } else { + continue; + } + alarmOffset.normalize(); + item.alarmOffset = alarmOffset; + item.alarmRelated = Ci.calIItemBase.ALARM_RELATED_START; } + // gd:extendedProperty (alarm workaround) + if (!aCalendar.isDefaultCalendar) { + var alarmTime = fromRFC3339(aXMLEntry.gd::extendedProperty + .(@name == "X-MOZ-ALARM-WORKAROUND") + .@value.toString(), aTimezone); + if (alarmTime) { + item.alarmOffset = alarmTime.subtractDate(item.startDate); + item.alarmRelated = Ci.calIItemBase.ALARM_RELATED_START; + } else { + item.alarmOffset = null; + } + } + + // gd:extendedProperty (alarmLastAck) + var alarmLastAck = aXMLEntry.gd::extendedProperty + .(@name == "X-MOZ-LASTACK") + .@value.toString(); + item.alarmLastAck = fromRFC3339(alarmLastAck, aTimezone); + + // gd:extendedProperty (snooze time) + var xmlSnoozeTime = aXMLEntry.gd::extendedProperty + .(@name == "X-MOZ-SNOOZE-TIME").@value.toString(); + var dtSnoozeTime = fromRFC3339(xmlSnoozeTime, aTimezone); + var snoozeProperty = (dtSnoozeTime ? dtSnoozeTime.icalString : null); + item.setProperty("X-MOZ-SNOOZE-TIME", snoozeProperty); + // gd:where item.setProperty("LOCATION", aXMLEntry.gd::where.@valueString.toString()); @@ -743,7 +877,6 @@ function XMLEntryToItem(aXMLEntry, aTimezone) { // TODO gd:recurrenceException: Enhancement tracked in bug 362650 // TODO gd:comments: Enhancement tracked in bug 362653 // TODO gd:who Enhancement tracked in bug 355226 - // TODO gd:reminder: Enhancement tracked in bug 362648 // XXX Google currently has no priority support. See // http://code.google.com/p/google-gdata/issues/detail?id=52 @@ -774,6 +907,9 @@ function LOGitem(item) { "\n\tendTime:" + item.endDate.toString() + "\n\tlocation:" + item.getProperty("LOCATION") + "\n\tprivacy:" + item.privacy + + "\n\talarmOffset:" + item.alarmOffset + + "\n\talarmLastAck:" + item.alarmLastAck + + "\n\tsnoozeTime:" + item.getProperty("X-MOZ-SNOOZE-TIME") + "\n\tisOccurrence:" + item.getProperty("x-GOOGLE-ITEM-IS-OCCURRENCE")); }