Bug 340949: error handling, task alarm handling, misc

git-svn-id: svn://10.0.0.236/trunk@208804 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
daniel.boelzle%sun.com 2006-08-30 10:47:38 +00:00
parent 0f2080bb34
commit 6055018da3
8 changed files with 366 additions and 217 deletions

View File

@ -183,9 +183,11 @@ calWcapCachedCalendar.prototype = {
function( err )
{
debugger;
var str = this.logError( err );
this.notifyObservers( "onError",
[err instanceof Error ? -1 : err, str] );
var msg = this.logError(err);
this.notifyObservers(
"onError",
err instanceof Components.interfaces.nsIException
? [err.result, err.message] : [-1, msg] );
},
// calIWcapCalendar:
@ -472,7 +474,7 @@ calWcapCachedCalendar.prototype = {
}
}
else {
throw new Error(
throw new Components.Exception(
"unexpected operation type! " +
"(expected SYNC)" );
}

View File

@ -128,17 +128,19 @@ calWcapCalendar.prototype = {
logError:
function( err, context )
{
var str = ("error: " + errorToString(err));
Components.utils.reportError( this.log( str, context ) );
return str;
var msg = errorToString(err);
Components.utils.reportError( this.log("error: " + msg, context) );
return msg;
},
notifyError:
function( err )
{
debugger;
var str = this.logError( err );
this.notifyObservers( "onError",
[err instanceof Error ? -1 : err, str] );
var msg = this.logError(err);
this.notifyObservers(
"onError",
err instanceof Components.interfaces.nsIException
? [err.result, err.message] : [-1, msg] );
},
// calICalendar:
@ -319,7 +321,6 @@ calWcapCalendar.prototype = {
},
// set defaultTimezone( tzid ) {
// if (this.readOnly)
// throw Components.interfaces.calIErrors.CAL_IS_READONLY;
// // xxx todo:
// throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
// },

View File

@ -355,11 +355,12 @@ calWcapCalendar.prototype.storeItem = function( item, oldItem, receiverFunc )
// undefined, assume an allDay todo???
dtstart = item.entryDate;
dtend = item.dueDate;
if (dtend) {
url += ("&due=" + getIcalUTC(dtend));
// url += ("&X-NSCP-DUE-TZID=" + encodeURIComponent(
// this.getAlignedTimezone(dtend.timezone)));
}
url += ("&due=" + getIcalUTC(dtend));
// if (dtend) {
// url += ("&X-NSCP-DUE-TZID=" + encodeURIComponent(
// this.getAlignedTimezone(dtend.timezone)));
// }
bIsAllDay = (dtstart && dtstart.isDate);
if (item.isCompleted)
url += "&percent=100";
@ -383,10 +384,10 @@ calWcapCalendar.prototype.storeItem = function( item, oldItem, receiverFunc )
if (bIsAllDay)
url += "&isAllDay=1";
url += ("&dtstart=" + getIcalUTC(dtstart));
if (dtstart) {
// important to provide tz info with entry date for proper
// occurrence calculation (daylight savings)
url += ("&dtstart=" + getIcalUTC(dtstart));
// xxx todo: setting X-NSCP-tz does not work.
// i.e. for now no separate tz for start/end.
// url += ("&X-NSCP-DTSTART-TZID=" +
@ -396,6 +397,10 @@ calWcapCalendar.prototype.storeItem = function( item, oldItem, receiverFunc )
this.getAlignedTimezone(dtstart.timezone)));
}
// xxx todo: alarm mimic of todos currently different:
// WCAP offsets relate to DUE
if (bIsEvent) {
// alarm support:
var alarmStart = item.alarmOffset;
if (alarmStart) {
@ -422,19 +427,16 @@ calWcapCalendar.prototype.storeItem = function( item, oldItem, receiverFunc )
// this.log( "setting default alarm start: " + alarmStart.icalString );
// }
// }
url += "&alarmStart=";
if (alarmStart) {
// minimal alarm server support: Alarms are currently off by default,
// so let server at least send reminder eMails...
url += alarmStart.icalString;
url += "&alarmEmails=";
var emails = "";
if (item.hasProperty("alarmEmailAddress"))
url += encodeURIComponent( item.getProperty("alarmEmailAddress") );
emails = encodeURIComponent(item.getProperty("alarmEmailAddress"));
else {
var ar = this.session.getUserPreferences(
"X-NSCP-WCAP-PREF-ceDefaultAlarmEmail", {});
if (ar.length > 0 && ar[0].length > 0) {
var emails = "";
for each ( var i in ar ) {
var ars = i.split(/[;,]/);
for each ( var j in ars ) {
@ -446,20 +448,21 @@ calWcapCalendar.prototype.storeItem = function( item, oldItem, receiverFunc )
}
}
}
url += emails;
url += "&alarmPopup=";
}
else {
// xxx todo: popup exor emails can be currently specified...
url += ("&alarmPopup=" + alarmStart.icalString);
}
}
url += ("&alarmStart=" + alarmStart.icalString);
url += ("&alarmEmails=" + emails);
url += "&alarmPopup=";
if (emails.length == 0)
url += alarmStart.icalString;
// xxx todo: missing: alarm triggers for flashing, etc.
}
else {
// clear popup, emails:
url += "&alarmPopup=&alarmEmails=";
url += "&alarmStart=&alarmPopup=&alarmEmails=";
}
} // if (bIsEvent)
// xxx todo: however, sometimes socs just returns an empty calendar when
// nothing or only optional props like attendee ROLE has changed,
@ -506,7 +509,7 @@ calWcapCalendar.prototype.adoptItem_resp = function( wcapResponse, listener )
Components.interfaces.calICalendar.ITEM_FILTER_ALL_ITEMS,
0, null, null );
if (items.length < 1)
throw new Error("empty VCALENDAR returned!");
throw new Components.Exception("empty VCALENDAR returned!");
if (items.length > 1)
this.notifyError( "unexpected number of items: " + items.length );
item = items[0];
@ -535,9 +538,13 @@ calWcapCalendar.prototype.adoptItem_resp = function( wcapResponse, listener )
calWcapCalendar.prototype.adoptItem = function( item, listener )
{
this.log( "adoptItem() call: " + item.title );
if (this.readOnly)
throw Components.interfaces.calIErrors.CAL_IS_READONLY;
try {
if (this.readOnly) {
throw new Components.Exception(
"Calendar is read-only.",
Components.interfaces.calIErrors.CAL_IS_READONLY );
}
// xxx todo: workaround really necessary for adding an occurrence?
var oldItem = null;
if (!isParent(item)) {
@ -583,7 +590,7 @@ calWcapCalendar.prototype.modifyItem_resp = function(
Components.interfaces.calICalendar.ITEM_FILTER_ALL_ITEMS,
0, null, null );
if (items.length < 1)
throw new Error("empty VCALENDAR returned!");
throw new Components.Exception("empty VCALENDAR returned!");
if (items.length > 1)
this.notifyError( "unexpected number of items: " + items.length );
item = items[0];
@ -610,13 +617,15 @@ calWcapCalendar.prototype.modifyItem_resp = function(
calWcapCalendar.prototype.modifyItem = function( newItem, oldItem, listener )
{
this.log( "modifyItem() call: " + newItem.id );
if (this.readOnly)
throw Components.interfaces.calIErrors.CAL_IS_READONLY;
this.log( "modifyItem() call: " + newItem.id );
try {
if (this.readOnly) {
throw new Components.Exception(
"Calendar is read-only.",
Components.interfaces.calIErrors.CAL_IS_READONLY );
}
if (!newItem.id)
throw new Error("new item has no id!");
throw new Components.Exception("new item has no id!");
var this_ = this;
this.storeItem(
@ -673,11 +682,14 @@ calWcapCalendar.prototype.deleteItem_resp = function(
calWcapCalendar.prototype.deleteItem = function( item, listener )
{
this.log( "deleteItem() call: " + item.id );
if (this.readOnly)
throw Components.interfaces.calIErrors.CAL_IS_READONLY;
try {
if (this.readOnly) {
throw new Components.Exception(
"Calendar is read-only.",
Components.interfaces.calIErrors.CAL_IS_READONLY );
}
if (item.id == null)
throw new Error("no item id!");
throw new Components.Exception("no item id!");
var url = this.session.getCommandUrl(
isEvent(item) ? "deleteevents_by_id" : "deletetodos_by_id" );
@ -777,12 +789,13 @@ 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 );
// 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 );
if (item) { // xxx todo: todo alarms currently off
item.alarmOffset = null;
item.alarmLastAck = null;
}
@ -865,7 +878,7 @@ calWcapCalendar.prototype.parseItems = function(
for each ( var item in excItems ) {
var parent = uid2parent[item.id];
if (parent == null) {
this.logError( "getItems_resp(): no parent item for rid=" +
this.logError( "parseItems(): no parent item for rid=" +
item.recurrenceId );
}
else {
@ -931,7 +944,7 @@ calWcapCalendar.prototype.getItem = function( id, listener )
Components.interfaces.calICalendar.ITEM_FILTER_ALL_ITEMS,
1, null, null );
if (items.length < 1)
throw new Error("no such item!");
throw new Components.Exception("no such item!");
if (items.length > 1) {
this_.notifyError(
"unexpected number of items: " + items.length );
@ -941,7 +954,7 @@ calWcapCalendar.prototype.getItem = function( id, listener )
listener.onGetResult(
this_.superCalendar, Components.results.NS_OK,
Components.interfaces.calIItemBase,
this_.log( "getItems_resp(): success." ),
this_.log( "getItem(): success." ),
items.length, items );
listener.onOperationComplete(
this_.superCalendar, Components.results.NS_OK,
@ -988,8 +1001,8 @@ calWcapCalendar.prototype.getItems_resp = function(
var exc = wcapResponse.exception;
// check whether access is denied,
// then show free-busy information instead:
if (exc && (exc == Components.interfaces.
calIWcapErrors.WCAP_ACCESS_DENIED_TO_CALENDAR)) {
if (testResultCode( exc, Components.interfaces.
calIWcapErrors.WCAP_ACCESS_DENIED_TO_CALENDAR)) {
if (listener != null) {
var this_ = this;
var freeBusyListener = { // calIWcapFreeBusyListener:
@ -1048,7 +1061,7 @@ calWcapCalendar.prototype.getItems_resp = function(
if (listener != null) {
listener.onGetResult( this.superCalendar, Components.results.NS_OK,
Components.interfaces.calIItemBase,
this.log( "getItems_resp(): success." ),
this.log( "getItems(): success." ),
items.length, items );
listener.onOperationComplete(
this.superCalendar, Components.results.NS_OK,
@ -1149,7 +1162,8 @@ calWcapCalendar.prototype.getItems = function(
Components.interfaces.calIOperationListener.GET,
null, exc );
}
if (exc == Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED) {
if (testResultCode(exc, Components.interfaces.
calIWcapErrors.WCAP_LOGIN_FAILED)) {
// silently ignore login failed, no calIObserver UI:
this.log( "getItems_resp() ignored: " + errorToString(exc) );
}
@ -1211,14 +1225,16 @@ FinishListener.prototype = {
}
else if (this.m_opType != opType) {
this.m_syncState.abort(
new Error("unexpected operation type: " + opType) );
new Components.Exception("unexpected operation type: " +
opType) );
}
this.m_syncState.release();
},
onGetResult:
function( calendar, status, itemType, detail, count, items )
{
this.m_syncState.abort( new Error("unexpected onGetResult()!") );
this.m_syncState.abort(
new Components.Exception("unexpected onGetResult()!") );
}
};

View File

@ -60,6 +60,9 @@ var CACHE = "off";
// denotes where to host local storage calendar(s)
var CACHE_DIR = null;
// timeout for sync network requests (in secs):
var SYNC_REQUESTS_TIMEOUT = 10;
// logging:
#expand var LOG_LEVEL = __LOG_LEVEL__;
var LOG_TIMEZONE = null;
@ -92,6 +95,9 @@ function initWcapProvider()
"busyItem.title.text");
g_busyPhantomItemUuidPrefix = ("PHANTOM_uuid" + getTime().icalString);
SYNC_REQUESTS_TIMEOUT = getPref(
"calendar.wcap.sync_request_timeout", 10);
LOG_TIMEZONE = getPref("calendar.timezone.local", null);
var logLevel = getPref("calendar.wcap.log_level", null);
@ -166,7 +172,7 @@ function initWcapProvider()
}
}
var calWcapCalendarModule = {
var calWcapCalendarModule = { // nsIModule:
WcapCalendarInfo: {
classDescription: "Sun Java System Calendar Server WCAP Provider",
@ -197,6 +203,16 @@ var calWcapCalendarModule = {
fileSpec, location, type );
},
unregisterSelf:
function( compMgr, fileSpec, location ) {
compMgr = compMgr.QueryInterface(
Components.interfaces.nsIComponentRegistrar );
compMgr.unregisterFactoryLocation(
this.WcapCalendarInfo.classID, fileSpec );
compMgr.unregisterFactoryLocation(
this.WcapSessionInfo.classID, fileSpec );
},
m_scriptsLoaded: false,
getClassObject:
function( compMgr, cid, iid )
@ -230,9 +246,9 @@ var calWcapCalendarModule = {
if (!iid.equals( Components.interfaces.nsIFactory ))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
return {
createInstance:
function( outer, iid ) {
return { // nsIFactory:
lockFactory: function( lock ) {},
createInstance: function( outer, iid ) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
var session = new calWcapSession();

View File

@ -37,10 +37,90 @@
*
* ***** END LICENSE BLOCK ***** */
//
// Common netwerk errors:
//
const NS_ERROR_MODULE_BASE_OFFSET = 0x45;
const NS_ERROR_MODULE_NETWORK = 6;
function generateFailure(module, code) {
return ((1<<31) | ((module + NS_ERROR_MODULE_BASE_OFFSET) << 16) | code);
}
function generateNetFailure(code) {
return generateFailure(NS_ERROR_MODULE_NETWORK, code);
}
function getErrorModule( rc ) {
return (((rc >>> 16) & 0x7fff) - NS_ERROR_MODULE_BASE_OFFSET);
}
// Cannot perform operation, because user is offline.
// This has been taken from netwerk/base/public/nsNetError.h
// The following error codes have been adopted from
// netwerk/base/public/nsNetError.h
// and ought to be defined in IDL. xxx todo
const NS_ERROR_OFFLINE = ((1<<31) | ((6+0x45)<<16) | 16);
// The requested action could not be completed while the networking
// is in the offline state.
const NS_ERROR_OFFLINE = generateNetFailure(16);
// The async request failed for some unknown reason.
const NS_BINDING_FAILED = generateNetFailure(1);
const g_nsNetErrorCodes = [
NS_BINDING_FAILED,
"The async request failed for some unknown reason.",
/*NS_BINDING_ABORTED*/ generateNetFailure(2),
"The async request failed because it was aborted by some user action.",
/*NS_ERROR_MALFORMED_URI*/ generateNetFailure(10),
"The URI is malformed.",
/*NS_ERROR_UNKNOWN_PROTOCOL*/ generateNetFailure(18),
"The URI scheme corresponds to an unknown protocol handler.",
/*NS_ERROR_CONNECTION_REFUSED*/ generateNetFailure(13),
"The connection attempt failed, for example, because no server was listening at specified host:port.",
/*NS_ERROR_PROXY_CONNECTION_REFUSED*/ generateNetFailure(72),
"The connection attempt to a proxy failed.",
/*NS_ERROR_NET_TIMEOUT*/ generateNetFailure(14),
"The connection was lost due to a timeout error.",
NS_ERROR_OFFLINE,
"The requested action could not be completed while the networking library is in the offline state.",
/*NS_ERROR_PORT_ACCESS_NOT_ALLOWED*/ generateNetFailure(19),
"The requested action was prohibited because it would have caused the networking library to establish a connection to an unsafe or otherwise banned port.",
/*NS_ERROR_NET_RESET*/ generateNetFailure(20),
"The connection was established, but no data was ever received.",
/*NS_ERROR_NET_INTERRUPT*/ generateNetFailure(71),
"The connection was established, but the data transfer was interrupted.",
/*NS_ERROR_NOT_RESUMABLE*/ generateNetFailure(25),
"This request is not resumable, but it was tried to resume it, or to request resume-specific data.",
/*NS_ERROR_ENTITY_CHANGED*/ generateNetFailure(32),
"It was attempted to resume the request, but the entity has changed in the meantime.",
/*NS_ERROR_REDIRECT_LOOP*/ generateNetFailure(31),
"The request failed as a result of a detected redirection loop.",
/*NS_ERROR_UNKNOWN_HOST*/ generateNetFailure(30),
"The lookup of a hostname failed. This generally refers to the hostname from the URL being loaded.",
/*NS_ERROR_UNKNOWN_PROXY_HOST*/ generateNetFailure(42),
"The lookup of a proxy hostname failed.",
/*NS_ERROR_UNKNOWN_SOCKET_TYPE*/ generateNetFailure(51),
"The specified socket type does not exist.",
/*NS_ERROR_SOCKET_CREATE_FAILED*/ generateNetFailure(52),
"The specified socket type could not be created."
];
function netErrorToString( rc )
{
if (getErrorModule(rc) == NS_ERROR_MODULE_NETWORK) {
var i = 0;
while (i < g_nsNetErrorCodes.length) {
// rc is kept unsigned, our generated code signed,
// so == won't work here:
if ((g_nsNetErrorCodes[i] ^ rc) == 0)
return g_nsNetErrorCodes[i + 1];
i += 2;
}
}
throw Components.results.NS_ERROR_INVALID_ARG;
}
//
// WCAP error handling helpers
@ -181,34 +261,6 @@ function wcapErrorToString( rc )
throw Components.results.NS_ERROR_INVALID_ARG;
}
function errorToString( err )
{
if (typeof(err) == "string")
return err;
if (err instanceof Error)
return err.message;
switch (err) {
case NS_ERROR_OFFLINE:
return "NS_ERROR_OFFLINE";
// xxx todo: there may be a more comprehensive API for these:
case Components.results.NS_ERROR_INVALID_ARG:
return "NS_ERROR_INVALID_ARG";
case Components.results.NS_ERROR_NO_INTERFACE:
return "NS_ERROR_NO_INTERFACE";
case Components.results.NS_ERROR_NOT_IMPLEMENTED:
return "NS_ERROR_NOT_IMPLEMENTED";
case Components.results.NS_ERROR_FAILURE:
return "NS_ERROR_FAILURE";
default: // probe for WCAP error:
try {
return wcapErrorToString(err);
}
catch (exc) {
return ("[" + err + "] Unknown error.");
}
}
}
function getWcapErrorCode( errno )
{
var index = -1;
@ -233,7 +285,9 @@ function getWcapXmlErrno( xml )
return parseInt(elem.textContent);
}
// some commands just respond with an empty calendar, no errno. WTF.
throw Components.interfaces.calIWcapErrors.WCAP_NO_ERRNO;
throw new Components.Exception(
"No WCAP errno (missing X-NSCP-WCAP-ERRNO).",
Components.interfaces.calIWcapErrors.WCAP_NO_ERRNO );
}
function getWcapIcalErrno( icalRootComp )
@ -242,15 +296,26 @@ function getWcapIcalErrno( icalRootComp )
if (prop)
return parseInt(prop.value);
// some commands just respond with an empty calendar, no errno. WTF.
throw Components.interfaces.calIWcapErrors.WCAP_NO_ERRNO;
throw new Components.Exception(
"No WCAP errno (missing X-NSCP-WCAP-ERRNO).",
Components.interfaces.calIWcapErrors.WCAP_NO_ERRNO );
}
function checkWcapErrno( errno, expectedErrno )
{
if (expectedErrno == undefined)
expectedErrno = 0; // i.e. Command successful.
if (errno != expectedErrno)
throw getWcapErrorCode(errno);
if (errno != expectedErrno) {
var rc;
try {
rc = getWcapErrorCode(errno);
}
catch (exc) {
throw new Components.Exception(
"No WCAP error no.", Components.results.NS_ERROR_INVALID_ARG );
}
throw new Components.Exception( wcapErrorToString(rc), rc );
}
}
function checkWcapXmlErrno( xml, expectedErrno )
@ -263,3 +328,34 @@ function checkWcapIcalErrno( icalRootComp, expectedErrno )
checkWcapErrno( getWcapIcalErrno(icalRootComp), expectedErrno );
}
function errorToString( err )
{
if (typeof(err) == "string")
return err;
if (err instanceof Error)
return err.message;
switch (err) {
case Components.results.NS_ERROR_INVALID_ARG:
return "NS_ERROR_INVALID_ARG";
case Components.results.NS_ERROR_NO_INTERFACE:
return "NS_ERROR_NO_INTERFACE";
case Components.results.NS_ERROR_NOT_IMPLEMENTED:
return "NS_ERROR_NOT_IMPLEMENTED";
case Components.results.NS_ERROR_FAILURE:
return "NS_ERROR_FAILURE";
default: // probe for WCAP error:
try {
return wcapErrorToString(err);
}
catch (exc) { // probe for netwerk error:
try {
return netErrorToString(err);
}
catch (exc) {
return ("[" + err + "] Unknown error.");
}
}
}
}

View File

@ -78,8 +78,11 @@ WcapResponse.prototype = {
function stringToIcal( data )
{
if (!data || data == "") // assuming time-out
throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED;
if (!data || data == "") { // assuming time-out
throw new Components.Exception(
"Login failed. Invalid session ID.",
Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED );
}
var icalRootComp = getIcsService().parseICS( data );
checkWcapIcalErrno( icalRootComp );
return icalRootComp;
@ -87,8 +90,11 @@ function stringToIcal( data )
function stringToXml( data )
{
if (!data || data == "") // assuming time-out
throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED;
if (!data || data == "") { // assuming time-out
throw new Components.Exception(
"Login failed. Invalid session ID.",
Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED );
}
var xml = getDomParser().parseFromString( data, "text/xml" );
checkWcapXmlErrno( xml );
return xml;
@ -185,7 +191,21 @@ function issueSyncRequest( url, receiverFunc, bLogging )
var channel = getIoService().newChannel(
url, "" /* charset */, null /* baseURI */ );
channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
var timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
timer.initWithCallback(
{ // nsITimerCallback:
notify: function( timer_ ) {
if (channel.isPending())
channel.cancel(NS_BINDING_FAILED);
}
},
SYNC_REQUESTS_TIMEOUT * 1000,
Components.interfaces.nsITimer.TYPE_ONE_SHOT );
var stream = channel.open();
timer.cancel();
var status = channel.status;
if (status == Components.results.NS_OK) {
var charset = channel.contentCharset;
@ -205,7 +225,11 @@ function issueSyncRequest( url, receiverFunc, bLogging )
logMessage( "issueSyncRequest( \"" + url + "\" )",
"failed: " + status );
}
throw status;
throw new Components.Exception(
bLogging ? ("issueSyncRequest( \"" + url + "\" ) failed.")
: "issueSyncRequest() failed.",
status );
}
function issueSyncXMLRequest( url, receiverFunc, bLogging )

View File

@ -134,17 +134,19 @@ calWcapSession.prototype = {
logError:
function( err, context )
{
var str = ("error: " + errorToString(err));
Components.utils.reportError( this.log( str, context ) );
return str;
var msg = errorToString(err);
Components.utils.reportError( this.log("error: " + msg, context) );
return msg;
},
notifyError:
function( err )
{
debugger;
var str = this.logError( err );
this.notifyObservers( "onError",
[err instanceof Error ? -1 : err, str] );
var msg = this.logError(err);
this.notifyObservers(
"onError",
err instanceof Components.interfaces.nsIException
? [err.result, err.message] : [-1, msg] );
},
m_observers: null,
@ -211,7 +213,7 @@ calWcapSession.prototype = {
var str = issueSyncRequest( url );
var icalRootComp = getIcsService().parseICS( str );
if (icalRootComp == null)
throw new Error("invalid data, expected ical!");
throw new Components.Exception("invalid data, expected ical!");
checkWcapIcalErrno( icalRootComp );
var tzids = [];
var this_ = this;
@ -258,7 +260,7 @@ calWcapSession.prototype = {
var str = issueSyncRequest( url );
var icalRootComp = getIcsService().parseICS( str );
if (icalRootComp == null)
throw new Error("invalid data, expected ical!");
throw new Components.Exception("invalid data, expected ical!");
checkWcapIcalErrno( icalRootComp );
var serverTime = getDatetimeFromIcalProp(
icalRootComp.getFirstProperty( "X-NSCP-WCAPTIME" ) );
@ -298,30 +300,35 @@ calWcapSession.prototype = {
{
if (this.m_bNoLoginsAnymore) {
this.log( "login has failed, no logins anymore for this user." );
throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED;
throw new Components.Exception(
"Login failed. Invalid session ID.",
Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED );
}
if (getIoService().offline) {
this.log( "in offline mode." );
throw NS_ERROR_OFFLINE;
throw new Components.Exception(
"The requested action could not be completed while the " +
"networking library is in the offline state.",
NS_ERROR_OFFLINE );
}
if (this.m_sessionId == null || this.m_sessionId == timedOutSessionId) {
var this_ = this;
syncExec(
lockedExec(
function() {
if (this_.m_sessionId == null ||
this_.m_sessionId == timedOutSessionId)
{
if (!this_.m_bNoLoginsAnymore &&
(this_.m_sessionId == null ||
this_.m_sessionId == timedOutSessionId)) {
if (timedOutSessionId != null) {
this_.m_sessionId = null;
this_.log(
"session timeout; prompting to reconnect." );
this_.log( "session timeout; " +
"prompting to reconnect." );
var prompt =getWindowWatcher().getNewPrompter(null);
var bundle = getWcapBundle();
if (!prompt.confirm(
bundle.GetStringFromName(
"reconnectConfirmation.label" ),
"reconnectConfirmation.label"),
bundle.formatStringFromName(
"reconnectConfirmation.text",
[this_.uri.hostPort], 1 ) )) {
@ -343,8 +350,11 @@ calWcapSession.prototype = {
}
} );
}
if (this.m_sessionId == null) {
throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED;
throw new Components.Exception(
"Login failed. Invalid session ID.",
Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED );
}
return this.m_sessionId;
},
@ -381,7 +391,7 @@ calWcapSession.prototype = {
var loginUri = this.sessionUri.clone();
if (loginUri.scheme.toLowerCase() != "https") {
if (loginUri.port == -1) {
// no https, but no port specified
// no https and no port specified
// => enforce login via https:
loginUri.scheme = "https";
}
@ -421,7 +431,7 @@ calWcapSession.prototype = {
loginText = this.getServerInfo( loginUri );
}
if (loginText == null) {
throw new Error(
throw new Components.Exception(
getWcapBundle().formatStringFromName(
"accessingServerFailedError.text",
[loginUri.hostPort], 1 ) );
@ -429,7 +439,7 @@ calWcapSession.prototype = {
if (this.sessionUri.scheme.toLowerCase() == "https") {
// user specified https, so http is no option:
loginText = null;
throw new Error(
throw new Components.Exception(
getWcapBundle().formatStringFromName(
"mandatoryHttpsError.text",
[loginUri.hostPort], 1 ) );
@ -477,6 +487,7 @@ calWcapSession.prototype = {
var savePW = { value: false };
while (this.m_sessionId == null) {
this.log( "prompting for user/pw..." );
var prompt = getWindowWatcher().getNewPrompter(null);
if (prompt.promptUsernameAndPassword(
getWcapBundle().GetStringFromName(
@ -526,7 +537,7 @@ calWcapSession.prototype = {
checkWcapIcalErrno( icalRootComp );
var prop = icalRootComp.getFirstProperty( "X-NSCP-WCAP-SESSION-ID" );
if (prop == null)
throw new Error("missing X-NSCP-WCAP-SESSION-ID!");
throw new Components.Exception("missing X-NSCP-WCAP-SESSION-ID!");
this.m_sessionId = prop.value;
// var xml = issueSyncXMLRequest(
@ -552,7 +563,7 @@ calWcapSession.prototype = {
return null; // no ical data returned
icalRootComp = getIcsService().parseICS( str );
if (icalRootComp == null)
throw new Error("invalid ical data!");
throw new Components.Exception("invalid ical data!");
}
catch (exc) { // soft error; request denied etc.
this.log( "server version request failed: " + errorToString(exc) );
@ -566,7 +577,7 @@ calWcapSession.prototype = {
loginTextVars.push( prop ? prop.value : "<unknown>" );
prop = icalRootComp.getFirstProperty( "X-NSCP-WCAPVERSION" );
if (prop == null)
throw new Error("missing X-NSCP-WCAPVERSION!");
throw new Components.Exception("missing X-NSCP-WCAPVERSION!");
loginTextVars.push( prop.value );
var wcapVersion = parseInt(prop.value);
if (wcapVersion < 3) {
@ -578,7 +589,7 @@ calWcapSession.prototype = {
bundle.formatStringFromName(
"insufficientWcapVersionConfirmation.text",
loginTextVars, loginTextVars.length ) )) {
throw new Error(labelText);
throw new Components.Exception(labelText);
}
}
return getWcapBundle().formatStringFromName(
@ -589,7 +600,7 @@ calWcapSession.prototype = {
function( wcapCommand )
{
if (this.sessionUri == null)
throw new Error("no URI!");
throw new Components.Exception("no URI!");
// ensure established session, so userId is set;
// (calId defaults to userId) if not set:
this.getSessionId();
@ -613,8 +624,10 @@ calWcapSession.prototype = {
data, wcapResponse );
}
catch (exc) {
if (exc == Components.interfaces.
calIWcapErrors.WCAP_LOGIN_FAILED) /* timeout */ {
if (testResultCode(
exc, Components.interfaces.
calIWcapErrors.WCAP_LOGIN_FAILED)) /* timeout */
{
// getting a new session will throw any exception in
// this block, thus it is notified into receiverFunc
this_.getSessionId(
@ -931,7 +944,7 @@ calWcapSession.prototype = {
}
catch (exc) {
const calIWcapErrors = Components.interfaces.calIWcapErrors;
switch (exc) {
switch (getResultCode(exc)) {
case calIWcapErrors.WCAP_NO_ERRNO: // workaround
case calIWcapErrors.WCAP_ACCESS_DENIED_TO_CALENDAR:
case calIWcapErrors.WCAP_CALENDAR_DOES_NOT_EXIST:

View File

@ -131,6 +131,57 @@ function getCalendarManager()
return g_calendarManager;
};
var g_bInitedLockedExec = false;
var g_eventQueueService = null;
var g_threadManager = null;
/** Locks event dispatching for the current event queue while the passed
function is executed.
xxx todo: this hinders timeeout events for sync requests
to be dispatched!
*/
function lockedExec( func )
{
if (!g_bInitedLockedExec) {
try {
var cl = Components.classes["@mozilla.org/event-queue-service;1"];
if (cl) {
g_eventQueueService =
cl.getService(Components.interfaces.nsIEventQueueService);
}
}
catch (exc) { // eventQueue has vanished on trunk
}
if (!g_eventQueueService) {
g_threadManager =
Components.classes["@mozilla.org/thread-manager;1"]
.getService(Components.interfaces.nsIThreadManager);
}
g_bInitedLockedExec = true;
}
var queue;
if (g_eventQueueService)
queue = g_eventQueueService.pushThreadEventQueue();
else // we are on trunk using nsIThreadInternal
g_threadManager.currentThread.pushEventQueue(null);
try {
return func();
}
catch (exc) {
if (g_eventQueueService)
g_eventQueueService.popThreadEventQueue(queue);
else // we are on trunk using nsIThreadInternal
g_threadManager.currentThread.popEventQueue();
throw exc;
}
if (g_eventQueueService)
g_eventQueueService.popThreadEventQueue(queue);
else // we are on trunk using nsIThreadInternal
g_threadManager.currentThread.popEventQueue();
}
var g_wcapBundle = null;
function getWcapBundle()
{
@ -144,6 +195,17 @@ function getWcapBundle()
return g_wcapBundle;
}
function getResultCode( exc )
{
return (exc instanceof Components.interfaces.nsIException
? exc.result : exc);
}
function testResultCode( exc, rc )
{
return (getResultCode(exc) == rc);
}
function isEvent( item )
{
return (item instanceof Components.interfaces.calIEvent);
@ -151,11 +213,13 @@ function isEvent( item )
function isParent( item )
{
if (item.id != item.parentItem.id)
throw new Error("proxy has different id than its parent!");
if (item.id != item.parentItem.id) {
throw new Components.Exception(
"proxy has different id than its parent!");
}
if (item.parentItem.recurrenceId) {
throw new Error("parent has recurrenceId: " +
item.parentItem.recurrenceId);
throw new Components.Exception("parent has recurrenceId: " +
item.parentItem.recurrenceId);
}
return (!item.recurrenceId);
}
@ -260,91 +324,8 @@ function setPref(prefName, value)
prefBranch.setCharPref(prefName, value);
break;
default:
throw new Error("unsupported pref value: " + typeof(value));
throw new Components.Exception("unsupported pref value: " +
typeof(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();
// }