improved error handling, added getCalendarProperties, added item filters, fixed task complete status, more wcap error codes, revised free-busy listener

This commit is contained in:
daniel.boelzle%sun.com 2006-07-12 07:19:20 +00:00
Родитель 791743405c
Коммит 99eaaaada9
11 изменённых файлов: 562 добавлений и 364 удалений

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

@ -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

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

@ -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;
// },

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

@ -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,

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

@ -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 {

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

@ -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 )

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

@ -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()

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

@ -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;

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

@ -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")

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

@ -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. "<user>:")
* @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 <code>dtFrom</code>.

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

@ -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 =

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

@ -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,