From 8444610ee093ef455168e599505eefd73eff4e3d Mon Sep 17 00:00:00 2001 From: "daniel.boelzle%sun.com" Date: Wed, 12 Jul 2006 07:19:20 +0000 Subject: [PATCH] improved error handling, added getCalendarProperties, added item filters, fixed task complete status, more wcap error codes, revised free-busy listener git-svn-id: svn://10.0.0.236/trunk@201922 18797224-902f-48f8-a5cc-f745e15eee43 --- .../providers/wcap/calWcapCachedCalendar.js | 2 +- .../providers/wcap/calWcapCalendar.js | 294 +++++++++--------- .../providers/wcap/calWcapCalendarItems.js | 238 +++++++++----- .../providers/wcap/calWcapCalendarModule.js | 6 +- .../calendar/providers/wcap/calWcapErrors.js | 131 ++++---- .../calendar/providers/wcap/calWcapRequest.js | 111 ++++--- .../calendar/providers/wcap/calWcapSession.js | 40 ++- .../calendar/providers/wcap/calWcapUtils.js | 6 +- .../wcap/public/calIWcapCalendar.idl | 76 ++++- .../providers/wcap/public/calIWcapErrors.idl | 19 ++ .../wcap/public/calIWcapFreeBusyListener.idl | 3 + 11 files changed, 562 insertions(+), 364 deletions(-) diff --git a/mozilla/calendar/providers/wcap/calWcapCachedCalendar.js b/mozilla/calendar/providers/wcap/calWcapCachedCalendar.js index 41f7c2a7158..bb9d837e64b 100644 --- a/mozilla/calendar/providers/wcap/calWcapCachedCalendar.js +++ b/mozilla/calendar/providers/wcap/calWcapCachedCalendar.js @@ -131,7 +131,7 @@ calWcapCachedCalendar.prototype = { // xxx todo: better eoncoding? var key = this.getCalKey(); var cal = g_localCals[key]; - if (! cal) { + if (!cal) { this.log( "creating cache calendar for calId " + this.calId ); var uri; if (CACHE == "memory") { // in-memory caching diff --git a/mozilla/calendar/providers/wcap/calWcapCalendar.js b/mozilla/calendar/providers/wcap/calWcapCalendar.js index 809b1f911f4..4bae28e305c 100644 --- a/mozilla/calendar/providers/wcap/calWcapCalendar.js +++ b/mozilla/calendar/providers/wcap/calWcapCalendar.js @@ -118,18 +118,7 @@ calWcapCalendar.prototype = { logError: function( err, context ) { - var str = "error: "; - if (err instanceof Error) { - str += err.message; - } - else { - try { - str += getWcapErrorCodeString(err); - } - catch (exc) { - str += ("[" + err + "] Unknown error code."); - } - } + var str = ("error: " + errorToString(err)); Components.utils.reportError( this.log( str, context ) ); return str; }, @@ -251,44 +240,36 @@ calWcapCalendar.prototype = { }, issueRequest: - function( url, issueFunc, dataConvFunc, receiverFunc, ignoredWcapErrors ) + function( url, issueFunc, dataConvFunc, receiverFunc ) { var sessionId = this.session.getSessionId(); - if (sessionId == null) - return; // return silently, ignore error var this_ = this; issueFunc( url + ("&id=" + sessionId), - function( utf8Data ) { + function( data ) { var wcapResponse = new WcapResponse(); try { - var errno = dataConvFunc( utf8Data, wcapResponse ); - if (errno == 1) { - sessionId = this_.session.getSessionId( - sessionId /* timed-out session */ ); - if (sessionId != null) { + try { + wcapResponse.data = dataConvFunc( + data, wcapResponse ); + } + catch (exc) { + if (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_.session.getSessionId( + sessionId /* (old) timed-out session */ ); // try again: this_.issueRequest( - url, issueFunc, dataConvFunc, - receiverFunc, ignoredWcapErrors ); + url, issueFunc, dataConvFunc, receiverFunc ); return; - } // else notify error - } - else if (ignoredWcapErrors) { - for each ( var err in ignoredWcapErrors ) { - if (err == errno) { - errno = 0; // patch to OK - break; - } } + throw exc; // rethrow } - checkWcapErrno( errno ); } catch (exc) { - this_.logError( - "issueRequest(): exception occured upon response\n" + - utf8Data ); // setting the request's exception will rethrow exception // when request's data is retrieved. wcapResponse.exception = exc; @@ -297,24 +278,24 @@ calWcapCalendar.prototype = { } ); }, issueAsyncRequest: - function( url, dataConvFunc, receiverFunc, ignoredWcapErrors ) + function( url, dataConvFunc, receiverFunc ) { - this.issueRequest( url, issueAsyncUtf8Request, - dataConvFunc, receiverFunc, ignoredWcapErrors ); + this.issueRequest( + url, issueAsyncRequest, dataConvFunc, receiverFunc ); }, issueSyncRequest: - function( url, dataConvFunc, receiverFunc, ignoredWcapErrors ) + function( url, dataConvFunc, receiverFunc ) { - var ret; + var ret = null; this.issueRequest( - url, issueSyncUtf8Request, + url, issueSyncRequest, dataConvFunc, function( wcapResponse ) { - ret = wcapResponse; if (receiverFunc) { receiverFunc( wcapResponse ); } - }, ignoredWcapErrors ); + ret = wcapResponse.data; // may throw + } ); return ret; }, @@ -331,7 +312,7 @@ calWcapCalendar.prototype = { getWcapErrorString: function( rc ) { - return getWcapErrorCodeString(rc); + return wcapErrorToString(rc); }, // xxx todo: which userId is used when for offline scheduling? @@ -352,61 +333,64 @@ calWcapCalendar.prototype = { this.calId.indexOf(this.userId + ":") == 0); }, - ensureOnline: - function() - { - if (getIoService().offline) { - // Cannot perform operation, because user is offline. - // This has been taken from netwerk/base/public/nsNetError.h - // and ought to be defined in IDL. - throw ((1<<31) | ((6+0x45)<<16) | 16); - } - }, - createCalendar: function( calId, name, bAllowDoubleBooking, bSetCalProps, bAddToSubscribed ) { - this.ensureOnline(); - var url = this.getCommandUrl( "createcalendar" ); - url += ("&allowdoublebook=" + (bAllowDoubleBooking ? "1" : "0")); - url += ("&set_calprops=" + (bSetCalProps ? "1" : "0")); - url += ("&subscribe=" + (bAddToSubscribed ? "1" : "0")); - url += ("&calid=" + encodeURIComponent(calId)); - url += ("&name=" + encodeURIComponent(name)); // xxx todo: undocumented! - // xxx todo: what about categories param??? - var xml = this.issueSyncRequest( - url + "&fmt-out=text%2Fxml", utf8ToXml ).data; - return (this.userId + ":" + calId); + try { + var url = this.getCommandUrl( "createcalendar" ); + url += ("&allowdoublebook=" + (bAllowDoubleBooking ? "1" : "0")); + url += ("&set_calprops=" + (bSetCalProps ? "1" : "0")); + url += ("&subscribe=" + (bAddToSubscribed ? "1" : "0")); + url += ("&calid=" + encodeURIComponent(calId)); + // xxx todo: name undocumented! + url += ("&name=" + encodeURIComponent(name)); + // xxx todo: what about categories param??? + this.issueSyncRequest( url + "&fmt-out=text%2Fxml", stringToXml ); + return (this.userId + ":" + calId); + } + catch (exc) { + this.notifyError( exc ); + throw exc; + } }, deleteCalendar: function( calId, bRemoveFromSubscribed ) { - this.ensureOnline(); - var url = this.getCommandUrl( "deletecalendar" ); - url += ("&unsubscribe=" + (bRemoveFromSubscribed ? "1" : "0")); - url += ("&calid=" + encodeURIComponent(calId)); - this.issueSyncRequest( - url + "&fmt-out=text%2Fxml", utf8ToXml ).data; + try { + var url = this.getCommandUrl( "deletecalendar" ); + url += ("&unsubscribe=" + (bRemoveFromSubscribed ? "1" : "0")); + url += ("&calid=" + encodeURIComponent(calId)); + this.issueSyncRequest( url + "&fmt-out=text%2Fxml", stringToXml ); + } + catch (exc) { + this.notifyError( exc ); + throw exc; + } }, getCalIds: function( out_count, bGetOwnedCals ) { - this.ensureOnline(); - var url = this.getCommandUrl( - bGetOwnedCals ? "list" : "list_subscribed" ); - var ret = []; - var xml = this.issueSyncRequest( - url + "&fmt-out=text%2Fxml", utf8ToXml ).data; - var nodeList = xml.getElementsByTagName( - bGetOwnedCals ? "X-S1CS-CALPROPS-OWNED-CALENDAR" - : "X-S1CS-CALPROPS-SUBSCRIBED-CALENDAR" ); - for ( var i = 0; i < nodeList.length; ++i ) { - ret.push( nodeList.item(i).textContent ); + try { + var url = this.getCommandUrl( + bGetOwnedCals ? "list" : "list_subscribed" ); + var ret = []; + var xml = this.issueSyncRequest( + url + "&fmt-out=text%2Fxml", stringToXml ); + var nodeList = xml.getElementsByTagName( + bGetOwnedCals ? "X-S1CS-CALPROPS-OWNED-CALENDAR" + : "X-S1CS-CALPROPS-SUBSCRIBED-CALENDAR" ); + for ( var i = 0; i < nodeList.length; ++i ) { + ret.push( nodeList.item(i).textContent ); + } + out_count.value = ret.length; + return ret; + } + catch (exc) { + this.notifyError( exc ); + throw exc; } - out_count.value = ret.length; - return ret; }, getOwnedCalendars: @@ -424,18 +408,22 @@ calWcapCalendar.prototype = { modifyCalendarSubscriptions: function( calIds, bSubscribe ) { - this.ensureOnline(); - var url = this.getCommandUrl( - bSubscribe ? "subscribe_calendars" : "unsubscribe_calendars" ); - var calId = ""; - for ( var i = 0; i < calIds.length; ++i ) { - if (i > 0) - calId += ";"; - calId += encodeURIComponent(calIds[i]); + try { + var url = this.getCommandUrl( + bSubscribe ? "subscribe_calendars" : "unsubscribe_calendars" ); + var calId = ""; + for ( var i = 0; i < calIds.length; ++i ) { + if (i > 0) + calId += ";"; + calId += encodeURIComponent(calIds[i]); + } + url += ("&calid=" + calId); + this.issueSyncRequest( url + "&fmt-out=text%2Fxml", stringToXml ); + } + catch (exc) { + this.notifyError( exc ); + throw exc; } - url += ("&calid=" + calId); - var xml = this.issueSyncRequest( - url + "&fmt-out=text%2Fxml", utf8ToXml ).data; }, subscribeToCalendars: @@ -455,9 +443,7 @@ calWcapCalendar.prototype = { { try { var xml = wcapResponse.data; // first statement, may throw - // don't notify if one of ignored errors: 28, 29 - var errno = getWcapXmlErrno(xml); - if (errno == 0 && iListener != null) { + if (iListener != null) { var ret = []; var nodeList = xml.getElementsByTagName("FB"); for ( var i = 0; i < nodeList.length; ++i ) { @@ -478,6 +464,7 @@ calWcapCalendar.prototype = { ret.push( entry ); } iListener.onGetFreeBusyTimes( + Components.results.NS_OK, requestId, calId, ret.length, ret ); } if (LOG_LEVEL > 0) { @@ -486,7 +473,20 @@ calWcapCalendar.prototype = { } } catch (exc) { - this.notifyError( exc ); + const calIWcapErrors = Components.interfaces.calIWcapErrors; + switch (exc) { + case calIWcapErrors.WCAP_NO_ERRNO: // workaround + case calIWcapErrors.WCAP_ACCESS_DENIED_TO_CALENDAR: + case calIWcapErrors.WCAP_CALENDAR_DOES_NOT_EXIST: + this.log( "getFreeBusyTimes_resp() ignored: " + + errorToString(exc) ); // no error + break; + default: + this.notifyError( exc ); + break; + } + if (iListener != null) + iListener.onGetFreeBusyTimes( exc, requestId, calId, 0, [] ); } }, @@ -494,21 +494,21 @@ calWcapCalendar.prototype = { function( calId, rangeStart, rangeEnd, bBusyOnly, iListener, bAsync, requestId ) { - this.ensureOnline(); - // assure DATETIMEs: - if (rangeStart != null && rangeStart.isDate) { - rangeStart = rangeStart.clone(); - rangeStart.isDate = false; - } - if (rangeEnd != null && rangeEnd.isDate) { - rangeEnd = rangeEnd.clone(); - rangeEnd.isDate = false; - } - var zRangeStart = getIcalUTC(rangeStart); - var zRangeEnd = getIcalUTC(rangeEnd); - this.log( "getFreeBusyTimes():\n\trangeStart=" + zRangeStart + - ",\n\trangeEnd=" + zRangeEnd ); try { + // assure DATETIMEs: + if (rangeStart != null && rangeStart.isDate) { + rangeStart = rangeStart.clone(); + rangeStart.isDate = false; + } + if (rangeEnd != null && rangeEnd.isDate) { + rangeEnd = rangeEnd.clone(); + rangeEnd.isDate = false; + } + var zRangeStart = getIcalUTC(rangeStart); + var zRangeEnd = getIcalUTC(rangeEnd); + this.log( "getFreeBusyTimes():\n\trangeStart=" + zRangeStart + + ",\n\trangeEnd=" + zRangeEnd ); + var url = this.getCommandUrl( "get_freebusy" ); url += ("&calid=" + encodeURIComponent(calId)); url += ("&busyonly=" + (bBusyOnly ? "1" : "0")); @@ -521,18 +521,42 @@ calWcapCalendar.prototype = { this_.getFreeBusyTimes_resp( wcapResponse, calId, iListener, requestId ); } - if (bAsync) { - this.issueAsyncRequest( - url, utf8ToXml, resp, - [28 /* ignore ACCESS_DENIED_TO_CALENDAR */, - 29 /* ignore CALENDAR_DOES_NOT_EXIST */] ); + if (bAsync) + this.issueAsyncRequest( url, stringToXml, resp ); + else + this.issueSyncRequest( url, stringToXml, resp ); + } + catch (exc) { + this.notifyError( exc ); + if (iListener != null) + iListener.onGetFreeBusyTimes( exc, requestId, calId, 0, [] ); + throw exc; + } + }, + + m_calProps: null, + m_calPropsCalid: null, + getCalendarProperties: + function( propName, calId, out_count ) + { + try { + if (calId.length == 0) { + calId = this.calId; } - else { - this.issueSyncRequest( - url, utf8ToXml, resp, - [28 /* ignore ACCESS_DENIED_TO_CALENDAR */, - 29 /* ignore CALENDAR_DOES_NOT_EXIST */] ); + if (this.m_calPropsCalid != calId) { + var url = this.getCommandUrl( "get_calprops" ); + url += ("&calid=" + encodeURIComponent(calId)); + this.m_calProps = this.issueSyncRequest( + url + "&fmt-out=text%2Fxml", stringToXml ); + this.m_calPropsCalid = calId; } + var ret = []; + var nodeList = this.m_calProps.getElementsByTagName( propName ); + for ( var i = 0; i < nodeList.length; ++i ) { + ret.push( nodeList.item(i).textContent ); + } + out_count.value = ret.length; + return ret; } catch (exc) { this.notifyError( exc ); @@ -540,27 +564,8 @@ calWcapCalendar.prototype = { } }, - // xxx todo: opt, need to separate by calId - m_calProps: null, - getCalProp: - function( name ) - { - this.ensureOnline(); - if (! this.m_calProps) { - var url = this.getCommandUrl( "get_calprops" ); - this.m_calProps = this.issueSyncRequest( - url + "&fmt-out=text%2Fxml", utf8ToXml ).data; - } - var ret = []; - var nodeList = this.m_calProps.getElementsByTagName( name ); - for ( var i = 0; i < nodeList.length; ++i ) { - ret.push( nodeList.item(i).textContent ); - } - return ret; - }, - get defaultTimezone() { - var tzid = this.getCalProp("X-NSCP-CALPROPS-TZID"); + var tzid = this.getCalendarProperties("X-NSCP-CALPROPS-TZID", "", {}); if (tzid.length < 1) { return "UTC"; // fallback } @@ -570,7 +575,6 @@ calWcapCalendar.prototype = { // set defaultTimezone( tzid ) { // if (this.readOnly) // throw Components.interfaces.calIErrors.CAL_IS_READONLY; -// this.ensureOnline(); // // xxx todo: // throw Components.results.NS_ERROR_NOT_IMPLEMENTED; // }, diff --git a/mozilla/calendar/providers/wcap/calWcapCalendarItems.js b/mozilla/calendar/providers/wcap/calWcapCalendarItems.js index e483253b89d..09bd8cee130 100644 --- a/mozilla/calendar/providers/wcap/calWcapCalendarItems.js +++ b/mozilla/calendar/providers/wcap/calWcapCalendarItems.js @@ -39,7 +39,7 @@ // xxx todo: just to avoid registration errors, how to do better? var calWcapCalendar; -if (! calWcapCalendar) { +if (!calWcapCalendar) { calWcapCalendar = {}; calWcapCalendar.prototype = {}; } @@ -210,20 +210,22 @@ calWcapCalendar.prototype.getStoreUrl = function( item ) url += ("&priority=" + item.priority); url += "&replace=1"; // (update) don't append to any lists url += ("&icsClass="+ ((item.privacy != null && item.privacy != "") - ? item.privacy - : "PUBLIC")); - url += "&status="; - if (item.status != null) { + ? item.privacy : "PUBLIC")); + if (!bIsEvent && item.isCompleted) { + url += "&status=4"; // force to COMPLETED + } + else { switch (item.status) { - case "CONFIRMED": url += "0"; break; - case "CANCELLED": url += "1"; break; - case "TENTATIVE": url += "2"; break; - case "NEEDS-ACTION": url += "3"; break; - case "COMPLETED": url += "4"; break; - case "IN-PROCESS": url += "5"; break; - case "DRAFT": url += "6"; break; - case "FINAL": url += "7"; break; + case "CONFIRMED": url += "&status=0"; break; + case "CANCELLED": url += "&status=1"; break; + case "TENTATIVE": url += "&status=2"; break; + case "NEEDS-ACTION": url += "&status=3"; break; + case "COMPLETED": url += "&status=4"; break; + case "IN-PROCESS": url += "&status=5"; break; + case "DRAFT": url += "&status=6"; break; + case "FINAL": url += "&status=7"; break; default: + url += "&status=3"; // NEEDS-ACTION this.logError( "getStoreUrl(): unexpected item status=" + item.status ); break; @@ -322,12 +324,12 @@ calWcapCalendar.prototype.getStoreUrl = function( item ) // dtstart and due are mandatory for cs, so if those are // undefined, assume an allDay todo: dtstart = item.entryDate; - if (! dtstart) { + if (!dtstart) { dtstart = getTime(); dtstart.isDate = true; // => all day } dtend = item.dueDate; - if (! dtend) { + if (!dtend) { // xxx todo: this.logError( "getStoreUrl(): no sensible default for due date!" ); dtend = dtstart; // is due today @@ -338,10 +340,18 @@ calWcapCalendar.prototype.getStoreUrl = function( item ) // xxx todo: missing duration if (dtstart.isDate) url += "&isAllDay=1"; - url += ("&percent=" + item.percentComplete); - url += "&complete="; + if (item.isCompleted) + url += "&percent=100"; + else + url += ("&percent=" + + (item.percentComplete ? item.percentComplete : "0")); + url += "&completed="; if (item.completedDate != null) url += getIcalUTC(item.completedDate); + else if (item.isCompleted) + url += getIcalUTC(getTime()); // repair missing completedDate + else + url += "0"; // not yet completed // xxx todo: sentBy sentUID fields in cs: missing in cal api } @@ -419,11 +429,11 @@ calWcapCalendar.prototype.adoptItem_resp = function( wcapResponse, iListener ) Components.interfaces.calICalendar.ITEM_FILTER_ALL_ITEMS, 0, null, null ); if (items.length < 1) - throw new Error("no ical data!"); + throw new Error("empty VCALENDAR returned!"); if (items.length > 1) this.notifyError( "unexpected number of items: " + items.length ); item = items[0]; - + this.log( "item.id=" + item.id ); if (iListener != null) { iListener.onOperationComplete( @@ -469,7 +479,7 @@ calWcapCalendar.prototype.adoptItem = function( item, iListener ) var this_ = this; this.issueAsyncRequest( - url + "&fmt-out=text%2Fcalendar", utf8ToIcal, + url + "&fmt-out=text%2Fcalendar", stringToIcal, function( wcapResponse ) { this_.adoptItem_resp( wcapResponse, iListener ); } ); @@ -492,9 +502,9 @@ calWcapCalendar.prototype.addItem = function( item, iListener ) }; calWcapCalendar.prototype.modifyItem_resp = function( - wcapResponse, oldItem, iListener ) + wcapResponse, newItem_, oldItem, iListener ) { - var item = null; + var newItem = null; try { var icalRootComp = wcapResponse.data; // first statement, may throw @@ -504,17 +514,24 @@ calWcapCalendar.prototype.modifyItem_resp = function( 0, null, null ); if (items.length > 1) this.notifyError( "unexpected number of items: " + items.length ); - if (items.length < 1) - throw new Error("empty VCALENDAR returned!"); - item = items[0]; + if (items.length < 1) { + // however, sometimes socs just returns an empty calendar when + // nothing has changed, although fetch=1. + // This also occurs when the event organizer is in the attendees + // list and switches its PARTSTAT too often... WTF. + this.log( "empty VCALENDAR returned!" ); + newItem = newItem_; // fallback, assuming item has been written + } + else + newItem = items[0]; if (iListener != null) { iListener.onOperationComplete( this.superCalendar, Components.results.NS_OK, Components.interfaces.calIOperationListener.MODIFY, - item.id, item ); + newItem.id, newItem ); } - this.notifyObservers( "onModifyItem", [item, oldItem] ); + this.notifyObservers( "onModifyItem", [newItem, oldItem] ); // xxx todo: maybe log request status } catch (exc) { @@ -522,7 +539,7 @@ calWcapCalendar.prototype.modifyItem_resp = function( iListener.onOperationComplete( this.superCalendar, Components.results.NS_ERROR_FAILURE, Components.interfaces.calIOperationListener.MODIFY, - item == null ? null : item.id, exc ); + newItem == null ? null : newItem.id, exc ); } this.notifyError( exc ); } @@ -536,7 +553,7 @@ calWcapCalendar.prototype.modifyItem = function( throw Components.interfaces.calIErrors.CAL_IS_READONLY; try { - if (! newItem.id) + if (!newItem.id) throw new Error("new item has no id!"); var url = this.getStoreUrl( newItem ); @@ -557,9 +574,10 @@ calWcapCalendar.prototype.modifyItem = function( var this_ = this; this.issueAsyncRequest( - url + "&fmt-out=text%2Fcalendar", utf8ToIcal, + url + "&fmt-out=text%2Fcalendar", stringToIcal, function( wcapResponse ) { - this_.modifyItem_resp( wcapResponse, oldItem, iListener ); + this_.modifyItem_resp( wcapResponse, + newItem, oldItem, iListener ); } ); } catch (exc) { @@ -636,7 +654,7 @@ calWcapCalendar.prototype.deleteItem = function( item, iListener ) var this_ = this; this.issueAsyncRequest( - url + "&fmt-out=text%2Fxml", utf8ToXml, + url + "&fmt-out=text%2Fxml", stringToXml, function( wcapResponse ) { this_.deleteItem_resp( wcapResponse, item, iListener ); } ); @@ -709,7 +727,7 @@ calWcapCalendar.prototype.parseItems = function( { case Components.interfaces.calICalendar .ITEM_FILTER_COMPLETED_YES: - if (! item.isCompleted) { + if (!item.isCompleted) { delete item; item = null; } @@ -825,6 +843,71 @@ calWcapCalendar.prototype.parseItems = function( return items; }; +calWcapCalendar.prototype.getItem = function( id, iListener ) +{ + // xxx todo: test + // xxx todo: howto detect whether to call + // fetchevents_by_id ot fetchtodos_by_id? + // currently drag/drop is implemented for events only, + // try events first, fallback to todos... in the future... + this.log( ">>>>>>>>>>>>>>>> getItem() call!"); + try { + var this_ = this; + var syncResponseFunc = function( wcapResponse ) { + var icalRootComp = wcapResponse.data; // first statement, may throw + var items = this_.parseItems( + icalRootComp, + Components.interfaces.calICalendar.ITEM_FILTER_ALL_ITEMS, + 1, null, null ); + if (items.length < 1) + throw new Error("no such item!"); + if (items.length > 1) { + this_.notifyError( + "unexpected number of items: " + items.length ); + } + item = items[0]; + if (iListener != null) { + iListener.onGetResult( + this_.superCalendar, Components.results.NS_OK, + Components.interfaces.calIItemBase, + this_.log( "getItems_resp(): success." ), + items.length, items ); + iListener.onOperationComplete( + this_.superCalendar, Components.results.NS_OK, + Components.interfaces.calIOperationListener.GET, + items.length == 1 ? items[0].id : null, null ); + } + this_.log( "item delivered." ); + }; + + var params = "&compressed=1&recurring=1&fmt-out=text%2Fcalendar"; + params += ("&calid=" + encodeURIComponent(this.calId)); + params += ("&uid=" + id); + try { + // most common: event + this.issueSyncRequest( + this.getCommandUrl( "fetchevents_by_id" ) + params, + stringToIcal, syncResponseFunc ); + } + catch (exc) { + // try again, may be a task: + this.issueSyncRequest( + this.getCommandUrl( "fetchtodos_by_id" ) + params, + stringToIcal, syncResponseFunc ); + } + } + catch (exc) { + if (iListener != null) { + iListener.onOperationComplete( + this.superCalendar, Components.results.NS_ERROR_FAILURE, + Components.interfaces.calIOperationListener.GET, + null, exc ); + } + this.notifyError( exc ); + } + this.log( "getItem() returning." ); +}; + calWcapCalendar.prototype.getItems_resp = function( wcapResponse, itemFilter, maxResult, rangeStart, rangeEnd, iListener ) @@ -858,48 +941,6 @@ calWcapCalendar.prototype.getItems_resp = function( } }; -calWcapCalendar.prototype.getItem = function( id, iListener ) -{ - // xxx todo: test - // xxx todo: howto detect whether to call - // fetchevents_by_id ot fetchtodos_by_id? - // currently drag/drop is implemented for events only, - // try events first, fallback to todos... in the future... - this.log( ">>>>>>>>>>>>>>>> getItem() call!"); - try { - var this_ = this; - var respFunc = function( wcapResponse ) { - this_.getItems_resp( wcapResponse, - 0, 1, null, null, iListener ); - }; - var params = "&compressed=1&recurring=1&fmt-out=text%2Fcalendar"; - params += ("&calid=" + encodeURIComponent(this.calId)); - params += ("&uid=" + id); - try { - // most common: event - this.issueAsyncRequest( - this.getCommandUrl( "fetchevents_by_id" ) + params, - utf8ToIcal, respFunc ); - } - catch (exc) { - // try again, may be a task: - this.issueAsyncRequest( - this.getCommandUrl( "fetchtodos_by_id" ) + params, - utf8ToIcal, respFunc ); - } - } - catch (exc) { - if (iListener != null) { - iListener.onOperationComplete( - this.superCalendar, Components.results.NS_ERROR_FAILURE, - Components.interfaces.calIOperationListener.GET, - null, exc ); - } - this.notifyError( exc ); - } - this.log( "getItem() returning." ); -}; - calWcapCalendar.prototype.getItems = function( itemFilter, maxResult, rangeStart, rangeEnd, iListener ) { @@ -931,6 +972,25 @@ calWcapCalendar.prototype.getItems = function( url += "&component-type=event"; break; } + const calIWcapCalendar = Components.interfaces.calIWcapCalendar; + var compstate = ""; + if (itemFilter & calIWcapCalendar.ITEM_FILTER_REPLY_DECLINED) + compstate += ";REPLY-DECLINED"; + if (itemFilter & calIWcapCalendar.ITEM_FILTER_REPLY_ACCEPTED) + compstate += ";REPLY-ACCEPTED"; + if (itemFilter & calIWcapCalendar.ITEM_FILTER_REQUEST_COMPLETED) + compstate += ";REQUEST-COMPLETED"; + if (itemFilter & calIWcapCalendar.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_PENDING) + compstate += ";REQUEST-PENDING"; + if (itemFilter & calIWcapCalendar.ITEM_FILTER_REQUEST_WAITFORREPLY) + compstate += ";REQUEST-WAITFORREPLY"; + if (compstate.length > 0) + url += ("&compstate=" + compstate.substr(1)); + if (maxResult > 0) url += ("&maxResult=" + maxResult); // xxx todo: correctly normalized dates to zulu time? @@ -939,7 +999,7 @@ calWcapCalendar.prototype.getItems = function( var this_ = this; this.issueAsyncRequest( - url + "&fmt-out=text%2Fcalendar", utf8ToIcal, + url + "&fmt-out=text%2Fcalendar", stringToIcal, function( wcapResponse ) { this_.getItems_resp( wcapResponse, itemFilter, maxResult, @@ -953,7 +1013,12 @@ calWcapCalendar.prototype.getItems = function( Components.interfaces.calIOperationListener.GET, null, exc ); } - this.notifyError( exc ); + if (exc == Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED) { + // silently ignore login failed, no calIObserver UI: + this.log( "getItems_resp() ignored: " + errorToString(exc) ); + } + else + this.notifyError( exc ); } this.log( "getItems() returning." ); }; @@ -980,12 +1045,13 @@ SyncState.prototype = { } }, - checkAborted: function() { if (this.m_exc) throw this.m_exc; }, + checkAborted: function() { + if (this.m_exc) + throw this.m_exc; + }, get hasAborted() { return this.m_exc != null; }, - abort: - function( exc ) - { - if (! this.hasAborted) // store only first error that has occurred + abort: function( exc ) { + if (!this.hasAborted) // store only first error that has occurred this.m_exc = exc; this.m_abortFunc( exc ); } @@ -1096,9 +1162,9 @@ calWcapCalendar.prototype.syncChangesTo = function( syncState.acquire(); var url = this.getCommandUrl( "fetchcomponents_by_range" ); url += ("&compressed=1&recurring=1&calid=" + - encodeURIComponent(this.calId)); + encodeURIComponent(this.calId)); this.issueAsyncRequest( - url + "&fmt-out=text%2Fcalendar", utf8ToIcal, + url + "&fmt-out=text%2Fcalendar", stringToIcal, function( wcapResponse ) { this_.syncChangesTo_resp( wcapResponse, syncState, iListener, @@ -1122,7 +1188,7 @@ calWcapCalendar.prototype.syncChangesTo = function( syncState.acquire(); this.issueAsyncRequest( this.getCommandUrl( "fetchcomponents_by_lastmod" ) + params, - utf8ToIcal, + stringToIcal, function( wcapResponse ) { this_.syncChangesTo_resp( wcapResponse, syncState, iListener, @@ -1151,7 +1217,7 @@ calWcapCalendar.prototype.syncChangesTo = function( syncState.acquire(); this.issueAsyncRequest( this.getCommandUrl( "fetch_deletedcomponents" ) + params, - utf8ToIcal, + stringToIcal, function( wcapResponse ) { this_.syncChangesTo_resp( wcapResponse, syncState, iListener, diff --git a/mozilla/calendar/providers/wcap/calWcapCalendarModule.js b/mozilla/calendar/providers/wcap/calWcapCalendarModule.js index c40b9635c19..60f9d2ac195 100644 --- a/mozilla/calendar/providers/wcap/calWcapCalendarModule.js +++ b/mozilla/calendar/providers/wcap/calWcapCalendarModule.js @@ -61,7 +61,7 @@ var calWcapCalendarModule = { getClassObject: function( compMgr, cid, iid ) { - if (! this.m_scriptsLoaded) { + if (!this.m_scriptsLoaded) { this.m_scriptsLoaded = true; // load scripts: const scripts = [ "calWcapUtils.js", "calWcapErrors.js", @@ -83,9 +83,9 @@ var calWcapCalendarModule = { init(); // init first time } - if (! cid.equals( calWcapCalendar.prototype.classID )) + if (!cid.equals( calWcapCalendar.prototype.classID )) throw Components.results.NS_ERROR_NO_INTERFACE; - if (! iid.equals( Components.interfaces.nsIFactory )) + if (!iid.equals( Components.interfaces.nsIFactory )) throw Components.results.NS_ERROR_NOT_IMPLEMENTED; return { diff --git a/mozilla/calendar/providers/wcap/calWcapErrors.js b/mozilla/calendar/providers/wcap/calWcapErrors.js index 585da1a5490..d584003c97c 100644 --- a/mozilla/calendar/providers/wcap/calWcapErrors.js +++ b/mozilla/calendar/providers/wcap/calWcapErrors.js @@ -37,6 +37,11 @@ * * ***** END LICENSE BLOCK ***** */ +// Cannot perform operation, because user is offline. +// This has been taken 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); + // // WCAP error handling helpers // @@ -44,7 +49,7 @@ const g_wcapErrorCodes = [ /* -1 */ Components.results.NS_OK, "Logout successful.", /* 0 */ Components.results.NS_OK, "Command successful.", - /* 1 */ Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED, "Login failed, session ID timed out. Invalid session ID.", + /* 1 */ Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED, "Login failed. Invalid session ID.", /* 2 */ Components.interfaces.calIWcapErrors.WCAP_LOGIN_OK_DEFAULT_CALENDAR_NOT_FOUND, "login.wcap was successful, but the default calendar for this user was not found. A new default calendar set to the userid was created.", /* 3 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", /* 4 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", @@ -125,12 +130,20 @@ const g_wcapErrorCodes = [ /* 79 */ Components.interfaces.calIWcapErrors.WCAP_ATTENDEE_NOT_ALLOWED_TO_REQUEST_ON_MODIFY, "Attendee is not allowed to modify an event with method=request.", /* 80 */ Components.interfaces.calIWcapErrors.WCAP_TRANSP_RESOURCE_NOT_ALLOWED, "Resources do not permit the transparency parameter.", /* 81 */ Components.interfaces.calIWcapErrors.WCAP_RECURRING_COMPONENT_NOT_FOUND, "Recurring component not found. Only happens when recurring=1 is passed in by fetch commands. This code is returned if part of the recurring series (either the master or an exception) is missing.", - /* 82 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", - /* 83 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", - /* 84 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", - /* 85 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", - /* 86 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", - /* 87 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", + /* new by WCAP 4.0: */ + /* 82 */ Components.interfaces.calIWcapErrors.WCAP_BAD_MIME_TYPE, + "The mime headers supplied while storing the attachment using storeevents.wcap/storetodos.wcap is malformatted.", + /* 83 */ Components.interfaces.calIWcapErrors.WCAP_MISSING_BOUNDARY, + "While supplying attachments to the storeveents/storetodos commands the mime boundary was not found.", + /* 84 */ Components.interfaces.calIWcapErrors.WCAP_INVALID_ATTACHMENT, + "The attachment supplied to be stored on the server is malformatted.", + /* 85 */ Components.interfaces.calIWcapErrors.WCAP_ATTACH_DELETE_SUCCESS, + "All the attachments requested to be deleted from the server by supplying deleteattach were deleted successsfully.", + /* 86 */ Components.interfaces.calIWcapErrors.WCAP_ATTACH_DELETE_PARTIAL, + "Of All attachments requested to be deleted from the server by supplying deleteattach , only few were deleted successfully.", + /* 87 */ Components.interfaces.calIWcapErrors.WCAP_ATTACHMENT_NOT_FOUND, + "The attachent requested to be fetched or deleted from the server was not found.", + /* / new by WCAP 4.0 */ /* 88 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", /* 89 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", /* 90 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.", @@ -154,7 +167,47 @@ const g_wcapErrorCodes = [ /* 11008 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_CHECKVERSION_FAILED, "DWP version check failed." ]; -function getWcapErrorIndex( errno ) +function wcapErrorToString( rc ) +{ + if (rc == Components.interfaces.calIWcapErrors.WCAP_NO_ERRNO) + return "No WCAP errno (missing X-NSCP-WCAP-ERRNO)."; + + var index = (rc - Components.interfaces.calIWcapErrors.WCAP_ERROR_BASE + 1); + if (index >= 1 && index <= 108 && + g_wcapErrorCodes[index * 2] != Components.results.NS_ERROR_INVALID_ARG) + { + return g_wcapErrorCodes[(index * 2) + 1]; + } + throw Components.results.NS_ERROR_INVALID_ARG; +} + +function errorToString( 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 code."); + } + } +} + +function getWcapErrorCode( errno ) { var index = -1; if (errno >= -1 && errno <= 81) @@ -164,72 +217,38 @@ function getWcapErrorIndex( errno ) if (index >= 0 && g_wcapErrorCodes[index * 2] != Components.results.NS_ERROR_INVALID_ARG) { - return index; + return g_wcapErrorCodes[index * 2]; } - else - throw Components.results.NS_ERROR_INVALID_ARG; -} - -function getWcapErrorIndexByErrorCode( rc ) -{ - var index = (rc - Components.interfaces.calIWcapErrors.WCAP_ERROR_BASE + 1); - if (index >= 1 && index <= 108 && - g_wcapErrorCodes[index * 2] != Components.results.NS_ERROR_INVALID_ARG) - { - return index; - } - else - throw Components.results.NS_ERROR_INVALID_ARG; -} - -function getWcapErrorCodeString( rc ) -{ - return g_wcapErrorCodes[(getWcapErrorIndexByErrorCode(rc) * 2) + 1]; -} - -function getWcapErrorCode( errno ) -{ - return g_wcapErrorCodes[getWcapErrorIndex(errno) * 2]; + throw Components.results.NS_ERROR_INVALID_ARG; } function getWcapXmlErrno( xml ) { - if (xml == undefined) - throw new Error("no XML!"); - var item = xml.getElementsByTagName("X-NSCP-WCAP-ERRNO").item(0); - if (item) - return parseInt(item.textContent); - else { - // xxx todo: throw new Eror("missing element X-NSCP-WCAP-ERRNO!"); - // cs currently may forget to send X-NSCP-WCAP-ERRNO on - // some commands, maybe fixed in later versions. WTF. - return 0; + var elem = xml.getElementsByTagName( "X-NSCP-WCAP-ERRNO" ); + if (elem) { + elem = elem.item(0); + if (elem) + return parseInt(elem.textContent); } + // some commands just respond with an empty calendar, no errno. WTF. + throw Components.interfaces.calIWcapErrors.WCAP_NO_ERRNO; } function getWcapIcalErrno( icalRootComp ) { - if (icalRootComp == undefined) - throw new Error("no VCALENDAR root component!"); var prop = icalRootComp.getFirstProperty( "X-NSCP-WCAP-ERRNO" ); if (prop) return parseInt(prop.value); - else { - // xxx todo: throw new Eror("missing element X-NSCP-WCAP-ERRNO!"); - // cs currently may forget to send X-NSCP-WCAP-ERRNO on - // some commands, maybe fixed in later versions. WTF. - return 0; - } + // some commands just respond with an empty calendar, no errno. WTF. + throw Components.interfaces.calIWcapErrors.WCAP_NO_ERRNO; } function checkWcapErrno( errno, expectedErrno ) { - if (expectedErrno == undefined) { - expectedErrno = 0; - } - if (errno != expectedErrno) { + if (expectedErrno == undefined) + expectedErrno = 0; // i.e. Command successful. + if (errno != expectedErrno) throw getWcapErrorCode(errno); - } } function checkWcapXmlErrno( xml, expectedErrno ) diff --git a/mozilla/calendar/providers/wcap/calWcapRequest.js b/mozilla/calendar/providers/wcap/calWcapRequest.js index 9f0cc215a1a..9202e38ef49 100644 --- a/mozilla/calendar/providers/wcap/calWcapRequest.js +++ b/mozilla/calendar/providers/wcap/calWcapRequest.js @@ -73,80 +73,95 @@ WcapResponse.prototype = { } }; -function utf8ToIcal( utf8Data, wcapResponse ) +function stringToIcal( data ) { - if (!utf8Data || utf8Data == "") - return 1; // assuming session timeout - var icalRootComp = getIcsService().parseICS( utf8Data ); - wcapResponse.data = icalRootComp; - return getWcapIcalErrno( icalRootComp ); + if (!data || data == "") // assuming time-out + throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED; + var icalRootComp = getIcsService().parseICS( data ); + checkWcapIcalErrno( icalRootComp ); + return icalRootComp; } -function utf8ToXml( utf8Data, wcapResponse ) +function stringToXml( data ) { - if (!utf8Data || utf8Data == "") - return 1; // assuming session timeout - var xml = getDomParser().parseFromString( utf8Data, "text/xml"); - wcapResponse.data = xml; - return getWcapXmlErrno( xml ); + if (!data || data == "") // assuming time-out + throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED; + var xml = getDomParser().parseFromString( data, "text/xml" ); + checkWcapXmlErrno( xml ); + return xml; } -function Utf8Reader( url, receiverFunc ) { +function UnicharReader( receiverFunc ) { this.wrappedJSObject = this; - this.m_url = url; this.m_receiverFunc = receiverFunc; } -Utf8Reader.prototype = { - m_url: null, +UnicharReader.prototype = { m_receiverFunc: null, // nsIUnicharStreamLoaderObserver: onDetermineCharset: function( loader, context, firstSegment, length ) { - return "UTF-8"; + var charset = loader.channel.contentCharset; + if (!charset || charset == "") + charset = "UTF-8"; + return charset; }, onStreamComplete: function( loader, context, status, /* nsIUnicharInputStream */ unicharData ) { if (status == Components.results.NS_OK) { + if (LOG_LEVEL > 2) { + logMessage( "issueAsyncRequest( \"" + + loader.channel.URI.spec + "\" )", + "received stream." ); + } var str = ""; - var str_ = {}; - while (unicharData.readString( -1, str_ )) { - str += str_.value; + if (unicharData) { + var str_ = {}; + while (unicharData.readString( -1, str_ )) { + str += str_.value; + } } if (LOG_LEVEL > 1) { - logMessage( "issueAsyncUtf8Request( \"" + this.m_url + "\" )", - "request result: " + str ); + logMessage( "issueAsyncRequest( \"" + + loader.channel.URI.spec + "\" )", + "contentCharset = " + loader.channel.contentCharset+ + "\nrequest result:\n" + str ); } this.m_receiverFunc( str ); } } }; -function issueAsyncUtf8Request( url, receiverFunc ) +function issueAsyncRequest( url, receiverFunc ) { var reader = null; if (receiverFunc != null) { - reader = new Utf8Reader( url, receiverFunc ); + reader = new UnicharReader( receiverFunc ); } var loader = Components.classes["@mozilla.org/network/unichar-stream-loader;1"] .createInstance(Components.interfaces.nsIUnicharStreamLoader); - logMessage( "issueAsyncUtf8Request( \"" + url + "\" )", "opening channel."); + logMessage( "issueAsyncRequest( \"" + url + "\" )", "opening channel." ); var channel = getIoService().newChannel( - url, "UTF-8" /* charset */, null /* baseURI */ ); + url, "" /* charset */, null /* baseURI */ ); loader.init( channel, reader, null /* context */, 0 /* segment size */ ); } -function streamToUtf8String( inStream ) +function streamToString( inStream, charset ) { - // byte-array to utf8 string: + if (LOG_LEVEL > 2) { + logMessage( "streamToString()", + "inStream.available() = " + inStream.available() + + ", charset = " + charset ); + } + // byte-array to string: var convStream = Components.classes["@mozilla.org/intl/converter-input-stream;1"] .createInstance(Components.interfaces.nsIConverterInputStream); - convStream.init( inStream, "UTF-8", 0, 0x0000 ); + convStream.init( inStream, charset, 0, 0x0000 ); var str = ""; var str_ = {}; while (convStream.readString( -1, str_ )) { @@ -155,47 +170,53 @@ function streamToUtf8String( inStream ) return str; } -function issueSyncUtf8Request( url, receiverFunc, bLogging ) +function issueSyncRequest( url, receiverFunc, bLogging ) { if (bLogging == undefined) bLogging = true; if (bLogging && LOG_LEVEL > 0) { - logMessage( "issueSyncUtf8Request( \"" + url + "\" )", + logMessage( "issueSyncRequest( \"" + url + "\" )", "opening channel." ); } var channel = getIoService().newChannel( - url, "UTF-8" /* charset */, null /* baseURI */ ); + url, "" /* charset */, null /* baseURI */ ); 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 str = streamToUtf8String( stream ); + var charset = channel.contentCharset; + if (!charset || charset == "") + charset = "UTF-8"; + var str = streamToString( stream, charset ); if (bLogging && LOG_LEVEL > 1) { - logMessage( "issueSyncUtf8Request( \"" + url + "\" )", + logMessage( "issueSyncRequest( \"" + url + "\" )", "returned: " + str ); } - if (receiverFunc != null) { + if (receiverFunc) { receiverFunc( str ); } return str; } else if (bLogging && LOG_LEVEL > 0) { - logMessage( "issueSyncUtf8Request( \"" + url + "\" )", + logMessage( "issueSyncRequest( \"" + url + "\" )", "failed: " + status ); } - return null; + throw status; } function issueSyncXMLRequest( url, receiverFunc, bLogging ) { - var str = issueSyncUtf8Request( url, null, bLogging ); - if (str != null) { - var xml = getDomParser().parseFromString( str, "text/xml" ); - if (receiverFunc != null) { - receiverFunc( xml ); - } - return xml; + var str = issueSyncRequest( url, null, bLogging ); + var xml = getDomParser().parseFromString( str, "text/xml" ); + if (receiverFunc) { + receiverFunc( xml ); } - return null; + return xml; } // response object for Calendar.issueRequest() diff --git a/mozilla/calendar/providers/wcap/calWcapSession.js b/mozilla/calendar/providers/wcap/calWcapSession.js index 8c1e0013a05..c504bb781d9 100644 --- a/mozilla/calendar/providers/wcap/calWcapSession.js +++ b/mozilla/calendar/providers/wcap/calWcapSession.js @@ -137,12 +137,10 @@ calWcapSession.prototype = { var url = this.uri.spec + "get_all_timezones.wcap?appid=mozilla-lightning" + "&fmt-out=text%2Fcalendar&id=" + this.m_sessionId; - var str = issueSyncUtf8Request( url ); - if (str == null) - throw new Error("request failed!"); + var str = issueSyncRequest( url ); var icalRootComp = getIcsService().parseICS( str ); if (icalRootComp == null) - throw new Error("invalid data!"); + throw new Error("invalid data, expected ical!"); checkWcapIcalErrno( icalRootComp ); var tzids = []; var this_ = this; @@ -186,12 +184,10 @@ calWcapSession.prototype = { "&fmt-out=text%2Fcalendar&id=" + this.m_sessionId; // xxx todo: this is no solution! var localTime = getTime(); - var str = issueSyncUtf8Request( url ); - if (str == null) - throw new Error("request failed!"); + var str = issueSyncRequest( url ); var icalRootComp = getIcsService().parseICS( str ); if (icalRootComp == null) - throw new Error("invalid data!"); + throw new Error("invalid data, expected ical!"); checkWcapIcalErrno( icalRootComp ); var serverTime = getDatetimeFromIcalProp( icalRootComp.getFirstProperty( "X-NSCP-WCAPTIME" ) ); @@ -228,11 +224,11 @@ calWcapSession.prototype = { { if (this.m_bNoLoginsAnymore) { this.log( "login has failed, no logins anymore for this user." ); - return null; + throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED; } if (getIoService().offline) { this.log( "in offline mode." ); - return null; + throw NS_ERROR_OFFLINE; } if (this.m_sessionId == null || this.m_sessionId == timedOutSessionId) { @@ -257,7 +253,7 @@ calWcapSession.prototype = { this.log( "session timeout; prompting to reconnect." ); var prompt = getWindowWatcher().getNewPrompter(null); var bundle = getBundle(); - if (! prompt.confirm( + if (!prompt.confirm( bundle.GetStringFromName( "reconnectConfirmation.label" ), bundle.formatStringFromName( @@ -266,7 +262,7 @@ calWcapSession.prototype = { this.m_bNoLoginsAnymore = true; } } - if (! this.m_bNoLoginsAnymore) + if (!this.m_bNoLoginsAnymore) this.getSessionId_(); this.getSupportedTimezones( true /* refresh */ ); @@ -279,6 +275,9 @@ calWcapSession.prototype = { } eventQueueService.popThreadEventQueue( eventQueue ); } + if (this.m_sessionId == null) { + throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED; + } return this.m_sessionId; }, getSessionId_: @@ -319,7 +318,7 @@ calWcapSession.prototype = { else { // user has specified a specific port, but no https: // => leave it to her whether to connect... - if (! confirmUnsecureLogin( loginUri )) { + if (!confirmUnsecureLogin( loginUri )) { this.m_bNoLoginsAnymore = true; this.log( "user rejected unsecure login." ); return null; @@ -450,13 +449,11 @@ calWcapSession.prototype = { try { // currently, xml parsing at an early stage during process startup // does not work reliably, so use libical parsing for now: - var str = issueSyncUtf8Request( + var str = issueSyncRequest( uri.spec + "version.wcap?fmt-out=text%2Fcalendar" ); - if (str == null) - throw new Error("request failed!"); var icalRootComp = getIcsService().parseICS( str ); if (icalRootComp == null) - throw new Error("invalid data!"); + throw new Error("invalid data, expected ical!"); var prop = icalRootComp.getFirstProperty( "PRODID" ); if (prop == null) throw new Error("missing PRODID!"); @@ -507,12 +504,10 @@ calWcapSession.prototype = { } // currently, xml parsing at an early stage during process startup // does not work reliably, so use libical parsing for now: - var str = issueSyncUtf8Request( + var str = issueSyncRequest( loginUri.spec + "login.wcap?fmt-out=text%2Fcalendar&user=" + encodeURIComponent(user) + "&password=" + encodeURIComponent(pw), null /* receiverFunc */, false /* no logging */ ); - if (str == null) - throw new Error("request failed!"); var icalRootComp = getIcsService().parseICS( str ); checkWcapIcalErrno( icalRootComp ); var prop = icalRootComp.getFirstProperty( "X-NSCP-WCAP-SESSION-ID" ); @@ -540,7 +535,8 @@ calWcapSession.prototype = { var url = (this.uri.spec + "logout.wcap?fmt-out=text%2Fxml&id=" + this.m_sessionId); try { - checkWcapXmlErrno( issueSyncXMLRequest(url), -1 ); + checkWcapXmlErrno( issueSyncXMLRequest(url), + -1 /* logout successfull */ ); this.log( "WCAP logout succeeded." ); } catch (exc) { @@ -583,7 +579,7 @@ g_sessions = {}; function getSession( uri ) { var session = g_sessions[uri.spec]; - if (! session) { + if (!session) { logMessage( "getSession()", "entering session for uri=" + uri.spec ); var session = new calWcapSession( uri ); g_sessions[uri.spec] = session; diff --git a/mozilla/calendar/providers/wcap/calWcapUtils.js b/mozilla/calendar/providers/wcap/calWcapUtils.js index 01713390476..8851a2f41f7 100644 --- a/mozilla/calendar/providers/wcap/calWcapUtils.js +++ b/mozilla/calendar/providers/wcap/calWcapUtils.js @@ -178,7 +178,7 @@ function init() } CACHE_DIR = cacheDir; logMessage( "calendar.wcap.cache_dir", CACHE_DIR.path ); - if (! CACHE_DIR.exists()) { + if (!CACHE_DIR.exists()) { CACHE_DIR.create( Components.interfaces.nsIFile.DIRECTORY_TYPE, 0700 /* read, write, execute/search by owner */ ); @@ -308,7 +308,7 @@ function getTime() function getIcalUTC( dt ) { - if (! dt) + if (!dt) return "0"; else { var dtz = dt.timezone; @@ -321,7 +321,7 @@ function getIcalUTC( dt ) function getDatetimeFromIcalProp( prop ) { - if (! prop) + if (!prop) return null; var val = prop.valueAsIcalString; if (val.length == 0 || val == "0") diff --git a/mozilla/calendar/providers/wcap/public/calIWcapCalendar.idl b/mozilla/calendar/providers/wcap/public/calIWcapCalendar.idl index 97f35f0bb94..1e8a8972c7d 100644 --- a/mozilla/calendar/providers/wcap/public/calIWcapCalendar.idl +++ b/mozilla/calendar/providers/wcap/public/calIWcapCalendar.idl @@ -66,18 +66,34 @@ interface calIWcapCalendar : calICalendar * Gets or sets this calendar's (calId) default timezone. */ readonly attribute string defaultTimezone; + + /** + * Gets calendar properties for specified calId. + * An error is notified to all registered calIObservers, then thrown. + * + * @param propName property name (e.g. X-S1CS-CALPROPS-COMMON-NAME) + * @param calId a calid, "mailto:rfc822addr" or + * empty string (=> current user's calId) + * @return array of property values + */ + void getCalendarProperties( + in string propName, + in string calId, + out unsigned long count, + [array, size_is(count), retval] out string properties ); /** * Gets a text for an error code. * * @param rc error code defined in calIWcapErrors * @return error string - * @exception Components.results.NS_ERROR_INVALID_ARG + * @exception NS_ERROR_INVALID_ARG */ string getWcapErrorString( in unsigned long rc ); /** * Creates a new calendar for user. + * An error is notified to all registered calIObservers, then thrown. * * @param calId calendar's calId (portion); * without user's id, e.g. "test-cal". @@ -106,6 +122,7 @@ interface calIWcapCalendar : calICalendar /** * Deletes a calendar. + * An error is notified to all registered calIObservers, then thrown. * * @param calId full calId (incl. ":") * @param bRemoveFromSubscribed whether calendar ought to be removed @@ -117,6 +134,7 @@ interface calIWcapCalendar : calICalendar /** * Gets own calendars. + * An error is notified to all registered calIObservers, then thrown. * * @return owned calendars (string array of "calId1$Description1", ...) */ @@ -126,6 +144,7 @@ interface calIWcapCalendar : calICalendar /** * Gets subscribed calendars. + * An error is notified to all registered calIObservers, then thrown. * * @return subscribed calendars (string array of "calId1$Description1",...) */ @@ -135,6 +154,7 @@ interface calIWcapCalendar : calICalendar /** * Subscribe to calendar(s). + * An error is notified to all registered calIObservers, then thrown. * * @param count number of calIds * @param calIds array of calIds (calid or "mailto:rfc822addr") @@ -145,6 +165,7 @@ interface calIWcapCalendar : calICalendar /** * Unsubscribe from calendar(s). + * An error is notified to all registered calIObservers, then thrown. * * @param count number of calIds * @param calIds array of calIds (calid or "mailto:rfc822addr") @@ -156,8 +177,10 @@ interface calIWcapCalendar : calICalendar /** * Gets free-busy entries for calid. * Results are notifies to passed listener instance. - * Errors are always notified to all registered calIObservers, - * and rethrown in calling thread (only). + * An error is notified to all registered calIObservers and + * to calIWcapFreeBusyListener::onGetFreeBusyTimes with rc != NS_OK. + * Additionally, when an error occurs within getFreeBusyTimes, + * the error is also thrown. * * @param calId a calid or "mailto:rfc822addr" * @param dtRangeStart start time of free-busy search @@ -179,6 +202,53 @@ interface calIWcapCalendar : calICalendar /** xxx todo: to be moved to calIOperationListener? */ const unsigned long SYNC = 5; + + /* xxx todo: additional filters sensible for calICalendar, too? + claiming bits 24-30 for now. + */ + /** + * Scope: Attendee + * The event or todo is an invitation from another + * user and the current user has declined the invitation. + */ + const unsigned long ITEM_FILTER_REPLY_DECLINED = 1 << 24; + /** + * Scope: Attendee + * The event or todo is an invitation from another + * user and the current user has accepted the invitation. + */ + const unsigned long ITEM_FILTER_REPLY_ACCEPTED = 1 << 25; + /** + * Scope: Organizer + * The event or todo is an invitation from the current + * user to other invitees, and all invitees have replied. + */ + 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 is not required to reply. + */ + const unsigned long ITEM_FILTER_REQUEST_NEEDSNOACTION = 1 << 28; + /** + * Scope: Organizer + * The event or todo is an invitation from the current + * user to other invitees, and is currently in the + * process of sending out invitations. + */ + const unsigned long ITEM_FILTER_REQUEST_PENDING = 1 << 29; + /** + * Scope: Organizer + * The event or todo is an invitation from the current + * user to other invitees, and is currently awaiting. + */ + const unsigned long ITEM_FILTER_REQUEST_WAITFORREPLY = 1 << 30; /** * Syncs in changes since time dtFrom. diff --git a/mozilla/calendar/providers/wcap/public/calIWcapErrors.idl b/mozilla/calendar/providers/wcap/public/calIWcapErrors.idl index 22239af6ace..b1643a177bd 100644 --- a/mozilla/calendar/providers/wcap/public/calIWcapErrors.idl +++ b/mozilla/calendar/providers/wcap/public/calIWcapErrors.idl @@ -44,6 +44,9 @@ [scriptable, uuid(2ADC008C-A7A6-4f9a-91C8-A99742B68F3D)] interface calIWcapErrors : calIErrors { + const unsigned long WCAP_NO_ERRNO = WCAP_ERROR_BASE + 0; + + /* errno: */ /* 1 */ const unsigned long WCAP_LOGIN_FAILED = WCAP_ERROR_BASE + 1; /* 2 */ const unsigned long WCAP_LOGIN_OK_DEFAULT_CALENDAR_NOT_FOUND = @@ -198,6 +201,22 @@ interface calIWcapErrors : calIErrors WCAP_ERROR_BASE + 80; /* 81 */ const unsigned long WCAP_RECURRING_COMPONENT_NOT_FOUND = WCAP_ERROR_BASE + 81; + + /* new by WCAP 4.0: */ + /* 82 */ const unsigned long WCAP_BAD_MIME_TYPE = + WCAP_ERROR_BASE + 82; + /* 83 */ const unsigned long WCAP_MISSING_BOUNDARY = + WCAP_ERROR_BASE + 83; + /* 84 */ const unsigned long WCAP_INVALID_ATTACHMENT = + WCAP_ERROR_BASE + 84; + /* 85 */ const unsigned long WCAP_ATTACH_DELETE_SUCCESS = + WCAP_ERROR_BASE + 85; + /* 86 */ const unsigned long WCAP_ATTACH_DELETE_PARTIAL = + WCAP_ERROR_BASE + 86; + /* 87 */ const unsigned long WCAP_ATTACHMENT_NOT_FOUND = + WCAP_ERROR_BASE + 87; + /* / new by WCAP 4.0 */ + /* 11000 */ const unsigned long WCAP_CDWP_ERR_MAX_CONNECTION_REACHED = WCAP_ERROR_BASE + 100; /* 11001 */ const unsigned long WCAP_CDWP_ERR_CANNOT_CONNECT = diff --git a/mozilla/calendar/providers/wcap/public/calIWcapFreeBusyListener.idl b/mozilla/calendar/providers/wcap/public/calIWcapFreeBusyListener.idl index b2836bd141c..3136d717b04 100644 --- a/mozilla/calendar/providers/wcap/public/calIWcapFreeBusyListener.idl +++ b/mozilla/calendar/providers/wcap/public/calIWcapFreeBusyListener.idl @@ -45,12 +45,15 @@ interface calIWcapFreeBusyListener : nsISupports /** * Callback receiving free-busy entries. * + * @param rc result code, + * e.g. NS_OK or calIWcapErrors.WCAP_CALENDAR_DOES_NOT_EXIST * @param requestId request id to distinguish asynchronous requests * @param calId a calid or "mailto:rfc822addr" * @param count number of free-busy entries * @param entries free-busy entries */ void onGetFreeBusyTimes( + in nsresult rc, in unsigned long requestId, in string calId, in unsigned long count,