bug 340949: fixed alarms, minor bugs

This commit is contained in:
daniel.boelzle%sun.com 2006-08-10 14:33:37 +00:00
Родитель 704f340474
Коммит 40e6de6cbc
6 изменённых файлов: 243 добавлений и 184 удалений

Просмотреть файл

@ -44,7 +44,7 @@ accessingServerFailedError.text=Cannot access server %1$S!
mandatoryHttpsError.text=Server %1$S needs to support HTTPS!
# args: host
noHttpsConfirmation.text=Insecure login on %1$S! Server does not support HTTPS. Continue?
noHttpsConfirmation.text=Insecure login on %1$S! Server does not support HTTPS.\nContinue?
noHttpsConfirmation.check.text=Don't ask again.
noHttpsConfirmation.label=Warning!
@ -53,7 +53,8 @@ reconnectConfirmation.text=Session on %1$S has timed out. Reconnect?
reconnectConfirmation.label=Session TimeOut
# args: host, prodId, serverVersion, wcapVersion
insufficientWcapVersionError.text=Server %1$S (%2$S, v%3$S) has insufficient WCAP version %4$S!
insufficientWcapVersionConfirmation.text=Server %1$S (%2$S, v%3$S, WCAP v%4$S) doesn't supports a sufficient WCAP version! The required version is at least 3.0.0.\nContinue?
insufficientWcapVersionConfirmation.label=Insufficient WCAP version!
# args: host, prodId, serverVersion, wcapVersion
loginDialog.text=Server: %1$S (%2$S, v%3$S, WCAP v%4$S)

Просмотреть файл

