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:
parent
c180a5c9d0
commit
ae5d2f9c8a
@ -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";
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -87,6 +87,7 @@ XPIDLSRCS = calIAlarm.idl \
|
||||
calITodo.idl \
|
||||
calITransactionManager.idl \
|
||||
calIWeekTitleService.idl \
|
||||
calISchedulingSupport.idl \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = calBaseCID.h
|
||||
|
||||
@ -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 );
|
||||
|
||||
|
||||
@ -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"], [], []);
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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: " +
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@ -44,6 +44,7 @@ var g_classInfo = {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calICalendar,
|
||||
Components.interfaces.calISchedulingSupport,
|
||||
Components.interfaces.calIChangeLog,
|
||||
Components.interfaces.nsIClassInfo
|
||||
];
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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 ];
|
||||
}
|
||||
|
||||
|
||||
@ -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":
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user