Fix bug 370150 - API enhancement: additions for group scheduling. r=philipp,p=dbo

git-svn-id: svn://10.0.0.236/trunk@252659 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
mozilla%kewis.ch 2008-06-27 23:32:30 +00:00
parent c180a5c9d0
commit ae5d2f9c8a
23 changed files with 391 additions and 626 deletions

View File

@ -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";

View File

@ -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);
}
}

View File

@ -87,6 +87,7 @@ XPIDLSRCS = calIAlarm.idl \
calITodo.idl \
calITransactionManager.idl \
calIWeekTitleService.idl \
calISchedulingSupport.idl \
$(NULL)
EXPORTS = calBaseCID.h

View File

@ -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 );

View File

@ -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"], [], []);

View File

@ -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() {

View File

@ -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: " +

View File

@ -19,6 +19,7 @@
*
* Contributor(s):
* Thomas Benisch <thomas.benisch@sun.com>
* Daniel Boelzle <daniel.boelzle@sun.com>
*
* 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");
}

View File

@ -211,17 +211,11 @@
<method name="getCalendarItemParticipationStatus">
<parameter name="aItem"/>
<body><![CDATA[
try {
// temporary hack unless all group scheduling features are supported
// by the caching facade (calCachedCalendar):
var wcapCalendar = aItem.calendar.getProperty("private.wcapCalendar")
.QueryInterface(Components.interfaces.calIWcapCalendar);
var att = wcapCalendar.getInvitedAttendee(aItem);
if (att) {
return att.participationStatus;
}
} catch (e) {}
return null;
var att;
if (aItem.calendar instanceof Components.interfaces.calISchedulingSupport) {
att = aItem.calendar.getInvitedAttendee(aItem);
}
return (att ? att.participationStatus : null);
]]></body>
</method>
@ -229,20 +223,18 @@
<parameter name="aItem"/>
<parameter name="aStatus"/>
<body><![CDATA[
try {
// temporary hack unless all group scheduling features are supported
// by the caching facade (calCachedCalendar):
var wcapCalendar = aItem.calendar.getProperty("private.wcapCalendar")
.QueryInterface(Components.interfaces.calIWcapCalendar);
var att = wcapCalendar.getInvitedAttendee(aItem);
if (aItem.calendar instanceof Components.interfaces.calISchedulingSupport) {
var att = aItem.calendar.getInvitedAttendee(aItem);
if (att) {
var att_ = att.clone();
att_.participationStatus = aStatus;
// Update attendee
aItem.removeAttendee(att);
aItem.addAttendee(att_);
return true;
}
} catch (e) {}
}
return false;
]]></body>
</method>

View File

@ -20,6 +20,7 @@
* Contributor(s):
* Thomas Benisch <thomas.benisch@sun.com>
* Philipp Kewisch <mozilla@kewis.ch>
* Daniel Boelzle <daniel.boelzle@sun.com>
*
* 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);
}
};

View File

@ -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) {

View File

@ -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);
}

View File

@ -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);
}
};

View File

@ -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 <entry> 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);
}
};

View File

@ -44,6 +44,7 @@ var g_classInfo = {
var ifaces = [
Components.interfaces.nsISupports,
Components.interfaces.calICalendar,
Components.interfaces.calISchedulingSupport,
Components.interfaces.calIChangeLog,
Components.interfaces.nsIClassInfo
];

View File

@ -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

View File

@ -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) {

View File

@ -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 ];
}

View File

@ -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":

View File

@ -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) {

View File

@ -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,

View File

@ -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;
}

View File

@ -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 <code>dtFrom</code>.
* The passed <code>listener</code> receives a
* <code>SYNC</code> 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