@ -254,6 +254,8 @@ calWcapCalendar.prototype = {
},
get isOwnedCalendar() {
if (!this.session.isLoggedIn)
return false;
var ownerId = this.ownerId;
return (this.calId == ownerId ||
this.calId.indexOf(ownerId + ":") == 0);

Просмотреть файл

@ -196,7 +196,7 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
var bIsEvent = isEvent(item);
var url = this.session.getCommandUrl( bIsEvent ? "storeevents"
: "storetodos" );
url += "&fetch=1&compressed=1&recurring=1";
url += "&fetch=1&relativealarm=1&compressed=1&recurring=1";
url += ("&calid=" + encodeURIComponent(this.calId));
var ownerId = this.ownerId;
@ -331,24 +331,25 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
// alarm support:
var alarmOffset = item.alarmOffset;
if (alarmOffset) {
var alarmStart = null;
if (item.alarmRelated ==
Components.interfaces.calIItemBase.ALARM_RELATED_END) {
if (!dtend)
this.logError("no end date (no end nor due) for alarm!");
else {
alarmStart = dtend.clone();
var alarmRelated = item.alarmRelated;
if (alarmRelated==Components.interfaces.calIItemBase.ALARM_RELATED_END){
// cs does not support RELATED=END:
var dur = item.duration;
if (dur) {
alarmOffset = alarmOffset.clone();
alarmOffset.isNegative = !alarmOffset.isNegative;
alarmOffset.addDuration(dur);
}
else {
this.notifyError("alarm relates to END, but no duration!");
alarmRelated =
Components.interfaces.calIItemBase.ALARM_RELATED_START;
}
}
else if (dtstart)
alarmStart = dtstart.clone(); // default
if (alarmStart != null) {
alarmStart.addDuration(alarmOffset);
var zalarmStart = getIcalUTC(alarmStart);
url += ("&alarmStart=" + zalarmStart);
alarmOffset = alarmOffset.icalString;
url += ("&alarmStart=" + alarmOffset);
url += ("&X-MOZ-WCAP-ALARM-RELATED=" +
"X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-REPLACE^" +
alarmRelated);
// xxx todo: verify ;-separated addresses
url += "&alarmEmails=";
if (item.hasProperty("alarmEmailAddress")) {
@ -357,14 +358,15 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
}
else {
// xxx todo: popup exor emails can be currently specified...
url += ("&alarmPopup=" + zalarmStart);
url += ("&alarmPopup=" + alarmOffset);
}
// 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;
@ -373,6 +375,10 @@ calWcapCalendar.prototype.getStoreUrl = function( item, oldItem )
"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({});
@ -740,32 +746,41 @@ calWcapCalendar.prototype.parseItems = function(
}
break;
}
// assure correct TRIGGER;RELATED if VALARM,
// cs does not constrain start/due with correct RELATED:
if (item != null && item.alarmOffset &&
item.alarmRelated == Components.interfaces
.calIItemBase.ALARM_RELATED_START &&
!item.entryDate) {
if (item.dueDate) {
// patch missing RELATED=END:
item.alarmRelated = Components.interfaces
.calIItemBase.ALARM_RELATED_END;
}
else {
this_.log( "todo has no entryDate nor dueDate, " +
"but VALARM => removing alarm!" );
item.alarmOffset = 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) {
dur = dur.clone();
dur.isNegative = true;
}
alarmOffset.addDuration(dur);
item.alarmOffset = alarmOffset;
item.alarmRelated = alarmRelated;
}
else {
this_.notifyError("related to END, but no " +
"duration!");
}
}
}
var lastAckProp = subComp.getFirstProperty("X-MOZ-LASTACK");
if (lastAckProp) { // shift to alarm comp:
// TZID is UTC:
item.alarmLastAck =getDatetimeFromIcalProp(lastAckProp);
}
}
item.calendar = this_.superCalendar;
var rid = subComp.getFirstProperty("RECURRENCE-ID");
@ -892,7 +907,8 @@ calWcapCalendar.prototype.getItem = function( id, iListener )
this_.log( "item delivered." );
};
var params = "&compressed=1&recurring=1&fmt-out=text%2Fcalendar";
var params = ("&relativealarm=1&compressed=1&recurring=1" +
"&fmt-out=text%2Fcalendar");
params += ("&calid=" + encodeURIComponent(this.calId));
params += ("&uid=" + id);
try {
@ -1028,8 +1044,9 @@ calWcapCalendar.prototype.getItems = function(
",\n\trangeEnd=" + zRangeEnd );
try {
var url = this.session.getCommandUrl( "fetchcomponents_by_range" );
url += ("&calid=" + encodeURIComponent(this.calId));
url += "&compressed=1&recurring=1";
url += ("&relativealarm=1&compressed=1&recurring=1" +
"&fmt-out=text%2Fcalendar&calid=" +
encodeURIComponent(this.calId));
switch (itemFilter &
Components.interfaces.calICalendar.ITEM_FILTER_TYPE_ALL) {
@ -1066,7 +1083,7 @@ calWcapCalendar.prototype.getItems = function(
var this_ = this;
this.session.issueAsyncRequest(
url + "&fmt-out=text%2Fcalendar", stringToIcal,
url, stringToIcal,
function( wcapResponse ) {
this_.getItems_resp( wcapResponse,
itemFilter, maxResult,
@ -1228,10 +1245,11 @@ calWcapCalendar.prototype.syncChangesTo = function(
this.log( "syncChangesTo(): doing initial sync." );
syncState.acquire();
var url = this.session.getCommandUrl( "fetchcomponents_by_range" );
url += ("&compressed=1&recurring=1&calid=" +
url += ("&relativealarm=1&compressed=1&recurring=1" +
"&fmt-out=text%2Fcalendar&calid=" +
encodeURIComponent(this.calId));
this.session.issueAsyncRequest(
url + "&fmt-out=text%2Fcalendar", stringToIcal,
url, stringToIcal,
function( wcapResponse ) {
this_.syncChangesTo_resp(
wcapResponse, syncState, iListener,
@ -1249,7 +1267,7 @@ calWcapCalendar.prototype.syncChangesTo = function(
this.log( "syncChangesTo(): getting last modifications." );
var modifyItemListener = new FinishListener(
Components.interfaces.calIOperationListener.MODIFY, syncState );
var params = ("&compressed=1&recurring=1&calid=" +
var params = ("&relativealarm=1&compressed=1&recurring=1&calid=" +
encodeURIComponent(this.calId));
params += ("&fmt-out=text%2Fcalendar&dtstart=" + zdtFrom);
syncState.acquire();

Просмотреть файл

@ -186,12 +186,6 @@ function issueSyncRequest( url, receiverFunc, bLogging )
url, "" /* charset */, null /* baseURI */ );
channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
var stream = channel.open();
if (bLogging && LOG_LEVEL > 1) {
logMessage( "issueSyncRequest( \"" + url + "\" )",
"contentCharset = " + channel.contentCharset +
", contentLength = " + channel.contentLength +
", contentType = " + channel.contentType );
}
var status = channel.status;
if (status == Components.results.NS_OK) {
var charset = channel.contentCharset;

Просмотреть файл

@ -114,7 +114,7 @@ calWcapSession.prototype = {
toString:
function( msg )
{
var str = this.uri.spec;
var str = (this.uri ? this.uri.spec : "no uri");
if (this.m_userId != null) {
str += (", userId=" + this.userId);
}
@ -201,11 +201,11 @@ calWcapSession.prototype = {
getSupportedTimezones:
function( bRefresh )
{
var key = this.uri.hostPort;
var key = this.sessionUri.hostPort;
if ((bRefresh || !g_allSupportedTimezones[key]) &&
this.m_sessionId != null)
{
var url = this.uri.spec +
var url = this.sessionUri.spec +
"get_all_timezones.wcap?appid=mozilla-lightning" +
"&fmt-out=text%2Fcalendar&id=" + this.m_sessionId;
var str = issueSyncRequest( url );
@ -246,10 +246,10 @@ calWcapSession.prototype = {
getServerTimeDiff:
function( bRefresh )
{
var key = this.uri.hostPort;
var key = this.sessionUri.hostPort;
if ((bRefresh || !g_serverTimeDiffs[key]) &&
this.m_sessionId != null) {
var url = this.uri.spec +
var url = this.sessionUri.spec +
// xxx todo: assuming same diff for all calids:
"gettime.wcap?appid=mozilla-lightning" +
"&fmt-out=text%2Fcalendar&id=" + this.m_sessionId;
@ -306,51 +306,18 @@ calWcapSession.prototype = {
}
if (this.m_sessionId == null || this.m_sessionId == timedOutSessionId) {
// sync all execution for login to UI thread, using nsIRunnable:
// change from MOZILLA_1_8_BRANCH->TRUNK: probe xxx todo: test
var eventQueueService =
Components.classes["@mozilla.org/event-queue-service;1"]
.getService(Components.interfaces.nsIEventQueueService);
var target; // eventQueue or eventTarget
if (eventQueueService == null) {
// we are on the TRUNK:
var threadManager =
Components.classes["@mozilla.org/thread-manager;1"]
.getService(Components.interfaces.nsIThreadManager);
target = threadManager.mainThread;
}
else {
target = eventQueueService.getSpecialEventQueue(
Components.interfaces.
nsIEventQueueService.UI_THREAD_EVENT_QUEUE );
}
var proxyObjectManager =
Components.classes["@mozilla.org/xpcomproxy;1"]
.getService(Components.interfaces.nsIProxyObjectManager);
var this_ = this;
var proxy = proxyObjectManager.getProxyForObject(
target, Components.interfaces.nsIRunnable,
{ // need to implemented QueryInterface, because object param
// is not associated with iid:
QueryInterface: function( iid ) {
if (Components.interfaces.nsIRunnable.equals(iid) ||
Components.interfaces.nsISupports.equals(iid))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
// nsIRunnable:
run: function() {
syncExec(
function() {
if (this_.m_sessionId == null ||
this_.m_sessionId == timedOutSessionId)
{
if (timedOutSessionId != null) {
this_.m_sessionId = null;
this_.log( "session timeout; " +
"prompting to reconnect." );
var prompt =
getWindowWatcher().getNewPrompter(null);
this_.log(
"session timeout; prompting to reconnect." );
var prompt =getWindowWatcher().getNewPrompter(null);
var bundle = getWcapBundle();
if (!prompt.confirm(
bundle.GetStringFromName(
@ -374,11 +341,7 @@ calWcapSession.prototype = {
}
}
}
}
},
Components.interfaces.nsIProxyObjectManager.INVOKE_SYNC );
// xxx todo: are rc/exceptions forwarded to current thread?
proxy.run();
} );
}
if (this.m_sessionId == null) {
throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED;
@ -390,6 +353,8 @@ calWcapSession.prototype = {
{
if (this.m_sessionId == null) {
this.log( "attempting to get a session id..." );
var passwordManager =
Components.classes["@mozilla.org/passwordmanager;1"]
.getService(Components.interfaces.nsIPasswordManager);
@ -413,7 +378,7 @@ calWcapSession.prototype = {
}
}
var loginUri = this.uri.clone();
var loginUri = this.sessionUri.clone();
if (loginUri.scheme.toLowerCase() != "https") {
if (loginUri.port == -1) {
// no https, but no port specified
@ -425,7 +390,7 @@ calWcapSession.prototype = {
// => leave it to her whether to connect...
if (!confirmInsecureLogin( loginUri )) {
this.m_bNoLoginsAnymore = true;
this.log( "user rejected unsecure login." );
this.log( "user rejected insecure login." );
return null;
}
}
@ -461,7 +426,7 @@ calWcapSession.prototype = {
"accessingServerFailedError.text",
[loginUri.hostPort], 1 ) );
}
if (this.uri.scheme.toLowerCase() == "https") {
if (this.sessionUri.scheme.toLowerCase() == "https") {
// user specified https, so http is no option:
loginText = null;
throw new Error(
@ -489,7 +454,7 @@ calWcapSession.prototype = {
}
}
catch (exc) {
Components.utils.reportError( exc );
this.logError( exc );
if (loginText == null) {
// accessing server or invalid protocol,
// no logins anymore:
@ -577,55 +542,44 @@ calWcapSession.prototype = {
getServerInfo:
function( uri )
{
loginTextVars = [uri.hostPort];
var loginText;
var wcapVersion;
var icalRootComp;
try {
// currently, xml parsing at an early stage during process startup
// does not work reliably, so use libical parsing for now:
var str = issueSyncRequest(
uri.spec + "version.wcap?fmt-out=text%2Fcalendar" );
var icalRootComp = getIcsService().parseICS( str );
if (str.indexOf("BEGIN:VCALENDAR") < 0)
return null; // no ical data returned
icalRootComp = getIcsService().parseICS( str );
if (icalRootComp == null)
throw new Error("invalid data, expected ical!");
var prop = icalRootComp.getFirstProperty( "PRODID" );
if (prop == null)
throw new Error("missing PRODID!");
loginTextVars.push( prop.value );
var prop = icalRootComp.getFirstProperty( "X-NSCP-SERVERVERSION" );
if (prop == null)
throw new Error("missing X-NSCP-SERVERVERSION!");
loginTextVars.push( prop.value );
var prop = icalRootComp.getFirstProperty( "X-NSCP-WCAPVERSION" );
if (prop == null)
throw new Error("missing X-NSCP-WCAPVERSION!");
wcapVersion = prop.value;
loginTextVars.push( wcapVersion );
// var xml = issueSyncXMLRequest(
// uri.spec + "version.wcap?fmt-out=text%2Fxml" );
// wcapVersion = xml.getElementsByTagName(
// "X-NSCP-WCAPVERSION" ).item(0).textContent;
// if (wcapVersion == undefined || wcapVersion == "")
// throw new Error("invalid response!");
// serverInfo =
// ("Server-Info: " +
// xml.getElementsByTagName(
// "iCal" ).item(0).attributes.getNamedItem(
// "prodid" ).value +
// ", v" + xml.getElementsByTagName(
// "X-NSCP-SERVERVERSION" ).item(0).textContent +
// ", WCAP v" + wcapVersion);
throw new Error("invalid ical data!");
}
catch (exc) {
this.log( "error: " + exc );
catch (exc) { // soft error; request denied etc.
this.log( "server version request failed: " + errorToString(exc) );
return null;
}
if (parseInt(wcapVersion) < 2.0) {
this.log( "parsed server WCAP major: " + parseInt(wcapVersion) );
throw new Error(
getWcapBundle("insufficientWcapVersionError.text",
loginTextVars) );
loginTextVars = [uri.hostPort];
var prop = icalRootComp.getFirstProperty( "PRODID" );
loginTextVars.push( prop ? prop.value : "<unknown>" );
prop = icalRootComp.getFirstProperty( "X-NSCP-SERVERVERSION" );
loginTextVars.push( prop ? prop.value : "<unknown>" );
prop = icalRootComp.getFirstProperty( "X-NSCP-WCAPVERSION" );
if (prop == null)
throw new Error("missing X-NSCP-WCAPVERSION!");
loginTextVars.push( prop.value );
var wcapVersion = parseInt(prop.value);
if (wcapVersion < 3) {
var prompt = getWindowWatcher().getNewPrompter(null);
var bundle = getWcapBundle();
var labelText = bundle.GetStringFromName(
"insufficientWcapVersionConfirmation.label");
if (!prompt.confirm( labelText,
bundle.formatStringFromName(
"insufficientWcapVersionConfirmation.text",
loginTextVars, loginTextVars.length ) )) {
throw new Error(labelText);
}
}
return getWcapBundle().formatStringFromName(
"loginDialog.text", loginTextVars, loginTextVars.length );
@ -634,12 +588,13 @@ calWcapSession.prototype = {
getCommandUrl:
function( wcapCommand )
{
if (this.uri == null)
if (this.sessionUri == null)
throw new Error("no URI!");
// ensure established session, so userId is set;
// (calId defaults to userId) if not set:
this.getSessionId();
return (this.uri.spec + wcapCommand + ".wcap?appid=mozilla-lightning");
return (this.sessionUri.spec +
wcapCommand + ".wcap?appid=mozilla-lightning");
},
issueRequest:
@ -707,7 +662,9 @@ calWcapSession.prototype = {
// calIWcapSession:
m_uri: null,
m_sessionUri: null,
get uri() { return this.m_uri; },
get sessionUri() { return this.m_sessionUri; },
set uri( thatUri )
{
if (this.m_uri == null || thatUri == null ||
@ -724,7 +681,10 @@ calWcapSession.prototype = {
(nColon >= 0 ? username.substr(0, nColon) : username);
}
this.m_uri = thatUri.clone();
this.m_uri.userPass = "";
this.log( "setting uri to " + this.uri.spec );
this.m_sessionUri = thatUri.clone();
this.m_sessionUri.userPass = "";
this.log( "setting sessionUri to " + this.sessionUri.spec );
}
}
},
@ -748,7 +708,7 @@ calWcapSession.prototype = {
// although io service's offline flag is already
// set BEFORE notification (about to go offline, nsIOService.cpp).
// WTF.
var url = (this.uri.spec +
var url = (this.sessionUri.spec +
"logout.wcap?fmt-out=text%2Fxml&id=" + this.m_sessionId);
try {
checkWcapXmlErrno( issueSyncXMLRequest(url),

Просмотреть файл

@ -253,6 +253,90 @@ function setPref(prefName, value)
}
}
function syncExec( func )
{
// xxx todo: how to do better?
// possible HACK here, because of lack of sync possibilities:
// when we run into executing dialogs, the js runtime
// concurrently executes (another getItems() request).
// That concurrent request needs to wait for the first login
// attempt to finish.
// Creating a thread event queue somehow hinders the js engine
// from scheduling another js execution.
var eventQueueService = null;
try {
eventQueueService =
Components.classes["@mozilla.org/event-queue-service;1"]
.getService(Components.interfaces.nsIEventQueueService);
}
catch (exc) {
}
if (eventQueueService != null) {
var eventQueue = eventQueueService.pushThreadEventQueue();
try {
func();
}
catch (exc) {
eventQueueService.popThreadEventQueue( eventQueue );
throw exc;
}
eventQueueService.popThreadEventQueue( eventQueue );
}
else // xxx todo: eventQueue has vanished on TRUNK
func();
}
// // xxx todo: the below code still does not sync properly...
// function syncExec( func )
// {
// // sync all execution for login to UI thread, using nsIRunnable:
// // change from MOZILLA_1_8_BRANCH->TRUNK: probe xxx todo: test
// var target = null; // eventQueue or eventTarget
// try {
// var eventQueueService =
// Components.classes["@mozilla.org/event-queue-service;1"]
// .getService(Components.interfaces.nsIEventQueueService);
// if (eventQueueService != null) {
// target = eventQueueService.getSpecialEventQueue(
// Components.interfaces.
// nsIEventQueueService.UI_THREAD_EVENT_QUEUE );
// }
// }
// catch (exc) {
// // eventQueue has vanished on TRUNK
// }
// if (target == null) {
// // we are on the TRUNK:
// var threadManager = Components.classes["@mozilla.org/thread-manager;1"]
// .getService(Components.interfaces.nsIThreadManager);
// target = threadManager.mainThread;
// }
// var proxyObjectManager =
// Components.classes["@mozilla.org/xpcomproxy;1"]
// .getService(Components.interfaces.nsIProxyObjectManager);
// var proxy = proxyObjectManager.getProxyForObject(
// target, Components.interfaces.nsIRunnable,
// { // need to implemented QueryInterface, because object param
// // is not associated with iid:
// QueryInterface:
// function( iid ) {
// if (Components.interfaces.nsIRunnable.equals(iid) ||
// Components.interfaces.nsISupports.equals(iid))
// return this;
// throw Components.results.NS_ERROR_NO_INTERFACE;
// },
// // nsIRunnable:
// run:
// function() {
// func();
// }
// },
// Components.interfaces.nsIProxyObjectManager.INVOKE_SYNC );
// // xxx todo: are rc/exceptions forwarded to current thread?
// proxy.run();
// }
//
// init code for globals, prefs: