diff --git a/mozilla/calendar/base/content/calendar-item-editing.js b/mozilla/calendar/base/content/calendar-item-editing.js index 860ce21b0bd..e7e91f2ebcb 100644 --- a/mozilla/calendar/base/content/calendar-item-editing.js +++ b/mozilla/calendar/base/content/calendar-item-editing.js @@ -267,10 +267,9 @@ function openEventDialog(calendarItem, calendar, mode, callback, job) { // we'll open the summary dialog since the user is not allowed to change // the details of the item. var isInvitation = false; - try { + if (calendar instanceof Components.interfaces.calISchedulingSupport) { isInvitation = calendar.isInvitation(calendarItem); } - catch(e) {} // open the dialog modeless var url = "chrome://calendar/content/sun-calendar-event-dialog.xul"; diff --git a/mozilla/calendar/base/content/calendar-summary-dialog.js b/mozilla/calendar/base/content/calendar-summary-dialog.js index b14d6d4c7a9..3ab302dadf4 100644 --- a/mozilla/calendar/base/content/calendar-summary-dialog.js +++ b/mozilla/calendar/base/content/calendar-summary-dialog.js @@ -69,20 +69,15 @@ function onLoad() { } window.readOnly = calendar.readOnly; - if (!window.readOnly) { - try { - // temporary hack unless all group scheduling features are supported - // by the caching facade (calCachedCalendar): - var provider = calendar.getProperty("private.wcapCalendar") - .QueryInterface(Components.interfaces.calIWcapCalendar); - var attendee = provider.getInvitedAttendee(item); - if (attendee) { - window.attendee = attendee.clone(); - item.removeAttendee(attendee); - item.addAttendee(window.attendee); - } - } - catch(e) { + if (!window.readOnly && calendar instanceof Components.interfaces.calISchedulingSupport) { + var attendee = calendar.getInvitedAttendee(item); + if (attendee) { + window.attendee = attendee.clone(); + // Since we don't have API to update an attendee in place, remove + // and add again. Also, this is needed if the attendee doesn't exist + // (i.e REPLY on a mailing list) + item.removeAttendee(attendee); + item.addAttendee(window.attendee); } } diff --git a/mozilla/calendar/base/public/Makefile.in b/mozilla/calendar/base/public/Makefile.in index e7df373e62e..9e85ea4dfa6 100644 --- a/mozilla/calendar/base/public/Makefile.in +++ b/mozilla/calendar/base/public/Makefile.in @@ -87,6 +87,7 @@ XPIDLSRCS = calIAlarm.idl \ calITodo.idl \ calITransactionManager.idl \ calIWeekTitleService.idl \ + calISchedulingSupport.idl \ $(NULL) EXPORTS = calBaseCID.h diff --git a/mozilla/calendar/base/public/calICalendar.idl b/mozilla/calendar/base/public/calICalendar.idl index 06b7e6a77ee..ecead60aacf 100644 --- a/mozilla/calendar/base/public/calICalendar.idl +++ b/mozilla/calendar/base/public/calICalendar.idl @@ -133,6 +133,10 @@ interface calICalendar : nsISupports * [string] itip.transportType If the provider implements a custom calIItipTransport * this is the "type" used in the contract id. * [nsresult] currentStatus The current error status of the calendar (transient). + * [string] organizerId If provided, this is the preset organizer id on creating + * scheduling appointments + * [string] organizerCN If provided, this is the preset organizer common name on creating + * scheduling appointments * * The following calendar capabilities can be used to inform the UI or backend * that certain features are not supported. If not otherwise mentioned, not @@ -201,16 +205,16 @@ interface calICalendar : nsISupports */ const unsigned long ITEM_FILTER_COMPLETED_YES = 1 << 0; const unsigned long ITEM_FILTER_COMPLETED_NO = 1 << 1; - const unsigned long ITEM_FILTER_COMPLETED_ALL = - (ITEM_FILTER_COMPLETED_YES | ITEM_FILTER_COMPLETED_NO); + const unsigned long ITEM_FILTER_COMPLETED_ALL = (ITEM_FILTER_COMPLETED_YES | + ITEM_FILTER_COMPLETED_NO); const unsigned long ITEM_FILTER_TYPE_TODO = 1 << 2; const unsigned long ITEM_FILTER_TYPE_EVENT = 1 << 3; const unsigned long ITEM_FILTER_TYPE_JOURNAL = 1 << 4; - const unsigned long ITEM_FILTER_TYPE_ALL = - (ITEM_FILTER_TYPE_TODO | ITEM_FILTER_TYPE_EVENT | - ITEM_FILTER_TYPE_JOURNAL); - + const unsigned long ITEM_FILTER_TYPE_ALL = (ITEM_FILTER_TYPE_TODO | + ITEM_FILTER_TYPE_EVENT | + ITEM_FILTER_TYPE_JOURNAL); + const unsigned long ITEM_FILTER_ALL_ITEMS = 0xFFFF; /** @@ -221,6 +225,13 @@ interface calICalendar : nsISupports */ const unsigned long ITEM_FILTER_CLASS_OCCURRENCES = 1 << 16; + /** + * Scope: Attendee + * Filter items that correspond to an invitation from another + * user and the current user has not replied to it yet. + */ + const unsigned long ITEM_FILTER_REQUEST_NEEDS_ACTION = 1 << 17; + void addObserver( in calIObserver observer ); void removeObserver( in calIObserver observer ); diff --git a/mozilla/calendar/base/src/calCachedCalendar.js b/mozilla/calendar/base/src/calCachedCalendar.js index deb37ba269f..11df114b6f3 100644 --- a/mozilla/calendar/base/src/calCachedCalendar.js +++ b/mozilla/calendar/base/src/calCachedCalendar.js @@ -134,6 +134,12 @@ function calCachedCalendar(uncachedCalendar) { } calCachedCalendar.prototype = { QueryInterface: function cCC_QueryInterface(aIID) { + if (aIID.equals(Components.interfaces.calISchedulingSupport)) { + // check whether uncached calendar supports it: + if (this.mUncachedCalendar.QueryInterface(aIID)) { + return this; + } + } return doQueryInterface(this, calCachedCalendar.prototype, aIID, [Components.interfaces.calICachedCalendar, Components.interfaces.calICalendar, @@ -476,7 +482,8 @@ calCachedCalendar.prototype = { } defineForwards(calCachedCalendar.prototype, "mUncachedCalendar", - ["getProperty", "setProperty", "deleteProperty"], + ["getProperty", "setProperty", "deleteProperty", + "isInvitation", "getInvitedAttendee"], ["sendItipInvitations", "type"], ["id", "name", "uri", "readOnly"]); defineForwards(calCachedCalendar.prototype, "mCachedCalendar", ["getItem", "getItems", "startBatch", "endBatch"], [], []); diff --git a/mozilla/calendar/base/src/calItemBase.js b/mozilla/calendar/base/src/calItemBase.js index 439cc986532..8cd9955985a 100644 --- a/mozilla/calendar/base/src/calItemBase.js +++ b/mozilla/calendar/base/src/calItemBase.js @@ -452,18 +452,18 @@ calItemBase.prototype = { this.modify(); var found = false, newAttendees = []; var attendees = this.getAttendees({}); - var attIdLowerCase =attendee.id.toLowerCase(); + var attIdLowerCase = attendee.id.toLowerCase(); for (var i = 0; i < attendees.length; i++) { - if (attendees[i].id.toLowerCase() != attIdLowerCase) + if (attendees[i].id.toLowerCase() != attIdLowerCase) { newAttendees.push(attendees[i]); - else + } else { found = true; + } } - if (found) + if (found) { this.mAttendees = newAttendees; - else - throw Component.results.NS_ERROR_INVALID_ARG; + } }, removeAllAttendees: function() { diff --git a/mozilla/calendar/lightning/content/imip-bar.js b/mozilla/calendar/lightning/content/imip-bar.js index d88c2323c56..3e1b40579b2 100644 --- a/mozilla/calendar/lightning/content/imip-bar.js +++ b/mozilla/calendar/lightning/content/imip-bar.js @@ -448,7 +448,7 @@ function getTargetCalendar() { * event_status is an optional directive to set the Event STATUS property */ function setAttendeeResponse(type, eventStatus) { - var myAddress = gItipItem.identity + var myAddress = gItipItem.identity; if (!myAddress) { // Bug 420516 -- we don't support delegation yet TODO: Localize this? throw new Error("setAttendeeResponse: " + diff --git a/mozilla/calendar/prototypes/wcap/calendar-invitations-dialog.js b/mozilla/calendar/prototypes/wcap/calendar-invitations-dialog.js index b6a1ae85534..f6292d02450 100644 --- a/mozilla/calendar/prototypes/wcap/calendar-invitations-dialog.js +++ b/mozilla/calendar/prototypes/wcap/calendar-invitations-dialog.js @@ -19,6 +19,7 @@ * * Contributor(s): * Thomas Benisch + * Daniel Boelzle * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -75,10 +76,8 @@ function onLoad() { updatingBox.removeAttribute("hidden"); var args = window.arguments[0]; - args.invitationsManager.getInvitations( - false, - operationListener, - args.onLoadOperationListener); + args.invitationsManager.getInvitations(operationListener, + args.onLoadOperationListener); opener.setCursor("auto"); } diff --git a/mozilla/calendar/prototypes/wcap/calendar-invitations-list.xml b/mozilla/calendar/prototypes/wcap/calendar-invitations-list.xml index 8dd8a4ac200..d1ab7c412d9 100644 --- a/mozilla/calendar/prototypes/wcap/calendar-invitations-list.xml +++ b/mozilla/calendar/prototypes/wcap/calendar-invitations-list.xml @@ -211,17 +211,11 @@ @@ -229,20 +223,18 @@ diff --git a/mozilla/calendar/prototypes/wcap/calendar-invitations-manager.js b/mozilla/calendar/prototypes/wcap/calendar-invitations-manager.js index 11e0a45d145..ed72a45fe3b 100644 --- a/mozilla/calendar/prototypes/wcap/calendar-invitations-manager.js +++ b/mozilla/calendar/prototypes/wcap/calendar-invitations-manager.js @@ -20,6 +20,7 @@ * Contributor(s): * Thomas Benisch * Philipp Kewisch + * Daniel Boelzle * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -35,64 +36,22 @@ * * ***** END LICENSE BLOCK ***** */ -var gInvitationsRequestManager = null; +var gInvitationsRequestManager = { + mRequestStatusList: {}, -function getInvitationsRequestManager() { - if (!gInvitationsRequestManager) { - gInvitationsRequestManager = new InvitationsRequestManager(); - } - return gInvitationsRequestManager; -} - -function InvitationsRequestManager() { - this.mRequestStatusList = {}; -} - -InvitationsRequestManager.prototype = { - mRequestStatusList: null, - - getRequestStatus: function IRM_getRequestStatus(calendar) { - var calendarId = this._getCalendarId(calendar); - if (calendarId in this.mRequestStatusList) { - return this.mRequestStatusList[calendarId]; + addRequestStatus: function IRM_addRequestStatus(calendar, op) { + if (op) { + this.mRequestStatusList[calendar.id] = op; } - return null; - }, - - addRequestStatus: function IRM_addRequestStatus(calendar, requestStatus) { - var calendarId = this._getCalendarId(calendar); - this.mRequestStatusList[calendarId] = requestStatus; - }, - - deleteRequestStatus: function IRM_deleteRequestStatus(calendar) { - var calendarId = this._getCalendarId(calendar); - if (calendarId in this.mRequestStatusList) { - delete this.mRequestStatusList[calendarId]; - } - }, - - getPendingRequests: function IRM_getPendingRequests() { - var count = 0; - for each (var requestStatus in this.mRequestStatusList) { - var request = requestStatus.request; - if (request && request.isPending) { - count++; - } - } - return count; }, cancelPendingRequests: function IRM_cancelPendingRequests() { - for each (var requestStatus in this.mRequestStatusList) { - var request = requestStatus.request; + for each (var request in this.mRequestStatusList) { if (request && request.isPending) { request.cancel(null); } } - }, - - _getCalendarId: function IRM__getCalendarId(calendar) { - return encodeURIComponent(calendar.uri.spec); + this.mRequestStatusList = {}; } }; @@ -107,39 +66,22 @@ function getInvitationsManager() { function InvitationsManager() { this.mItemList = new Array(); - this.mOperationListeners = new Array(); this.mStartDate = null; this.mJobsPending = 0; this.mTimer = null; - this.mUnregisteredCalendars = new Array(); - - var calendarManagerObserver = { - mInvitationsManager: this, - onCalendarRegistered: function(aCalendar) { - }, - onCalendarUnregistering: function(aCalendar) { - this.mInvitationsManager.unregisterCalendar(aCalendar); - }, - onCalendarDeleting: function(aCalendar) { - } - }; - getCalendarManager().addObserver(calendarManagerObserver); var self = this; window.addEventListener("unload", function() { // Unload handlers get removed automatically self.cancelInvitationsUpdate(); - getCalendarManager().removeObserver(calendarManagerObserver); }, false); } InvitationsManager.prototype = { mItemList: null, - mOperationListeners: null, mStartDate: null, mJobsPending: 0, mTimer: null, - mUnregisteredCalendars: null, scheduleInvitationsUpdate: function IM_scheduleInvitationsUpdate(firstDelay, repeatDelay, @@ -149,9 +91,9 @@ InvitationsManager.prototype = { var self = this; this.mTimer = setTimeout(function startInvitationsTimer() { self.mTimer = setInterval(function repeatingInvitationsTimer() { - self.getInvitations(true, operationListener); + self.getInvitations(operationListener); }, repeatDelay); - self.getInvitations(true, operationListener); + self.getInvitations(operationListener); }, firstDelay); }, @@ -159,186 +101,96 @@ InvitationsManager.prototype = { clearTimeout(this.mTimer); }, - getInvitations: function IM_getInvitations(suppressOnError, - operationListener1, + getInvitations: function IM_getInvitations(operationListener1, operationListener2) { + var listeners = []; if (operationListener1) { - this.addOperationListener(operationListener1); + listeners.push(operationListener1); } if (operationListener2) { - this.addOperationListener(operationListener2); + listeners.push(operationListener2); } + + gInvitationsRequestManager.cancelPendingRequests(); this.updateStartDate(); - var requestManager = getInvitationsRequestManager(); - var calendars = getCalendarManager().getCalendars({}); - for each (var calendar in calendars) { - if (calendar.getProperty("disabled")) { + this.deleteAllItems(); + + var cals = getCalendarManager().getCalendars({}); + + var opListener = { + mCount: cals.length, + mRequestManager: gInvitationsRequestManager, + mInvitationsManager: this, + + // calIOperationListener + onOperationComplete: function(aCalendar, + aStatus, + aOperationType, + aId, + aDetail) { + if (--this.mCount == 0) { + this.mInvitationsManager.mItemList.sort( + function (a, b) { + return a.startDate.compare(b.startDate); + }); + for each (var listener in listeners) { + try { + if (this.mInvitationsManager.mItemList.length) { + // Only call if there are actually items + listener.onGetResult(null, + Components.results.NS_OK, + Components.interfaces.calIItemBase, + null, + this.mInvitationsManager.mItemList.length, + this.mInvitationsManager.mItemList); + } + listener.onOperationComplete(null, + Components.results.NS_OK, + Components.interfaces.calIOperationListener.GET, + null, + null); + } catch (exc) { + ERROR(exc); + } + } + } + }, + + onGetResult: function(aCalendar, + aStatus, + aItemType, + aDetail, + aCount, + aItems) { + if (Components.isSuccessCode(aStatus)) { + for each (var item in aItems) { + this.mInvitationsManager.addItem(item); + } + } + } + }; + + for each (var calendar in cals) { + if (!isCalendarWritable(calendar)) { + opListener.onOperationComplete(); continue; } - try { - // temporary hack unless all group scheduling features are supported - // by the caching facade (calCachedCalendar): - var wcapCalendar = calendar.getProperty("private.wcapCalendar") - .QueryInterface(Components.interfaces.calIWcapCalendar); - if (!wcapCalendar.isOwnedCalendar) { - continue; - } - var listener = { - mRequestManager: requestManager, - mInvitationsManager: this, - QueryInterface: function(aIID) { - if (!aIID.equals(Components.interfaces.nsISupports) && - !aIID.equals(Components.interfaces.calIOperationListener) && - !aIID.equals(Components.interfaces.calIObserver)) { - throw Components.results.NS_ERROR_NO_INTERFACE; - } - return this; - }, - - // calIOperationListener - onOperationComplete: function(aCalendar, - aStatus, - aOperationType, - aId, - aDetail) { - - if (aOperationType != Components.interfaces.calIOperationListener.GET && - aOperationType != Components.interfaces.calIWcapCalendar.SYNC) { - return; - } - var requestStatus = - this.mRequestManager.getRequestStatus(aCalendar); - if (Components.isSuccessCode(aStatus)) { - if (requestStatus.firstRequest) { - requestStatus.firstRequest = false; - requestStatus.lastUpdate = - requestStatus.firstRequestStarted; - } else { - requestStatus.lastUpdate = aDetail; - } - } - if (this.mRequestManager.getPendingRequests() == 0) { - this.mInvitationsManager - .deleteUnregisteredCalendarItems(); - this.mInvitationsManager.mItemList.sort( - function (a, b) { - var dateA = a.startDate.getInTimezone(calendarDefaultTimezone()); - var dateB = b.startDate.getInTimezone(calendarDefaultTimezone()); - return dateA.compare(dateB); - }); - var listener; - while ((listener = this.mInvitationsManager.mOperationListeners.shift())) { - if (this.mInvitationsManager.mItemList.length) { - // Only call if there are actually items - listener.onGetResult( - null, - Components.results.NS_OK, - Components.interfaces.calIItemBase, - null, - this.mInvitationsManager.mItemList.length, - this.mInvitationsManager.mItemList); - } - listener.onOperationComplete( - null, - Components.results.NS_OK, - Components.interfaces.calIOperationListener.GET, - null, - null); - } - } - }, - - onGetResult: function(aCalendar, - aStatus, - aItemType, - aDetail, - aCount, - aItems) { - if (!Components.isSuccessCode(aStatus)) { - return; - } - for each (var item in aItems) { - this.mInvitationsManager.addItem(item); - } - }, - - // calIObserver - onStartBatch: function() { - }, - - onEndBatch: function() { - }, - - onLoad: function() { - }, - - onAddItem: function(aItem) { - this.mInvitationsManager.addItem(aItem); - }, - - onModifyItem: function(aNewItem, aOldItem) { - this.mInvitationsManager.deleteItem(aNewItem); - this.mInvitationsManager.addItem(aNewItem); - }, - - onDeleteItem: function(aDeletedItem) { - this.mInvitationsManager.deleteItem(aDeletedItem); - }, - - onError: function(aCalendar, aErrNo, aMessage) { - }, - - onPropertyChanged: function(aCalendar, aName, aValue, aOldValue) { - }, - - onPropertyDeleting: function(aCalendar, aName) { - } - }; - var requestStatus = - requestManager.getRequestStatus(wcapCalendar); - if (!requestStatus) { - requestStatus = { - request: null, - firstRequest: true, - firstRequestStarted: null, - lastUpdate: null - }; - requestManager.addRequestStatus(wcapCalendar, - requestStatus); - } - if (!requestStatus.request || - !requestStatus.request.isPending) { - var filter = (suppressOnError ? - wcapCalendar.ITEM_FILTER_SUPPRESS_ONERROR : - 0); - var request; - if (requestStatus.firstRequest) { - requestStatus.firstRequestStarted = this.getDate(); - filter |= wcapCalendar.ITEM_FILTER_REQUEST_NEEDS_ACTION; - request = wcapCalendar.wrappedJSObject.getItems(filter, - 0, this.mStartDate, null, listener); - } else { - filter |= wcapCalendar.ITEM_FILTER_TYPE_EVENT; - request = wcapCalendar.syncChangesTo(null, filter, - requestStatus.lastUpdate, listener); - } - requestStatus.request = request; - } - } catch (e) { + // temporary hack unless calCachedCalendar supports REQUEST_NEEDSACTION filter: + calendar = calendar.getProperty("cache.uncachedCalendar"); + if (!calendar) { + opListener.onOperationComplete(); + continue; } - } - if (requestManager.getPendingRequests() == 0) { - this.deleteUnregisteredCalendarItems(); - var listener; - while ((listener = this.mOperationListeners.shift())) { - listener.onOperationComplete( - null, - Components.results.NS_ERROR_FAILURE, - Components.interfaces.calIOperationListener.GET, - null, - null ); + try { + var op = calendar.getItems(Components.interfaces.calICalendar.ITEM_FILTER_REQUEST_NEEDS_ACTION | + Components.interfaces.calICalendar.ITEM_FILTER_TYPE_ALL, + 0, this.mStartDate, null, opListener); + gInvitationsRequestManager.addRequestStatus(calendar, op); + } catch (exc) { + opListener.onOperationComplete(); + ERROR(exc); } } }, @@ -349,7 +201,7 @@ InvitationsManager.prototype = { args.onLoadOperationListener = onLoadOpListener; args.queue = new Array(); args.finishedCallBack = finishedCallBack; - args.requestManager = getInvitationsRequestManager(); + args.requestManager = gInvitationsRequestManager; args.invitationsManager = this; // the dialog will reset this to auto when it is done loading window.setCursor("wait"); @@ -416,17 +268,17 @@ InvitationsManager.prototype = { }, hasItem: function IM_hasItem(item) { - for (var i = 0; i < this.mItemList.length; ++i) { - if (this.mItemList[i].hashId == item.hashId) { - return true; - } - } - return false; + var hid = item.hashId; + return this.mItemList.some( + function someFunc(item_) { + return hid == item_.hashId; + }); }, addItem: function IM_addItem(item) { var recInfo = item.recurrenceInfo; if (recInfo && this.getParticipationStatus(item) != "NEEDS-ACTION") { + // scan exceptions: var ids = recInfo.getExceptionIds({}); for each (var id in ids) { var ex = recInfo.getExceptionFor(id, false); @@ -440,43 +292,22 @@ InvitationsManager.prototype = { }, deleteItem: function IM_deleteItem(item) { - var i = 0; - while (i < this.mItemList.length) { - // Delete all items with the same id from the list. - // If item is a recurrent event, also all exceptions are deleted. - if (this.mItemList[i].id == item.id) { - this.mItemList.splice(i, 1); - } else { - i++; - } - } + var id = item.id; + this.mItemList.filter( + function filterFunc(item_) { + return id != item_.id; + }); }, - addOperationListener: function IM_addOperationListener(operationListener) { - for each (var listener in this.mOperationListeners) { - if (listener == operationListener) { - return false; - } - } - this.mOperationListeners.push(operationListener); - return true; - }, - - getDate: function IM_getDate() { - var date = Components.classes["@mozilla.org/calendar/datetime;1"] - .createInstance(Components.interfaces.calIDateTime); - date.jsDate = new Date(); - return date; + deleteAllItems: function IM_deleteAllItems() { + this.mItemList = []; }, getStartDate: function IM_getStartDate() { - var date = Components.classes["@mozilla.org/calendar/datetime;1"] - .createInstance(Components.interfaces.calIDateTime); - date.jsDate = new Date(); - date = date.getInTimezone(calendarDefaultTimezone()); - date.hour = 0; - date.minute = 0; + var date = now(); date.second = 0; + date.minute = 0; + date.hour = 0; return date; }, @@ -487,70 +318,21 @@ InvitationsManager.prototype = { var startDate = this.getStartDate(); if (startDate.compare(this.mStartDate) > 0) { this.mStartDate = startDate; - var i = 0; - while (i < this.mItemList.length) { - if (!this.validateItem(this.mItemList[i])) { - this.mItemList.splice(i, 1); - } else { - i++; - } - } } } }, validateItem: function IM_validateItem(item) { var participationStatus = this.getParticipationStatus(item); - if (participationStatus != "NEEDS-ACTION") { - return false; - } - if (item.recurrenceInfo) { - return true; - } else { - var startDate = item.startDate - .getInTimezone(calendarDefaultTimezone()); - if (startDate.compare(this.mStartDate) >= 0) { - return true; - } - } - return false; + return (participationStatus == "NEEDS-ACTION" && + item.startDate.compare(this.mStartDate) >= 0); }, getParticipationStatus: function IM_getParticipationStatus(item) { - try { - // temporary hack unless all group scheduling features are supported - // by the caching facade (calCachedCalendar): - var wcapCalendar = item.calendar.getProperty("private.wcapCalendar") - .QueryInterface(Components.interfaces.calIWcapCalendar); - var attendee = wcapCalendar.getInvitedAttendee(item); - if (attendee) - return attendee.participationStatus; - } catch (e) {} - return null; - }, - - unregisterCalendar: function IM_unregisterCalendar(calendar) { - try { - var wcapCalendar = calendar.QueryInterface( - Components.interfaces.calIWcapCalendar); - this.mUnregisteredCalendars.push(wcapCalendar); - } catch (e) {} - }, - - deleteUnregisteredCalendarItems: function IM_deleteUnregisteredCalendarItems() { - var calendar; - while ((calendar = this.mUnregisteredCalendars.shift())) { - // delete all unregistered calendar items - var i = 0; - while (i < this.mItemList.length) { - if (this.mItemList[i].calendar.uri.equals(calendar.uri)) { - this.mItemList.splice(i, 1); - } else { - i++; - } - } - // delete unregistered calendar request status entry - getInvitationsRequestManager().deleteRequestStatus(calendar); + var attendee; + if (item.calendar instanceof Components.interfaces.calISchedulingSupport) { + var attendee = item.calendar.getInvitedAttendee(item); } + return (attendee ? attendee.participationStatus : null); } }; diff --git a/mozilla/calendar/prototypes/wcap/sun-calendar-event-dialog-attendees.js b/mozilla/calendar/prototypes/wcap/sun-calendar-event-dialog-attendees.js index f7ddc0602e9..691dea33b27 100644 --- a/mozilla/calendar/prototypes/wcap/sun-calendar-event-dialog-attendees.js +++ b/mozilla/calendar/prototypes/wcap/sun-calendar-event-dialog-attendees.js @@ -573,11 +573,8 @@ function onChangeCalendar(calendar) { // assume we're the organizer [in case that the calendar // does not support the concept of identities]. gIsInvitation = false; - - try { - gIsInvitation = provider.isInvitation(args.item); - } - catch (e) { + if (args.item.calendar instanceof Components.interfaces.calISchedulingSupport) { + gIsInvitation = args.item.calendar.isInvitation(args.item); } if (gIsReadOnly || gIsInvitation) { diff --git a/mozilla/calendar/prototypes/wcap/sun-calendar-event-dialog-attendees.xml b/mozilla/calendar/prototypes/wcap/sun-calendar-event-dialog-attendees.xml index f597a0e063a..290575bb0db 100644 --- a/mozilla/calendar/prototypes/wcap/sun-calendar-event-dialog-attendees.xml +++ b/mozilla/calendar/prototypes/wcap/sun-calendar-event-dialog-attendees.xml @@ -197,18 +197,12 @@ // assume we're the organizer [in case that the calendar // does not support the concept of identities]. this.mIsInvitation = false; - this.mOrganizerID = ((organizer && organizer.id) ? organizer.id : ""); - try { - // temporary hack unless all group scheduling features are supported - // by the caching facade (calCachedCalendar): - var provider = calendar.getProperty("private.wcapCalendar") - .QueryInterface(Components.interfaces.calIWcapCalendar); - this.mIsInvitation = provider.isInvitation(args.item); - if (this.mOrganizerID.length == 0) { - this.mOrganizerID = provider.ownerId; // sensible default - } - } - catch (e) { + this.mOrganizerID = ((organizer && organizer.id) ? + organizer.id : + calendar.getProperty("organizerId")); + + if (calendar instanceof Components.interfaces.calISchedulingSupport) { + this.mIsInvitation = calendar.isInvitation(args.item); } var listbox = @@ -243,19 +237,8 @@ organizer.participationStatus = "ACCEPTED"; } } - try { - // temporary hack unless all group scheduling features are supported - // by the caching facade (calCachedCalendar): - var provider = calendar.getProperty("private.wcapCalendar") - .QueryInterface(Components.interfaces.calIWcapCalendar); - var props = provider.getCalendarProperties("X-S1CS-CALPROPS-COMMON-NAME", {}); - if (props.length > 0) { - if(organizer.commonName.length <= 0) { - organizer.commonName = props[0]; - } - } - } - catch (e) { + if (!organizer.commonName.length) { + organizer.commonName = calendar.getProperty("organizerCN"); } this.appendAttendee(organizer, listbox, template, true); } diff --git a/mozilla/calendar/providers/base/calProviderBase.js b/mozilla/calendar/providers/base/calProviderBase.js index b890d6403c9..7212ab3e357 100644 --- a/mozilla/calendar/providers/base/calProviderBase.js +++ b/mozilla/calendar/providers/base/calProviderBase.js @@ -43,7 +43,8 @@ calProviderBase.prototype = { QueryInterface: function cPB_QueryInterface(aIID) { return doQueryInterface(this, calProviderBase.prototype, aIID, [Components.interfaces.nsISupports, - Components.interfaces.calICalendar]); + Components.interfaces.calICalendar, + Components.interfaces.calISchedulingSupport]); }, mID: null, @@ -200,6 +201,11 @@ calProviderBase.prototype = { // nsIVariant getProperty(in AUTF8String aName); getProperty: function cPB_getProperty(aName) { + // temporary hack to get the uncached calendar instance + if (aName == "cache.uncachedCalendar") { + return this; + } + var ret = this.mProperties[aName]; if (ret === undefined) { ret = null; @@ -290,5 +296,52 @@ calProviderBase.prototype = { // void removeObserver( in calIObserver observer ); removeObserver: function cPB_removeObserver(aObserver) { this.mObservers.remove(aObserver); + }, + + // calISchedulingSupport: Implementation corresponding to our iTIP/iMIP support + isInvitation: function cPB_isInvitation(aItem) { + return this.getInvitedAttendee(aItem) != null; + }, + + // helper function to filter invitations, checks exceptions for invitations: + itip_checkInvitation: function cPB_itip_checkInvitation(aItem) { + if (this.isInvitation(aItem)) { + return true; + } + var recInfo = aItem.recurrenceInfo; + if (recInfo) { + var this_ = this; + function checkExc(rid) { + return this_.isInvitation(recInfo.getExceptionFor(rid, false)); + } + return recInfo.getExceptionIds({}).some(checkExc); + } + return false; + }, + + itip_getInvitedAttendee: function cPB_itip_getInvitedAttendee(aItem) { + // This is the iTIP specific base implementation for storage and memory, + // it will mind what account has received the incoming message, e.g. +// var account = aItem.getProperty("X-MOZ-IMIP-INCOMING-ACCOUNT"); +// if (account) { +// account = ("mailto:" + account); +// var att = aItem.getAttendeeById(account); +// if (att) { +// // we take the existing attendee +// return att; +// } +// // else user may have changed mail accounts, or we has been invited via ml +// // in any way, we create a new attendee to be added here, which may be +// // overridden by UI in case that account doesn't exist anymore: +// att = Components.classes["@mozilla.org/calendar/attendee;1"] +// .createInstance(Components.interfaces.calIAttendee); +// att.participationStatus = "NEEDS-ACTION"; +// att.id = account; +// } + // for now not impl + return null; + }, + getInvitedAttendee: function cPB_getInvitedAttendee(aItem) { + return this.itip_getInvitedAttendee(aItem); } }; diff --git a/mozilla/calendar/providers/gdata/components/calGoogleCalendar.js b/mozilla/calendar/providers/gdata/components/calGoogleCalendar.js index 1f2948b25d1..bbdf42f1d9a 100644 --- a/mozilla/calendar/providers/gdata/components/calGoogleCalendar.js +++ b/mozilla/calendar/providers/gdata/components/calGoogleCalendar.js @@ -250,6 +250,16 @@ calGoogleCalendar.prototype = { return false; case "capabilities.privacy.values": return ["DEFAULT", "PUBLIC", "PRIVATE"]; + case "organizerId": + if (this.mSession) { + return this.session.userName; + } + break; + case "organizerCN": + if (this.mSession) { + return this.session.fullName; + } + break; } return this.__proto__.__proto__.getProperty.apply(this, arguments); @@ -530,16 +540,15 @@ calGoogleCalendar.prototype = { // item base type var wantEvents = ((aItemFilter & Components.interfaces.calICalendar.ITEM_FILTER_TYPE_EVENT) != 0); - var wantTodos = ((aItemFilter & - Components.interfaces.calICalendar.ITEM_FILTER_TYPE_TODO) != 0); + var wantInvitations = ((aItemFilter & + Components.interfaces.calICalendar.ITEM_FILTER_REQUEST_NEEDS_ACTION) != 0); - // check if events are wanted - if (!wantEvents && !wantTodos) { - // Nothing to do. The notifyOperationComplete in the catch block - // below will catch this. + + if (!wantEvents) { + // Events are not wanted, nothing to do. The + // notifyOperationComplete in the catch block below will catch + // this. throw new Components.Exception("", Components.results.NS_OK); - } else if (wantTodos && !wantEvents) { - throw new Components.Exception("", Components.results.NS_ERROR_NOT_IMPLEMENTED); } // Requesting only a DATE returns items based on UTC. Therefore, we make @@ -789,7 +798,7 @@ calGoogleCalendar.prototype = { * @param aData In case of an error, this is the error string, otherwise * an XML representation of the added item. */ - getItems_response: function cGC_getItems_response_onResult(aOperation, aData) { + getItems_response: function cGC_getItems_response(aOperation, aData) { // To simplify code, provide a one-stop function to call, independant of // if and what type of listener was passed. var listener = aOperation.operationListener || @@ -830,6 +839,10 @@ calGoogleCalendar.prototype = { this.mSession.fullName = xml.author.name.toString(); } + + var wantInvitations = ((aOperation.itemFilter & + Components.interfaces.calICalendar.ITEM_FILTER_REQUEST_NEEDS_ACTION) != 0); + // Parse all tags for each (var entry in xml.entry) { if (entry.gd::originalEvent.toString().length) { @@ -838,11 +851,28 @@ calGoogleCalendar.prototype = { // later. continue; } - LOG("Parsing entry:\n" + entry + "\n"); + var item = XMLEntryToItem(entry, timezone, this.superCalendar); item.calendar = this.superCalendar; + // If the item is not an invitation and invitations are wanted + // or vice versa, then continue. + if (wantInvitations != this.isInvitation(item)) { + continue; + } + + if (wantInvitations) { + // If the user is not an attendee, or has already accepted + // then this is also not an invitation. + var att = item.getAttendeeById("MAILTO:" + this.session.userName); + if (!att || att.participationStatus != "NEEDS-ACTION") { + continue; + } + } + + LOG("Parsing entry:\n" + entry + "\n"); + if (item.recurrenceInfo) { // If we are doing an uncached operation, then we need to // gather all exceptions and put them into the item. @@ -955,7 +985,7 @@ calGoogleCalendar.prototype = { // All operations need to call onOperationComplete // calIGoogleRequest's type corresponds to calIOperationListener's // constants, so we can use them here. - this.notifyOperationComplete(aOperation.operationListener + this.notifyOperationComplete(aOperation.operationListener, Components.results.NS_OK, aOperation.type, (item ? item.id : null), @@ -971,7 +1001,7 @@ calGoogleCalendar.prototype = { } // Operation failed - this.notifyOperationComplete(aOperation.operationListener + this.notifyOperationComplete(aOperation.operationListener, e.result, aOperation.type, null, @@ -1052,7 +1082,7 @@ calGoogleCalendar.prototype = { * an XML representation of the added item. * @param aIsFullSync If set, this is a full sync rather than an update. */ - syncItems_response: function cGC_getItems_response_onResult(aOperation, aData, isFullSync) { + syncItems_response: function cGC_syncItems_response(aOperation, aData, isFullSync) { LOG("Recieved response for " + aOperation.uri + (isFullSync ? " (full sync)" : "")); try { // Check if the call succeeded @@ -1184,5 +1214,24 @@ calGoogleCalendar.prototype = { LOG("Error syncing items:\n" + e); aOperation.operationListener.onResult({ status: e.result }, e.message); } + }, + + /** + * Implement calISchedulingSupport + */ + isInvitation: function cGC_isInvitation(aItem) { + if (!aItem.organizer) { + // If there is no organizer, we have no way to tell. + return false; + } + // The item is an invitation if the organizer is not the current + // session's user. + return (aItem.organizer.id.toLowerCase() != + "mailto:" + this.session.userName.toLowerCase()); + }, + + getInvitedAttendee: function cGC_getInvitedAttendee(aItem) { + // The invited attendee must always be the session user. + return aItem.getAttendeeById("MAILTO:" + this.session.userName); } }; diff --git a/mozilla/calendar/providers/gdata/components/calGoogleCalendarModule.js b/mozilla/calendar/providers/gdata/components/calGoogleCalendarModule.js index 1a44b901c3a..8adae61f0c8 100644 --- a/mozilla/calendar/providers/gdata/components/calGoogleCalendarModule.js +++ b/mozilla/calendar/providers/gdata/components/calGoogleCalendarModule.js @@ -44,6 +44,7 @@ var g_classInfo = { var ifaces = [ Components.interfaces.nsISupports, Components.interfaces.calICalendar, + Components.interfaces.calISchedulingSupport, Components.interfaces.calIChangeLog, Components.interfaces.nsIClassInfo ]; diff --git a/mozilla/calendar/providers/gdata/components/calGoogleUtils.js b/mozilla/calendar/providers/gdata/components/calGoogleUtils.js index 2c0c5032886..b16269abd1e 100644 --- a/mozilla/calendar/providers/gdata/components/calGoogleUtils.js +++ b/mozilla/calendar/providers/gdata/components/calGoogleUtils.js @@ -474,12 +474,12 @@ function ItemToXMLEntry(aItem, aAuthorEmail, aAuthorName) { } if (attendeeStatusMap[attendee.role]) { - xmlAttendee.gd::attendeeType.@value = + xmlAttendee.gd::attendeeType.@value = kEVENT_SCHEMA + attendeeStatusMap[attendee.role]; } if (attendeeStatusMap[attendee.participationStatus]) { - xmlAttendee.gd::attendeeStatus.@value = + xmlAttendee.gd::attendeeStatus.@value = kEVENT_SCHEMA + attendeeStatusMap[attendee.participationStatus]; } @@ -1063,6 +1063,9 @@ function XMLEntryToItem(aXMLEntry, aTimezone, aCalendar, aReferenceItem) { "event.tentative": "TENTATIVE" }; + // Clear all attendees in case a reference item was passed + item.removeAllAttendees(); + // Iterate all attendee tags. for each (var who in aXMLEntry.gd::who) { var attendee = createAttendee(); @@ -1104,6 +1107,8 @@ function XMLEntryToItem(aXMLEntry, aTimezone, aCalendar, aReferenceItem) { .@value.toString(); if (gdCategories) { item.setProperty("CATEGORIES", gdCategories); + } else { + item.removeProperty("CATEGORIES"); } // published diff --git a/mozilla/calendar/providers/memory/calMemoryCalendar.js b/mozilla/calendar/providers/memory/calMemoryCalendar.js index 9ce40c29fae..c7214224fcc 100644 --- a/mozilla/calendar/providers/memory/calMemoryCalendar.js +++ b/mozilla/calendar/providers/memory/calMemoryCalendar.js @@ -336,6 +336,8 @@ calMemoryCalendar.prototype = { // filters // + var wantInvitations = ((aItemFilter & calICalendar.ITEM_FILTER_REQUEST_NEEDS_ACTION) != 0); + // item base type var wantEvents = ((aItemFilter & calICalendar.ITEM_FILTER_TYPE_EVENT) != 0); var wantTodos = ((aItemFilter & calICalendar.ITEM_FILTER_TYPE_TODO) != 0); @@ -390,12 +392,18 @@ calMemoryCalendar.prototype = { if (itemReturnOccurrences && item.recurrenceInfo) { var occurrences = item.recurrenceInfo.getOccurrences( aRangeStart, aRangeEnd, aCount ? aCount - itemsFound.length : 0, {}); + if (wantInvitations) { + occurrences = occurrences.filter(this.isInvitation, this); + } if (!isEvent_) { occurrences = occurrences.filter(checkCompleted); } itemsFound = itemsFound.concat(occurrences); - } else if ((isEvent_ || checkCompleted(item)) && + } else if ((!wantInvitations || this.itip_checkInvitation(item)) && + (isEvent_ || checkCompleted(item)) && 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) { diff --git a/mozilla/calendar/providers/storage/calStorageCalendar.js b/mozilla/calendar/providers/storage/calStorageCalendar.js index 28516f78153..3c6ed933475 100644 --- a/mozilla/calendar/providers/storage/calStorageCalendar.js +++ b/mozilla/calendar/providers/storage/calStorageCalendar.js @@ -626,6 +626,7 @@ calStorageCalendar.prototype = { if (aRangeEnd) endTime = aRangeEnd.nativeTime; + var wantInvitations = ((aItemFilter & kCalICalendar.ITEM_FILTER_REQUEST_NEEDS_ACTION) != 0); var wantEvents = ((aItemFilter & kCalICalendar.ITEM_FILTER_TYPE_EVENT) != 0); var wantTodos = ((aItemFilter & kCalICalendar.ITEM_FILTER_TYPE_TODO) != 0); var asOccurrences = ((aItemFilter & kCalICalendar.ITEM_FILTER_CLASS_OCCURRENCES) != 0); @@ -685,20 +686,18 @@ calStorageCalendar.prototype = { // expanding occurrences, and queue the items for the listener function handleResultItem(item, theIID, optionalFilterFunc) { var expandedItems = []; - if (item.recurrenceInfo) { - if (asOccurrences) { - // If the item is recurring, get all ocurrences that fall in - // the range. If the item doesn't fall into the range at all, - // this expands to 0 items. - expandedItems = item.recurrenceInfo - .getOccurrences(aRangeStart, aRangeEnd, 0, {}); - } else if (checkIfInRange(item, aRangeStart, aRangeEnd)) { - // If no occurrences are wanted, check only the parent item. - // This will be changed with bug 416975. - expandedItems = [ item ]; + if (item.recurrenceInfo && asOccurrences) { + // If the item is recurring, get all ocurrences that fall in + // the range. If the item doesn't fall into the range at all, + // this expands to 0 items. + expandedItems = item.recurrenceInfo.getOccurrences(aRangeStart, aRangeEnd, 0, {}); + if (wantInvitations) { + expandedItems = expandedItems.filter(self.isInvitation, self); } - } else { - // non-recurring item + } else if ((!wantInvitations || self.itip_checkInvitation(item)) && + checkIfInRange(item, aRangeStart, aRangeEnd)) { + // If no occurrences are wanted, check only the parent item. + // This will be changed with bug 416975. expandedItems = [ item ]; } diff --git a/mozilla/calendar/providers/wcap/calWcapCalendar.js b/mozilla/calendar/providers/wcap/calWcapCalendar.js index 8fca0f0b1c8..2abf59d996b 100644 --- a/mozilla/calendar/providers/wcap/calWcapCalendar.js +++ b/mozilla/calendar/providers/wcap/calWcapCalendar.js @@ -59,7 +59,7 @@ calWcapCalendar.prototype = { return str; }, - notifyError_: function calWcapCalendar_notifyError_(err, msg, context, suppressOnError) { + notifyError_: function calWcapCalendar_notifyError_(err, msg, context) { var rc = getResultCode(err); switch (rc) { case calIWcapErrors.WCAP_COMPONENT_NOT_FOUND: @@ -78,16 +78,14 @@ calWcapCalendar.prototype = { log("error: " + msg, context); break; } - if (!suppressOnError) { - this.__proto__.__proto__.notifyError.apply( - this, - err instanceof Components.interfaces.nsIException - ? [err.result, err.message] - : [(isNaN(err) ? Components.results.NS_ERROR_FAILURE : err), msg]); - } + this.__proto__.__proto__.notifyError.apply( + this, + err instanceof Components.interfaces.nsIException + ? [err.result, err.message] + : [(isNaN(err) ? Components.results.NS_ERROR_FAILURE : err), msg]); }, - notifyError: function calWcapCalendar_notifyError(err, msg, suppressOnError) { - this.notifyError_(err, msg, this, suppressOnError); + notifyError: function calWcapCalendar_notifyError(err, msg) { + this.notifyError_(err, msg, this); }, // calICalendarProvider: @@ -144,16 +142,22 @@ calWcapCalendar.prototype = { getProperty: function calWcapCalendar_getProperty(aName) { var value = this.__proto__.__proto__.getProperty.apply(this, arguments); switch (aName) { + case "organizerId": + value = this.ownerId; + break; + case "organizerCN": + value = this.getCalendarProperties("X-S1CS-CALPROPS-COMMON-NAME"); + break; case "cache.supported": value = false; // until bug 412914 and bug 412606 are fixed break; - case "private.wcapCalendar": - value = this; - break; case "readOnly": if (value === null) { - // tweak readOnly default to true for non-owned calendars: - value = (this.m_session && this.session.isLoggedIn && !this.isOwnedCalendar); + // tweak readOnly default to true for non-owned calendars, + // all secondary calendars to readOnly unless we're logged in + value = (this.m_session && this.session.isLoggedIn + ? !this.isOwnedCalendar + : !this.isDefaultCalendar); } break; case "calendar-main-in-composite": diff --git a/mozilla/calendar/providers/wcap/calWcapCalendarItems.js b/mozilla/calendar/providers/wcap/calWcapCalendarItems.js index 7c7864c00df..6ccb1004a2f 100644 --- a/mozilla/calendar/providers/wcap/calWcapCalendarItems.js +++ b/mozilla/calendar/providers/wcap/calWcapCalendarItems.js @@ -1139,12 +1139,12 @@ function getItemFilterParams(itemFilter) { // compstate += ";REPLY-ACCEPTED"; // if (itemFilter & calIWcapCalendar.ITEM_FILTER_REQUEST_COMPLETED) // compstate += ";REQUEST-COMPLETED"; - if (itemFilter & calIWcapCalendar.ITEM_FILTER_REQUEST_NEEDS_ACTION) { + if (itemFilter & calICalendar.ITEM_FILTER_REQUEST_NEEDS_ACTION) { compstate += ";REQUEST-NEEDS-ACTION"; } - if (itemFilter & calIWcapCalendar.ITEM_FILTER_REQUEST_NEEDSNOACTION) { - compstate += ";REQUEST-NEEDSNOACTION"; - } +// if (itemFilter & calIWcapCalendar.ITEM_FILTER_REQUEST_NEEDSNOACTION) { +// compstate += ";REQUEST-NEEDSNOACTION"; +// } // if (itemFilter & calIWcapCalendar.ITEM_FILTER_REQUEST_PENDING) // compstate += ";REQUEST-PENDING"; // if (itemFilter & calIWcapCalendar.ITEM_FILTER_REQUEST_WAITFORREPLY) @@ -1177,10 +1177,6 @@ function calWcapCalendar_getItems(itemFilter, maxResults, rangeStart, rangeEnd, ",\n\trangeStart=" + zRangeStart + ",\n\trangeEnd=" + zRangeEnd, this)); - if (itemFilter & calIWcapCalendar.ITEM_FILTER_SUPPRESS_ONERROR) { - request.suppressOnError = true; - } - if (this.aboutToBeUnregistered) { // limiting the amount of network traffic while unregistering log("being unregistered, no results.", this); @@ -1337,96 +1333,28 @@ function calWcapCalendar_resetLog() { calWcapCalendar.prototype.replayChangesOn = function calWcapCalendar_replayChangesOn(destCal, listener) { var this_ = this; - var opListener = { - QueryInterface: function(iid) { - return doQueryInterface(this, opListener, iid, - [Components.interfaces.calIGenericOperationListener, - nsISupports]); - }, - onResult: function(op, result) { - if (!op.isPending) { - if (Components.isSuccessCode(op.status)) { - this_.setProperty("replay.last_stamp", getIcalUTC(result)); - log("new replay stamp: " + getIcalUTC(result), this_); - } else { - logError("error replaying changes: " + errorToString(op.status)); - } - if (listener) { - listener.onResult(op, null); - } - } - } - }; - return this.syncChangesTo_(destCal, calICalendar.ITEM_FILTER_ALL_ITEMS, - getDatetimeFromIcalString(this.getProperty("replay.last_stamp")), - opListener); -}; - -calWcapCalendar.prototype.syncChangesTo = -function calWcapCalendar_syncChangesTo(destCal, itemFilter, dtFrom, listener) { - // xxx todo: move to Thomas - // do NOT puke up error box every three minutes! - itemFilter |= calIWcapCalendar.ITEM_FILTER_SUPPRESS_ONERROR; - return this.syncChangesTo_(destCal, itemFilter, dtFrom, listener); -}; - -calWcapCalendar.prototype.syncChangesTo_ = -function calWcapCalendar_syncChangesTo_(destCal, itemFilter, dtFrom, listener) { - dtFrom = ensureDateTime(dtFrom); + var itemFilter = calICalendar.ITEM_FILTER_ALL_ITEMS; + var dtFrom = getDatetimeFromIcalString(this.getProperty("replay.last_stamp")); var now = getTime(); // new stamp for this sync - var this_ = this; var request_ = new calWcapRequest( - function syncChangesTo_resp(request, err) { + function replayChangesOn_resp(request, err) { if (err) { - log("SYNC failed!", this_); - if (listener) { - var opListener = null; - try { - opListener = listener.QueryInterface(Components.interfaces.calIGenericOperationListener); - } catch (exc) { - listener.onOperationComplete(this_.superCalendar, getResultCode(err), - calIWcapCalendar.SYNC, null, err); - } - if (opListener) { - opListener.onResult(request, null); - } - } - this_.notifyError(err, null, request.suppressOnError); + logError("error replaying changes: " + errorToString(err)); + this_.notifyError(err); } else { - log("SYNC succeeded.", this_); - if (listener) { - var opListener = null; - try { - opListener = listener.QueryInterface(Components.interfaces.calIGenericOperationListener); - } catch (exc) { - listener.onOperationComplete(this_.superCalendar, NS_OK, - calIWcapCalendar.SYNC, null, now); - } - if (opListener) { - opListener.onResult(request, now); - } - } - this_.setProperty("currentStatus", Components.results.NS_OK); + log("replay succeeded.", this_); + this_.setProperty("replay.last_stamp", getIcalUTC(now)); + log("new replay stamp: " + getIcalUTC(now), this_); + } + if (opListener) { + opListener.onResult(request, null); } }, - log("syncChangesTo():\n\titemFilter=0x" + itemFilter.toString(0x10) + + log("replayChangesOn():\n\titemFilter=0x" + itemFilter.toString(0x10) + "\n\tdtFrom=" + getIcalUTC(dtFrom), this)); - if (itemFilter & calIWcapCalendar.ITEM_FILTER_SUPPRESS_ONERROR) { - request_.suppressOnError = true; - } - try { - var calObserver = null; - if (listener) { - try { - calObserver = listener.QueryInterface(Components.interfaces.calIObserver); - } - catch (exc) { - } - } - var writeListener = { onGetResult: function() {}, onOperationComplete: function(cal, status, opType, id, detail) { @@ -1443,46 +1371,37 @@ function calWcapCalendar_syncChangesTo_(destCal, itemFilter, dtFrom, listener) { var bAdd = (!dtCreated || !dtFrom || dtCreated.compare(dtFrom) >= 0); modifiedIds[item.id] = true; if (bAdd) { - log("syncChangesTo(): new item " + item.id, this_); + log("replayChangesOn(): new item " + item.id, this_); if (destCal) { destCal.addItem(item, writeListener); } - if (calObserver) - calObserver.onAddItem(item); } else { - log("syncChangesTo(): modified item " + item.id, this_); + log("replayChangesOn(): modified item " + item.id, this_); if (destCal) { destCal.modifyItem(item, null, writeListener); } - if (calObserver) - calObserver.onModifyItem(item, null); } } for each (var item in request.m_deletedItems) { // don't delete anything that has been touched by lastmods: if (modifiedIds[item.id]) { - log("syncChangesTo(): skipping deletion of " + item.id, this_); + log("replayChangesOn(): skipping deletion of " + item.id, this_); } else if (isParent(item)) { - log("syncChangesTo(): deleted item " + item.id, this_); + log("replayChangesOn(): deleted item " + item.id, this_); if (destCal) { destCal.deleteItem(item, writeListener); } - if (calObserver) - calObserver.onDeleteItem(item); } else { // modify parent instead of // straight-forward deleteItem(). WTF. var parent = item.parentItem.clone(); parent.recurrenceInfo.removeOccurrenceAt(item.recurrenceId); - log("syncChangesTo(): modified parent "+ parent.id, this_); + log("replayChangesOn(): modified parent "+ parent.id, this_); if (destCal) { destCal.modifyItem(parent, item, writeListener); } - if (calObserver) { - calObserver.onModifyItem(parent, item); - } } } - }, "syncChangesTo() netFinishedRespFunc"); + }, "replayChangesOn() netFinishedRespFunc"); request_.attachSubRequest(request); // assure being logged in to calc server times: @@ -1501,7 +1420,7 @@ function calWcapCalendar_syncChangesTo_(destCal, itemFilter, dtFrom, listener) { params += ("&dtstart=" + getIcalUTC(dtFrom)); params += ("&dtend=" + getIcalUTC(this_.session.getServerTime(now))); - log("syncChangesTo(): getting last modifications...", this_); + log("replayChangesOn(): getting last modifications...", this_); this_.issueNetworkRequest( request, function modifiedNetResp(err, icalRootComp) { @@ -1516,7 +1435,7 @@ function calWcapCalendar_syncChangesTo_(destCal, itemFilter, dtFrom, listener) { params + getItemFilterParams(itemFilter), calIWcapCalendar.AC_COMP_READ); - log("syncChangesTo(): getting deleted items...", this_); + log("replayChangesOn(): getting deleted items...", this_); this_.issueNetworkRequest( request, function modifiedNetResp(err, icalRootComp) { diff --git a/mozilla/calendar/providers/wcap/calWcapCalendarModule.js b/mozilla/calendar/providers/wcap/calWcapCalendarModule.js index c7942f951cb..9cf56641950 100644 --- a/mozilla/calendar/providers/wcap/calWcapCalendarModule.js +++ b/mozilla/calendar/providers/wcap/calWcapCalendarModule.js @@ -127,6 +127,7 @@ var g_classInfo = { getInterfaces: function ci_wcapCalendar_getInterfaces(count) { const ifaces = [calIWcapCalendar, calICalendar, + Components.interfaces.calISchedulingSupport, Components.interfaces.calIChangeLog, Components.interfaces.calICalendarProvider, Components.interfaces.nsIClassInfo, diff --git a/mozilla/calendar/providers/wcap/calWcapSession.js b/mozilla/calendar/providers/wcap/calWcapSession.js index dfe4f622925..89f5ec0fe3a 100644 --- a/mozilla/calendar/providers/wcap/calWcapSession.js +++ b/mozilla/calendar/providers/wcap/calWcapSession.js @@ -75,6 +75,9 @@ function getWcapSessionFor(cal, uri) { break; } } + if (!defaultCal) { + logError("no default calendar!", session); + } session.defaultCalendar = defaultCal; } return session; @@ -112,9 +115,9 @@ calWcapSession.prototype = { } return str; }, - notifyError: function calWcapSession_notifyError(err, suppressOnError) { + notifyError: function calWcapSession_notifyError(err) { if (this.defaultCalendar) { - this.defaultCalendar.notifyError_(err, null, this, suppressOnError); + this.defaultCalendar.notifyError_(err, null, this); } else { logError("no default calendar!", this); logError(err, this); @@ -792,7 +795,7 @@ calWcapSession.prototype = { belongsTo: function calWcapSession_belongsTo(cal) { try { // xxx todo hack to get the unwrapped wcap calendar instance: - cal = cal.getProperty("private.wcapCalendar").QueryInterface(calIWcapCalendar).wrappedJSObject; + cal = cal.getProperty("cache.uncachedCalendar").QueryInterface(calIWcapCalendar).wrappedJSObject; if (cal && (cal.session.m_contextId == this.m_contextId)) { return cal; } diff --git a/mozilla/calendar/providers/wcap/public/calIWcapCalendar.idl b/mozilla/calendar/providers/wcap/public/calIWcapCalendar.idl index a9a0263bbc9..d6973879294 100644 --- a/mozilla/calendar/providers/wcap/public/calIWcapCalendar.idl +++ b/mozilla/calendar/providers/wcap/public/calIWcapCalendar.idl @@ -94,23 +94,6 @@ interface calIWcapCalendar : calICalendar */ readonly attribute string defaultTimezone; - /** - * Tests whether the passed item corresponds to an invitation. - * - * @param item item to be tested - * @return whether the passed item corresponds to an invitation - */ - boolean isInvitation(in calIItemBase item); - - /** - * Gets the invited attendee if the passed item corresponds to - * an invitation. - * - * @param item invitation item - * @return attendee object else null - */ - calIAttendee getInvitedAttendee(in calIItemBase item); - /** * Gets calendar properties. * @@ -140,12 +123,12 @@ interface calIWcapCalendar : calICalendar /* xxx todo: limit to currently needed ones: NEEDS-ACTION */ - /** - * Scope: getItems only - * Whether getItems should only return items that have alarms set for the - * specified range. - */ - const unsigned long ITEM_FILTER_BY_ALARM_RANGE = 1 << 23; +// /** +// * Scope: getItems only +// * Whether getItems should only return items that have alarms set for the +// * specified range. +// */ +// const unsigned long ITEM_FILTER_BY_ALARM_RANGE = 1 << 23; // /** // * Scope: Attendee @@ -168,19 +151,19 @@ interface calIWcapCalendar : calICalendar // */ // const unsigned long ITEM_FILTER_REQUEST_COMPLETED = 1 << 26; - /** - * Scope: Attendee - * The event or todo is an invitation from another - * user and the current user has not replied to it yet. - */ - const unsigned long ITEM_FILTER_REQUEST_NEEDS_ACTION = 1 << 27; +// /** +// * Scope: Attendee +// * The event or todo is an invitation from another +// * user and the current user has not replied to it yet. +// */ +// const unsigned long ITEM_FILTER_REQUEST_NEEDS_ACTION = 1 << 27; - /** - * Scope: Attendee - * The event or todo is an invitation from another - * user and the current user is not required to reply. - */ - const unsigned long ITEM_FILTER_REQUEST_NEEDSNOACTION = 1 << 28; +// /** +// * Scope: Attendee +// * The event or todo is an invitation from another +// * user and the current user is not required to reply. +// */ +// const unsigned long ITEM_FILTER_REQUEST_NEEDSNOACTION = 1 << 28; // /** // * Scope: Organizer @@ -197,32 +180,6 @@ interface calIWcapCalendar : calICalendar // */ // const unsigned long ITEM_FILTER_REQUEST_WAITFORREPLY = 1 << 30; - const unsigned long ITEM_FILTER_SUPPRESS_ONERROR = 1 << 31; - - /* xxx todo sync feature: separate into own interface? */ - /** xxx todo: to be moved to calIOperationListener? - */ - const unsigned long SYNC = 5; - - /** - * Syncs in changes since time dtFrom. - * The passed listener receives a - * SYNC with timestamp as detail. - * - * @param destCal destination calendar to write changes to (may be null) - * @param itemFilter ITEM_FILTER flags OR-ed together, - * ITEM_FILTER_CLASS_OCCURRENCES not allowed - * @param dtFrom start time to sync changes from, - * if null all items are synced in - * @param listener operation listener for SYNC operation - * (may optionally implemented calIObserver to receive - * onAddItem(), onModifyItem() or onDeleteItem() calls) - */ - calIOperation syncChangesTo(in calISyncCalendar destCal, - in unsigned long itemFilter, - in calIDateTime dtFrom, - in calIOperationListener listener); - /* xxx todo: separate out into another interface and leave only an attribute