зеркало из https://github.com/mozilla/gecko-dev.git
Bug 340949: alarms, again
This commit is contained in:
Родитель
77f151f65f
Коммит
0bff7fc140
|
@ -191,17 +191,94 @@ calWcapCalendar.prototype.getRecurrenceParams = function(
|
|||
}
|
||||
};
|
||||
|
||||
const XPROP_OP_ADD = 0;
|
||||
const XPROP_OP_REPLACE = 1;
|
||||
const XPROP_OP_DELETE = 2;
|
||||
|
||||
function makeXPropertyUrl( name, op, value )
|
||||
{
|
||||
var url = ("&" + name);
|
||||
switch (op) {
|
||||
case XPROP_OP_ADD:
|
||||
url += "=X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-ADD";
|
||||
break;
|
||||
case XPROP_OP_REPLACE:
|
||||
url += "=X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-REPLACE";
|
||||
break;
|
||||
case XPROP_OP_DELETE:
|
||||
url += "=X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-DELETE";
|
||||
break;
|
||||
}
|
||||
url += "^";
|
||||
if (value)
|
||||
url += value;
|
||||
return url;
|
||||
}
|
||||
|
||||
calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
|
||||
{
|
||||
var bIsEvent = isEvent(item);
|
||||
var url = this.session.getCommandUrl( bIsEvent ? "storeevents"
|
||||
: "storetodos" );
|
||||
url += "&fetch=1&relativealarm=1&compressed=1&recurring=1";
|
||||
url += ("&calid=" + encodeURIComponent(this.calId));
|
||||
|
||||
var ownerId = this.ownerId;
|
||||
var orgUID = ((item.organizer == null || item.organizer.id == null)
|
||||
? ownerId : item.organizer.id);
|
||||
|
||||
// attendees:
|
||||
var attendees = item.getAttendees({});
|
||||
if (attendees.length > 0) {
|
||||
// ORGANIZER is owner fo this cal?
|
||||
if (!oldItem || orgUID == ownerId) {
|
||||
url += "&method=2"; // REQUEST
|
||||
url += "&attendees=";
|
||||
for ( var i = 0; i < attendees.length; ++i ) {
|
||||
if (i > 0)
|
||||
url += ";";
|
||||
url += this.encodeAttendee( attendees[i], true /*forceRSVP*/ );
|
||||
}
|
||||
}
|
||||
else { // in modifyItem(), attendee's calendar:
|
||||
var attendee = item.getAttendeeById(ownerId);
|
||||
if (attendee == null) {
|
||||
this.logError( "not in attendee list, but in my cal?" );
|
||||
}
|
||||
else {
|
||||
this.log( "attendee: " + attendee.icalProperty.icalString );
|
||||
var oldAttendee = oldItem.getAttendeeById(ownerId);
|
||||
if (!oldAttendee ||
|
||||
attendee.participationStatus !=
|
||||
oldAttendee.participationStatus)
|
||||
{
|
||||
// REPLY for just this calendar owner:
|
||||
var replyUrl = (url + "&method=4&attendees=PARTSTAT=" +
|
||||
attendee.participationStatus);
|
||||
replyUrl += ("^" + ownerId);
|
||||
replyUrl += ("&uid=" + item.id);
|
||||
var rid = item.recurrenceId;
|
||||
if (rid) {
|
||||
replyUrl += "&mod=1"; // THIS INSTANCE
|
||||
// if not set, whole series of events is modified:
|
||||
replyUrl = getIcalUTC(rid);
|
||||
replyUrl += ("&rid=" + rid);
|
||||
}
|
||||
else {
|
||||
replyUrl += "&storetype=2";
|
||||
replyUrl += "&mod=4"; // THIS AND ALL INSTANCES
|
||||
}
|
||||
this.session.issueSyncRequest(
|
||||
replyUrl + "&fmt-out=text%2Fcalendar", stringToIcal );
|
||||
}
|
||||
}
|
||||
// continue with UPDATE of attendee's copy of item:
|
||||
url += "&method=256";
|
||||
}
|
||||
}
|
||||
else
|
||||
url += "&attendees="; // using just PUBLISH (method=1)
|
||||
|
||||
url += "&fetch=1&relativealarm=1&compressed=1&recurring=1";
|
||||
url += ("&orgUID=" + encodeURIComponent(orgUID));
|
||||
|
||||
// xxx todo: default prio is 0 (5 in sjs cs)
|
||||
|
@ -256,7 +333,6 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
|
|||
item.getProperty( "CATEGORIES" ).replace(/,/g, ";") );
|
||||
}
|
||||
|
||||
// xxx todo: contacts, resources missing in calAPI
|
||||
// xxx todo: missing relatedTos= in cal api
|
||||
|
||||
url += ("&summary=" + encodeURIComponent(item.title));
|
||||
|
@ -276,7 +352,7 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
|
|||
}
|
||||
|
||||
var dtstart = null;
|
||||
var dtend = null; // for alarmRelated
|
||||
var dtend = null;
|
||||
|
||||
if (bIsEvent) {
|
||||
dtstart = item.startDate;
|
||||
|
@ -297,7 +373,6 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
|
|||
// url += ("&X-NSCP-DUE-TZID=" + encodeURIComponent(
|
||||
// this.getAlignedTimezone(dtend.timezone)));
|
||||
}
|
||||
// xxx todo: missing duration
|
||||
if (dtstart && dtstart.isDate)
|
||||
url += "&isAllDay=1";
|
||||
if (item.isCompleted)
|
||||
|
@ -319,8 +394,8 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
|
|||
// important to provide tz info with entry date for proper
|
||||
// occurrence calculation (daylight savings)
|
||||
url += ("&dtstart=" + getIcalUTC(dtstart));
|
||||
// xxx todo: setting X-NSCP- does not work.
|
||||
// i.e. no separate tz for start/end. WTF.
|
||||
// xxx todo: setting X-NSCP-tz does not work.
|
||||
// i.e. for now no separate tz for start/end.
|
||||
// url += ("&X-NSCP-DTSTART-TZID=" +
|
||||
// encodeURIComponent(this.getAlignedTimezone(dtstart.timezone)));
|
||||
// currently the only way to influence X-NSCP-DTSTART-TZID:
|
||||
|
@ -329,27 +404,20 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
|
|||
}
|
||||
|
||||
// alarm support:
|
||||
var alarmOffset = item.alarmOffset;
|
||||
if (alarmOffset) {
|
||||
var alarmStart = item.alarmOffset;
|
||||
if (alarmStart) {
|
||||
var alarmRelated = item.alarmRelated;
|
||||
if (alarmRelated==Components.interfaces.calIItemBase.ALARM_RELATED_END){
|
||||
// cs does not support RELATED=END:
|
||||
// cs does not support explicit RELATED=END when
|
||||
// both dtstart/due are written
|
||||
var dur = item.duration;
|
||||
if (dur) {
|
||||
alarmOffset = alarmOffset.clone();
|
||||
alarmOffset.addDuration(dur);
|
||||
}
|
||||
else {
|
||||
this.notifyError("alarm relates to END, but no duration!");
|
||||
alarmRelated =
|
||||
Components.interfaces.calIItemBase.ALARM_RELATED_START;
|
||||
}
|
||||
if (dur) { // dtstart+due given
|
||||
alarmStart = alarmStart.clone();
|
||||
alarmStart.addDuration(dur);
|
||||
} // else only dtend is set
|
||||
}
|
||||
alarmOffset = alarmOffset.icalString;
|
||||
url += ("&alarmStart=" + alarmOffset);
|
||||
url += ("&X-MOZ-WCAP-ALARM-RELATED=" +
|
||||
"X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-REPLACE^" +
|
||||
alarmRelated);
|
||||
alarmStart = alarmStart.icalString;
|
||||
url += ("&alarmStart=" + alarmStart);
|
||||
// xxx todo: verify ;-separated addresses
|
||||
url += "&alarmEmails=";
|
||||
if (item.hasProperty("alarmEmailAddress")) {
|
||||
|
@ -358,76 +426,41 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
|
|||
}
|
||||
else {
|
||||
// xxx todo: popup exor emails can be currently specified...
|
||||
url += ("&alarmPopup=" + alarmOffset);
|
||||
url += ("&alarmPopup=" + alarmStart);
|
||||
}
|
||||
// xxx todo: missing: alarm triggers for flashing, etc.
|
||||
}
|
||||
else {
|
||||
// clear alarm:
|
||||
url += "&alarmStart=&alarmPopup=&alarmEmails=";
|
||||
url += ("&X-MOZ-WCAP-ALARM-RELATED=" +
|
||||
"X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-DELETE^");
|
||||
}
|
||||
// xxx todo: currently no support to store this at VALARM component...
|
||||
var alarmLastAck = item.alarmLastAck;
|
||||
if (alarmLastAck) {
|
||||
url += ("&X-MOZ-LASTACK=" +
|
||||
"X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-REPLACE^" +
|
||||
getIcalUTC(alarmLastAck));
|
||||
}
|
||||
else {
|
||||
url += ("&X-MOZ-LASTACK=" +
|
||||
"X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-DELETE^");
|
||||
}
|
||||
|
||||
// attendees:
|
||||
var attendees = item.getAttendees({});
|
||||
if (attendees.length > 0) {
|
||||
// ORGANIZER is owner fo this cal?
|
||||
if (!oldItem || orgUID == ownerId) {
|
||||
url += "&method=2"; // REQUEST
|
||||
url += "&attendees=";
|
||||
for ( var i = 0; i < attendees.length; ++i ) {
|
||||
if (i > 0)
|
||||
url += ";";
|
||||
url += this.encodeAttendee( attendees[i], true /*forceRSVP*/ );
|
||||
}
|
||||
}
|
||||
else { // attendee's calendar:
|
||||
var attendee = item.getAttendeeById(ownerId);
|
||||
if (attendee == null) {
|
||||
this.logError( "not in attendee list, but in my cal?" );
|
||||
}
|
||||
else {
|
||||
this.log( "attendee: " + attendee.icalProperty.icalString );
|
||||
var oldAttendee = oldItem.getAttendeeById(ownerId);
|
||||
if (!oldAttendee ||
|
||||
attendee.participationStatus !=
|
||||
oldAttendee.participationStatus) {
|
||||
// REPLY for just this calendar owner:
|
||||
url += "&method=4";
|
||||
url += ("&attendees=PARTSTAT=" +
|
||||
attendee.participationStatus);
|
||||
url += ("^" + ownerId);
|
||||
}
|
||||
else {
|
||||
// UPDATE attendee's copy of item:
|
||||
url += "&method=256";
|
||||
}
|
||||
}
|
||||
}
|
||||
} // else use just PUBLISH (method=1)
|
||||
|
||||
// xxx todo: however, sometimes socs just returns an empty calendar when
|
||||
// nothing or only optional props like attendee ROLE has changed,
|
||||
// although fetch=1.
|
||||
// This also occurs when the event organizer is in the attendees
|
||||
// list and switches its PARTSTAT too often...
|
||||
// hack: ever changing dummy prop, then the cs engine seems to write
|
||||
// every time. WTF.
|
||||
url += ("&X-MOZ-WCAP-DUMMY=" +
|
||||
"X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-REPLACE^" +
|
||||
getIcalUTC(getTime()));
|
||||
//
|
||||
// hack #1: ever changing X-dummy prop, then the cs engine seems to write
|
||||
// every time. => does not work for recurring items,
|
||||
// operation REPLACE does not work, just adds
|
||||
// more and more props. WTF.
|
||||
|
||||
// misusing CONTACTS for now to store additional X- data
|
||||
// (not used in cs web-frontend nor in mozilla)
|
||||
// xxx todo, contact asavari
|
||||
|
||||
// stamp:[lastack]:[related]
|
||||
var contacts = getIcalUTC(getTime());
|
||||
// xxx todo: currently no support to store this at VALARM component...
|
||||
var lastAck = item.alarmLastAck;
|
||||
contacts += ":";
|
||||
if (lastAck)
|
||||
contacts += getIcalUTC(lastAck);
|
||||
contacts += ":";
|
||||
if (alarmStart)
|
||||
contacts += item.alarmRelated;
|
||||
url += ("&contacts=" + encodeURIComponent(contacts));
|
||||
|
||||
return url;
|
||||
};
|
||||
|
@ -746,39 +779,52 @@ calWcapCalendar.prototype.parseItems = function(
|
|||
}
|
||||
break;
|
||||
}
|
||||
if (item &&
|
||||
item.alarmOffset && !item.entryDate && !item.dueDate) {
|
||||
// xxx todo: loss on roundtrip
|
||||
this_.log( "app currently does not support " +
|
||||
"absolute alarm trigger datetimes. " +
|
||||
"Removing alarm from item: " + item.title );
|
||||
item.alarmOffset = null;
|
||||
item.alarmLastAck = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (item != null) {
|
||||
var alarmOffset = item.alarmOffset;
|
||||
if (alarmOffset) {
|
||||
var alarmRelated = subComp.getFirstProperty(
|
||||
"X-MOZ-WCAP-ALARM-RELATED");
|
||||
if (alarmRelated) {
|
||||
alarmRelated = Number(alarmRelated.value);
|
||||
if (alarmRelated != item.alarmRelated) {
|
||||
alarmOffset = alarmOffset.clone();
|
||||
var dur = item.duration;
|
||||
if (dur) {
|
||||
if (alarmRelated == Components.interfaces
|
||||
.calIItemBase.ALARM_RELATED_END) {
|
||||
var contactsProp = subComp.getFirstProperty("CONTACT");
|
||||
if (contactsProp) { // stamp:[lastack]:[related]
|
||||
var ar = contactsProp.value.split(":");
|
||||
if (ar.length > 2) {
|
||||
var alarmRelated = ar[2];
|
||||
if (alarmRelated.length > 0) {
|
||||
alarmRelated = Number(alarmRelated);
|
||||
if (alarmRelated == Components.interfaces
|
||||
.calIItemBase.ALARM_RELATED_END &&
|
||||
alarmRelated != item.alarmRelated)
|
||||
{
|
||||
var dur = item.duration;
|
||||
if (dur) {
|
||||
dur = dur.clone();
|
||||
dur.isNegative = true;
|
||||
var alarmOffset = item.alarmOffset;
|
||||
if (alarmOffset) {
|
||||
alarmOffset = alarmOffset.clone();
|
||||
alarmOffset.addDuration(dur);
|
||||
item.alarmOffset = alarmOffset;
|
||||
}
|
||||
}
|
||||
alarmOffset.addDuration(dur);
|
||||
item.alarmOffset = alarmOffset;
|
||||
item.alarmRelated = alarmRelated;
|
||||
}
|
||||
else {
|
||||
this_.notifyError("related to END, but no " +
|
||||
"duration!");
|
||||
// else only DUE is set i.e. relates to END
|
||||
}
|
||||
item.alarmRelated = alarmRelated;
|
||||
}
|
||||
var lastAck = ar[1];
|
||||
if (lastAck.length > 0) {
|
||||
var dtLastAck = new CalDateTime();
|
||||
dtLastAck.icalString = lastAck; // TZID is UTC
|
||||
// shift to alarm comp:
|
||||
item.alarmLastAck = dtLastAck;
|
||||
}
|
||||
}
|
||||
var lastAckProp = subComp.getFirstProperty("X-MOZ-LASTACK");
|
||||
if (lastAckProp) { // shift to alarm comp:
|
||||
// TZID is UTC:
|
||||
item.alarmLastAck =getDatetimeFromIcalProp(lastAckProp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче