Bug 340949, revised/more IDL, separated session from calendar instances

This commit is contained in:
daniel.boelzle%sun.com 2006-07-24 14:44:03 +00:00
parent 0e74500a29
commit a96ab64df4
10 changed files with 879 additions and 606 deletions

View File

@ -37,9 +37,10 @@
*
* ***** END LICENSE BLOCK ***** */
function calWcapCalendar() {
function calWcapCalendar( calId, session ) {
this.wrappedJSObject = this;
this.m_observers = [];
this.m_calId = calId;
this.m_session = session;
}
calWcapCalendar.prototype = {
m_ifaces: [ Components.interfaces.calIWcapCalendar,
@ -99,15 +100,9 @@ calWcapCalendar.prototype = {
toString:
function()
{
var str;
if (this.m_session == null) {
str = "no session";
}
else {
str = this.session.toString();
if (this.m_calId != null && this.m_calId != this.userId)
str += (", calId=" + this.m_calId);
}
var str = this.session.toString();
if (this.calId != this.session.userId)
str += (", calId=" + this.calId);
return str;
},
log:
@ -149,65 +144,31 @@ calWcapCalendar.prototype = {
get readOnly() { return (this.m_bReadOnly || !this.isOwnedCalendar); },
set readOnly( bReadOnly ) { this.m_bReadOnly = bReadOnly; },
m_uri: null,
get uri() { return this.m_uri },
set uri( thatUri )
{
if (this.m_uri == null || thatUri == null ||
!this.m_uri.equals(thatUri))
{
if (this.m_session != null) {
this.m_session.logout();
this.m_session = null;
}
this.m_uri = null;
this.m_calId = null;
if (thatUri != null) {
this.m_uri = thatUri.clone();
this.m_calId = decodeURIComponent( thatUri.username );
if (this.m_calId == "") {
this.m_calId = null;
}
}
this.refresh();
}
// xxx todo: will potentially vanish from calICalendar:
get uri() { return this.session.uri; },
set uri( thatUri ) {
this.session.uri = thatUri;
this.m_calProps = null;
},
m_observers: null,
notifyObservers:
function( func, args )
{
this.m_observers.forEach(
function( obj ) {
try {
obj[func].apply( obj, args );
}
catch (exc) {
// don't call notifyError() here:
Components.utils.reportError( exc );
}
} );
function( func, args ) {
this.session.notifyObservers( func, args );
},
addObserver:
function( observer )
{
if (this.m_observers.indexOf( observer ) == -1) {
this.m_observers.push( observer );
}
function( observer ) {
this.session.addObserver( observer );
},
removeObserver:
function( observer )
{
this.m_observers = this.m_observers.filter(
function(x) { return x != observer; } );
function( observer ) {
this.session.removeObserver( observer );
},
// xxx todo: batch currently not used
startBatch: function() { this.notifyObservers( "onStartBatch", [] ); },
endBatch: function() { this.notifyObservers( "onEndBatch", [] ); },
// xxx todo: rework like in
// https://bugzilla.mozilla.org/show_bug.cgi?id=257428
m_bSuppressAlarms: true /* xxx todo:
off for now until all problems are solved */,
get suppressAlarms() {
@ -218,345 +179,85 @@ calWcapCalendar.prototype = {
},
get canRefresh() { return false; },
refresh:
function()
{
refresh: function() {
// no-op
this.log("refresh()");
},
getCommandUrl:
function( wcapCommand )
{
if (this.uri == null)
throw new Error("no URI!");
var session = this.session;
// ensure established session, so userId is set;
// (calId defaults to userId) if not set:
session.getSessionId();
return (session.uri.spec + wcapCommand +
".wcap?appid=mozilla-lightning");
},
issueRequest:
function( url, issueFunc, dataConvFunc, receiverFunc )
{
var sessionId = this.session.getSessionId();
var this_ = this;
issueFunc(
url + ("&id=" + sessionId),
function( data ) {
var wcapResponse = new WcapResponse();
try {
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 );
return;
}
throw exc; // rethrow
}
}
catch (exc) {
// setting the request's exception will rethrow exception
// when request's data is retrieved.
wcapResponse.exception = exc;
}
receiverFunc( wcapResponse );
} );
},
issueAsyncRequest:
function( url, dataConvFunc, receiverFunc )
{
this.issueRequest(
url, issueAsyncRequest, dataConvFunc, receiverFunc );
},
issueSyncRequest:
function( url, dataConvFunc, receiverFunc )
{
var ret = null;
this.issueRequest(
url, issueSyncRequest,
dataConvFunc,
function( wcapResponse ) {
if (receiverFunc) {
receiverFunc( wcapResponse );
}
ret = wcapResponse.data; // may throw
} );
return ret;
},
m_session: null,
get session() {
if (this.m_session == null) {
this.m_session = getSession( this.uri );
}
return this.m_session;
},
// calIWcapCalendar:
getWcapErrorString:
function( rc )
{
return wcapErrorToString(rc);
},
m_session: null,
get session() { return this.m_session; },
// xxx todo: which userId is used when for offline scheduling?
// if not logged in, no calId/userId is known... => UI
m_calId: null,
get calId() {
var userId = this.userId; // assure being logged in
var userId = this.session.userId; // assure being logged in
return this.m_calId || userId;
},
// xxx todo: for now to make subscriptions context menu work,
// will vanish when UI has been revised and every subscribed
// calendar has its own calICalendar object...
// poking calId, so default calendar will then behave
// like a subscribed one...
set calId( id ) {
this.log( "setting calId to " + id );
this.m_calId = id;
},
get userId() { return this.session.userId; },
get description() {
var ar = this.getCalendarProperties("X-NSCP-CALPROPS-DESCRIPTION", {});
if (ar.length < 1) {
return this.calId; // fallback
}
return ar[0];
},
get isOwnedCalendar() {
return (this.calId == this.userId ||
this.calId.indexOf(this.userId + ":") == 0);
},
createCalendar:
function( calId, name, bAllowDoubleBooking, bSetCalProps, bAddToSubscribed )
{
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 )
{
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 )
{
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;
}
},
getOwnedCalendars:
function( out_count )
{
return this.getCalIds( out_count, true );
},
getSubscribedCalendars:
function( out_count )
{
return this.getCalIds( out_count, false );
},
modifyCalendarSubscriptions:
function( calIds, bSubscribe )
{
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;
}
},
subscribeToCalendars:
function( count, calIds )
{
this.modifyCalendarSubscriptions( calIds, true );
},
unsubscribeFromCalendars:
function( count, calIds )
{
this.modifyCalendarSubscriptions( calIds, false );
},
getFreeBusyTimes_resp:
function( wcapResponse, calId, iListener, requestId )
{
try {
var xml = wcapResponse.data; // first statement, may throw
if (iListener != null) {
var ret = [];
var nodeList = xml.getElementsByTagName("FB");
for ( var i = 0; i < nodeList.length; ++i ) {
var item = nodeList.item(i);
var str = item.textContent;
var slash = str.indexOf( '/' );
var start = new CalDateTime();
start.icalString = str.substr( 0, slash );
var end = new CalDateTime();
end.icalString = str.substr( slash + 1 );
var entry = {
isBusyEntry:
(item.attributes.getNamedItem("FBTYPE").nodeValue
== "BUSY"),
dtRangeStart: start,
dtRangeEnd: end
};
ret.push( entry );
}
iListener.onGetFreeBusyTimes(
Components.results.NS_OK,
requestId, calId, ret.length, ret );
}
if (LOG_LEVEL > 0) {
this.log( "getFreeBusyTimes_resp() calId=" + calId + ", " +
getWcapRequestStatusString(xml) );
}
}
catch (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, [] );
}
},
getFreeBusyTimes:
function( calId, rangeStart, rangeEnd, bBusyOnly, iListener,
bAsync, requestId )
{
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"));
url += ("&dtstart=" + zRangeStart);
url += ("&dtend=" + zRangeEnd);
url += "&fmt-out=text%2Fxml";
var this_ = this;
function resp( wcapResponse ) {
this_.getFreeBusyTimes_resp(
wcapResponse, calId, iListener, requestId );
}
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;
}
var userId = this.session.userId;
return (this.calId == userId ||
this.calId.indexOf(userId + ":") == 0);
},
m_calProps: null,
m_calPropsCalid: null,
getCalendarProperties:
function( propName, calId, out_count )
function( propName, out_count )
{
this.getCalProps_(false /* !async: waits for response */);
var ret = [];
if (this.m_calProps != null) {
var nodeList = this.m_calProps.getElementsByTagName(propName);
for ( var i = 0; i < nodeList.length; ++i ) {
ret.push( trimString(nodeList.item(i).textContent) );
}
}
out_count.value = ret.length;
return ret;
},
getCalProps_:
function( bAsync )
{
try {
if (calId.length == 0) {
calId = this.calId;
if (this.m_calProps == null) {
var url = this.session.getCommandUrl( "get_calprops" );
url += ("&calid=" + encodeURIComponent(this.calId));
url += "&fmt-out=text%2Fxml";
var this_ = this;
function resp( wcapResponse ) {
try {
// first statement, may throw:
var xml = wcapResponse.data;
if (this_.m_calProps == null)
this_.m_calProps = xml;
}
catch (exc) {
this_.notifyError( exc );
}
}
if (bAsync)
this.session.issueAsyncRequest( url, stringToXml, resp );
else
this.session.issueSyncRequest( url, stringToXml, resp );
}
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 );
@ -565,13 +266,12 @@ calWcapCalendar.prototype = {
},
get defaultTimezone() {
var tzid = this.getCalendarProperties("X-NSCP-CALPROPS-TZID", "", {});
var tzid = this.getCalendarProperties("X-NSCP-CALPROPS-TZID", {});
if (tzid.length < 1) {
return "UTC"; // fallback
}
return tzid[0];
},
// set defaultTimezone( tzid ) {
// if (this.readOnly)
// throw Components.interfaces.calIErrors.CAL_IS_READONLY;
@ -590,6 +290,6 @@ calWcapCalendar.prototype = {
}
else // is ok (supported):
return tzid;
}
}
};

View File

@ -194,8 +194,8 @@ calWcapCalendar.prototype.getRecurrenceParams = function(
calWcapCalendar.prototype.getStoreUrl = function( item )
{
var bIsEvent = isEvent(item);
var url = this.getCommandUrl( bIsEvent ? "storeevents"
: "storetodos" );
var url = this.session.getCommandUrl( bIsEvent ? "storeevents"
: "storetodos" );
url += "&fetch=1&compressed=1&recurring=1";
url += ("&calid=" + encodeURIComponent(this.calId));
@ -292,7 +292,7 @@ calWcapCalendar.prototype.getStoreUrl = function( item )
forceRSVP = true;
}
else {
var userId = this.userId;
var userId = this.session.userId;
if (userId == null)
userId = this.calId; // fallback
var i = 0;
@ -478,7 +478,7 @@ calWcapCalendar.prototype.adoptItem = function( item, iListener )
url += "&storetype=1";
var this_ = this;
this.issueAsyncRequest(
this.session.issueAsyncRequest(
url + "&fmt-out=text%2Fcalendar", stringToIcal,
function( wcapResponse ) {
this_.adoptItem_resp( wcapResponse, iListener );
@ -573,7 +573,7 @@ calWcapCalendar.prototype.modifyItem = function(
}
var this_ = this;
this.issueAsyncRequest(
this.session.issueAsyncRequest(
url + "&fmt-out=text%2Fcalendar", stringToIcal,
function( wcapResponse ) {
this_.modifyItem_resp( wcapResponse,
@ -634,7 +634,7 @@ calWcapCalendar.prototype.deleteItem = function( item, iListener )
if (item.id == null)
throw new Error("no item id!");
var url = this.getCommandUrl(
var url = this.session.getCommandUrl(
isEvent(item) ? "deleteevents_by_id" : "deletetodos_by_id" );
url += ("&calid=" + encodeURIComponent(this.calId));
url += ("&uid=" + item.id);
@ -653,7 +653,7 @@ calWcapCalendar.prototype.deleteItem = function( item, iListener )
}
var this_ = this;
this.issueAsyncRequest(
this.session.issueAsyncRequest(
url + "&fmt-out=text%2Fxml", stringToXml,
function( wcapResponse ) {
this_.deleteItem_resp( wcapResponse, item, iListener );
@ -885,14 +885,14 @@ calWcapCalendar.prototype.getItem = function( id, iListener )
params += ("&uid=" + id);
try {
// most common: event
this.issueSyncRequest(
this.getCommandUrl( "fetchevents_by_id" ) + params,
this.session.issueSyncRequest(
this.session.getCommandUrl( "fetchevents_by_id" ) + params,
stringToIcal, syncResponseFunc );
}
catch (exc) {
// try again, may be a task:
this.issueSyncRequest(
this.getCommandUrl( "fetchtodos_by_id" ) + params,
this.session.issueSyncRequest(
this.session.getCommandUrl( "fetchtodos_by_id" ) + params,
stringToIcal, syncResponseFunc );
}
}
@ -960,7 +960,7 @@ calWcapCalendar.prototype.getItems = function(
",\n\trangeStart=" + zRangeStart +
",\n\trangeEnd=" + zRangeEnd );
try {
var url = this.getCommandUrl( "fetchcomponents_by_range" );
var url = this.session.getCommandUrl( "fetchcomponents_by_range" );
url += ("&calid=" + encodeURIComponent(this.calId));
url += "&compressed=1&recurring=1";
@ -998,7 +998,7 @@ calWcapCalendar.prototype.getItems = function(
url += ("&dtend=" + zRangeEnd);
var this_ = this;
this.issueAsyncRequest(
this.session.issueAsyncRequest(
url + "&fmt-out=text%2Fcalendar", stringToIcal,
function( wcapResponse ) {
this_.getItems_resp( wcapResponse,
@ -1160,10 +1160,10 @@ calWcapCalendar.prototype.syncChangesTo = function(
if (dtFrom == null) {
this.log( "syncChangesTo(): doing initial sync." );
syncState.acquire();
var url = this.getCommandUrl( "fetchcomponents_by_range" );
var url = this.session.getCommandUrl( "fetchcomponents_by_range" );
url += ("&compressed=1&recurring=1&calid=" +
encodeURIComponent(this.calId));
this.issueAsyncRequest(
this.session.issueAsyncRequest(
url + "&fmt-out=text%2Fcalendar", stringToIcal,
function( wcapResponse ) {
this_.syncChangesTo_resp(
@ -1186,8 +1186,8 @@ calWcapCalendar.prototype.syncChangesTo = function(
encodeURIComponent(this.calId));
params += ("&fmt-out=text%2Fcalendar&dtstart=" + zdtFrom);
syncState.acquire();
this.issueAsyncRequest(
this.getCommandUrl( "fetchcomponents_by_lastmod" ) + params,
this.session.issueAsyncRequest(
this.session.getCommandUrl("fetchcomponents_by_lastmod")+params,
stringToIcal,
function( wcapResponse ) {
this_.syncChangesTo_resp(
@ -1215,8 +1215,8 @@ calWcapCalendar.prototype.syncChangesTo = function(
var deleteItemListener = new FinishListener(
Components.interfaces.calIOperationListener.DELETE, syncState );
syncState.acquire();
this.issueAsyncRequest(
this.getCommandUrl( "fetch_deletedcomponents" ) + params,
this.session.issueAsyncRequest(
this.session.getCommandUrl("fetch_deletedcomponents") + params,
stringToIcal,
function( wcapResponse ) {
this_.syncChangesTo_resp(

View File

@ -45,6 +45,12 @@ var calWcapCalendarModule = {
classID: Components.ID("{CF4D93E5-AF79-451a-95F3-109055B32EF0}")
},
WcapSessionInfo: {
classDescription: "Sun Java System Calendar Server WCAP Session",
contractID: "@mozilla.org/calendar/session;1?type=wcap",
classID: Components.ID("{CBF803FD-4469-4999-AE39-367AF1C7B077}")
},
registerSelf:
function( compMgr, fileSpec, location, type )
{
@ -55,6 +61,11 @@ var calWcapCalendarModule = {
this.WcapCalendarInfo.classDescription,
this.WcapCalendarInfo.contractID,
fileSpec, location, type );
compMgr.registerFactoryLocation(
this.WcapSessionInfo.classID,
this.WcapSessionInfo.classDescription,
this.WcapSessionInfo.contractID,
fileSpec, location, type );
},
m_scriptsLoaded: false,
@ -95,12 +106,16 @@ var calWcapCalendarModule = {
throw Components.results.NS_ERROR_NO_AGGREGATION;
var cal;
switch (CACHE) {
case "memory":
case "storage":
cal = new calWcapCachedCalendar();
break;
// unsupported until fixed:
// case "memory":
// case "storage":
// cal = new calWcapCachedCalendar();
// break;
default:
cal = new calWcapCalendar();
cal = new calWcapCalendar(
null /* calId: indicates default calendar */,
new calWcapSession() );
cal.session.defaultCalendar = cal;
break;
}
return cal.QueryInterface( iid );

View File

@ -147,6 +147,7 @@ function issueAsyncRequest( url, receiverFunc )
logMessage( "issueAsyncRequest( \"" + url + "\" )", "opening channel." );
var channel = getIoService().newChannel(
url, "" /* charset */, null /* baseURI */ );
channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
loader.init( channel, reader, null /* context */, 0 /* segment size */ );
}
@ -180,6 +181,7 @@ function issueSyncRequest( url, receiverFunc, bLogging )
}
var channel = getIoService().newChannel(
url, "" /* charset */, null /* baseURI */ );
channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
var stream = channel.open();
if (bLogging && LOG_LEVEL > 1) {
logMessage( "issueSyncRequest( \"" + url + "\" )",

View File

@ -41,36 +41,75 @@
var g_serverTimeDiffs = {};
var g_allSupportedTimezones = {};
function calWcapSession( thatUri ) {
function calWcapSession() {
this.wrappedJSObject = this;
// sensible default for user id login:
var username = decodeURIComponent( thatUri.username );
if (username != "") {
var nColon = username.indexOf(':');
this.m_userId = (nColon >= 0 ? username.substr(0, nColon) : username);
}
this.m_uri = thatUri.clone();
this.m_uri.userPass = "";
this.m_observers = [];
this.m_calIdToCalendar = {};
// listen for shutdown, being logged out:
// network:offline-about-to-go-offline will be fired for
// XPCOM shutdown, too.
// xxx todo: alternatively, add shutdown notifications to cal manager
// xxx todo: how to simplify this for multiple topics?
var observerService = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
.getService(Components.interfaces.nsIObserverService);
observerService.addObserver( this, "quit-application",
false /* don't hold weakly: xxx todo */ );
observerService.addObserver( this, "network:offline-about-to-go-offline",
false /* don't hold weakly: xxx todo */ );
}
calWcapSession.prototype = {
m_uri: null,
m_sessionId: null,
m_userId: null,
m_bNoLoginsAnymore: false,
m_ifaces: [ Components.interfaces.calIWcapSession,
Components.interfaces.nsIInterfaceRequestor,
Components.interfaces.nsIClassInfo,
Components.interfaces.nsISupports ],
get uri() { return this.m_uri; },
// nsISupports:
QueryInterface:
function( iid )
{
for each ( var iface in this.m_ifaces ) {
if (iid.equals( iface ))
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
},
// nsIClassInfo:
getInterfaces:
function( count )
{
count.value = this.m_ifaces.length;
return this.m_ifaces;
},
get classDescription() {
return calWcapCalendarModule.WcapSessionInfo.classDescription;
},
get contractID() {
return calWcapCalendarModule.WcapSessionInfo.contractID;
},
get classID() {
return calWcapCalendarModule.WcapSessionInfo.classID;
},
getHelperForLanguage: function( language ) { return null; },
implementationLanguage:
Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
flags: 0,
// nsIInterfaceRequestor:
getInterface:
function( iid, instance )
{
if (iid.equals(Components.interfaces.nsIAuthPrompt)) {
// use the window watcher service to get a nsIAuthPrompt impl
return getWindowWatcher().getNewAuthPrompter(null);
}
else if (iid.equals(Components.interfaces.nsIPrompt)) {
// use the window watcher service to get a nsIPrompt impl
return getWindowWatcher().getNewPrompter(null);
}
Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
return null;
},
toString:
function( msg )
@ -92,17 +131,51 @@ calWcapSession.prototype = {
{
return logMessage( this.toString(), msg );
},
// nsISupports:
QueryInterface:
function( iid )
logError:
function( err, context )
{
if (iid.equals(Components.interfaces.nsIObserver) ||
iid.equals(Components.interfaces.nsISupports)) {
return this;
var str = ("error: " + errorToString(err));
Components.utils.reportError( this.log( str, context ) );
return str;
},
notifyError:
function( err )
{
debugger;
var str = this.logError( err );
this.notifyObservers( "onError",
[err instanceof Error ? -1 : err, str] );
},
m_observers: null,
notifyObservers:
function( func, args )
{
this.m_observers.forEach(
function( obj ) {
try {
obj[func].apply( obj, args );
}
catch (exc) {
// don't call notifyError() here:
Components.utils.reportError( exc );
}
} );
},
addObserver:
function( observer )
{
if (this.m_observers.indexOf( observer ) == -1) {
this.m_observers.push( observer );
}
else
throw Components.results.NS_ERROR_NO_INTERFACE;
},
removeObserver:
function( observer )
{
this.m_observers = this.m_observers.filter(
function(x) { return x != observer; } );
},
// nsIObserver:
@ -125,8 +198,6 @@ calWcapSession.prototype = {
}
},
get userId() { return this.m_userId; },
getSupportedTimezones:
function( bRefresh )
{
@ -219,6 +290,9 @@ calWcapSession.prototype = {
return realm;
},
m_sessionId: null,
m_bNoLoginsAnymore: false,
getSessionId:
function( timedOutSessionId )
{
@ -267,6 +341,11 @@ calWcapSession.prototype = {
this.getSupportedTimezones( true /* refresh */ );
this.getServerTimeDiff( true /* refresh */ );
// preread calprops for subscribed calendars:
var cals = this.getSubscribedCalendars({});
for each ( cal in cals ) {
cal.getCalProps_(true /* async */);
}
}
}
catch (exc) {
@ -289,7 +368,7 @@ calWcapSession.prototype = {
Components.classes["@mozilla.org/passwordmanager;1"]
.getService(Components.interfaces.nsIPasswordManager);
var outUser = { value: this.m_userId };
var outUser = { value: this.userId };
var outPW = { value: null };
var enumerator = passwordManager.enumerator;
@ -332,7 +411,7 @@ calWcapSession.prototype = {
else {
this.log( "password entry found for user " + outUser.value );
try {
this.login( loginUri, outUser.value, outPW.value );
this.login_( loginUri, outUser.value, outPW.value );
}
catch (exc) { // ignore silently
}
@ -370,8 +449,8 @@ calWcapSession.prototype = {
// user/pw has been found previously,
// but no login was possible,
// try again using http here:
this.login( loginUri,
outUser.value, outPW.value );
this.login_( loginUri,
outUser.value, outPW.value );
if (this.m_sessionId != null)
return this.m_sessionId;
}
@ -416,7 +495,7 @@ calWcapSession.prototype = {
savePW ))
{
try {
this.login( loginUri, outUser.value, outPW.value );
this.login_( loginUri, outUser.value, outPW.value );
}
catch (exc) {
Components.utils.reportError( exc );
@ -439,6 +518,34 @@ calWcapSession.prototype = {
return this.m_sessionId;
},
login_:
function( loginUri, user, pw )
{
if (this.m_sessionId != null) {
this.logout();
}
// currently, xml parsing at an early stage during process startup
// does not work reliably, so use libical parsing for now:
var str = issueSyncRequest(
loginUri.spec + "login.wcap?fmt-out=text%2Fcalendar&user=" +
encodeURIComponent(user) + "&password=" + encodeURIComponent(pw),
null /* receiverFunc */, false /* no logging */ );
var icalRootComp = getIcsService().parseICS( str );
checkWcapIcalErrno( icalRootComp );
var prop = icalRootComp.getFirstProperty( "X-NSCP-WCAP-SESSION-ID" );
if (prop == null)
throw new Error("missing X-NSCP-WCAP-SESSION-ID!");
this.m_sessionId = prop.value;
// var xml = issueSyncXMLRequest(
// loginUri.spec + "login.wcap?fmt-out=text%2Fxml&user=" +
// encodeURIComponent(user) + "&password=" + encodeURIComponent(pw) );
// checkWcapXmlErrno( xml );
// this.m_sessionId = xml.getElementsByTagName(
// "X-NSCP-WCAP-SESSION-ID" ).item(0).textContent;
this.m_userId = user;
this.log( "WCAP login succeeded." );
},
getServerInfo:
function( uri )
@ -496,33 +603,112 @@ calWcapSession.prototype = {
"loginDialog.text", loginTextVars, loginTextVars.length );
},
login:
function( loginUri, user, pw )
getCommandUrl:
function( wcapCommand )
{
if (this.m_sessionId != null) {
this.logout();
}
// currently, xml parsing at an early stage during process startup
// does not work reliably, so use libical parsing for now:
var str = issueSyncRequest(
loginUri.spec + "login.wcap?fmt-out=text%2Fcalendar&user=" +
encodeURIComponent(user) + "&password=" + encodeURIComponent(pw),
null /* receiverFunc */, false /* no logging */ );
var icalRootComp = getIcsService().parseICS( str );
checkWcapIcalErrno( icalRootComp );
var prop = icalRootComp.getFirstProperty( "X-NSCP-WCAP-SESSION-ID" );
if (prop == null)
throw new Error("missing X-NSCP-WCAP-SESSION-ID!");
this.m_sessionId = prop.value;
if (this.uri == null)
throw new Error("no URI!");
// ensure established session, so userId is set;
// (calId defaults to userId) if not set:
this.getSessionId();
return (this.uri.spec + wcapCommand + ".wcap?appid=mozilla-lightning");
},
issueRequest:
function( url, issueFunc, dataConvFunc, receiverFunc )
{
var sessionId = this.getSessionId();
// var xml = issueSyncXMLRequest(
// loginUri.spec + "login.wcap?fmt-out=text%2Fxml&user=" +
// encodeURIComponent(user) + "&password=" + encodeURIComponent(pw) );
// checkWcapXmlErrno( xml );
// this.m_sessionId = xml.getElementsByTagName(
// "X-NSCP-WCAP-SESSION-ID" ).item(0).textContent;
this.m_userId = user;
this.log( "WCAP login succeeded." );
var this_ = this;
issueFunc(
url + ("&id=" + sessionId),
function( data ) {
var wcapResponse = new WcapResponse();
try {
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_.getSessionId(
sessionId /* (old) timed-out session */ );
// try again:
this_.issueRequest(
url, issueFunc, dataConvFunc, receiverFunc );
return;
}
throw exc; // rethrow
}
}
catch (exc) {
// setting the request's exception will rethrow exception
// when request's data is retrieved.
wcapResponse.exception = exc;
}
receiverFunc( wcapResponse );
} );
},
issueAsyncRequest:
function( url, dataConvFunc, receiverFunc )
{
this.issueRequest(
url, issueAsyncRequest, dataConvFunc, receiverFunc );
},
issueSyncRequest:
function( url, dataConvFunc, receiverFunc )
{
var ret = null;
this.issueRequest(
url, issueSyncRequest,
dataConvFunc,
function( wcapResponse ) {
if (receiverFunc) {
receiverFunc( wcapResponse );
}
ret = wcapResponse.data; // may throw
} );
return ret;
},
// calIWcapSession:
m_uri: null,
get uri() { return this.m_uri; },
set uri( thatUri )
{
if (this.m_uri == null || thatUri == null ||
!this.m_uri.equals(thatUri))
{
this.logout();
this.m_uri = null;
if (thatUri != null) {
// sensible default for user id login:
var username = decodeURIComponent( thatUri.username );
if (username != "") {
var nColon = username.indexOf(':');
this.m_userId =
(nColon >= 0 ? username.substr(0, nColon) : username);
}
this.m_uri = thatUri.clone();
this.m_uri.userPass = "";
}
}
},
m_userId: null,
get userId() { return this.m_userId; },
login:
function()
{
this.logout(); // assure being logged out
this.getSessionId();
},
logout:
@ -544,18 +730,278 @@ calWcapSession.prototype = {
Components.utils.reportError( exc );
}
this.m_sessionId = null;
this.m_userId = null;
}
this.m_userId = null;
// ask next time we log in:
var this_ = this;
g_httpHosts = g_httpHosts.filter(
function(hostEntry) {
return (hostEntry.m_host != this_.uri.hostPort); } );
this.m_bNoLoginsAnymore = false;
},
getWcapErrorString:
function( rc )
{
return wcapErrorToString(rc);
},
get defaultCalendar() {
return this.getCalendarByCalId(this.userId);
},
set defaultCalendar(cal) {
this.m_defaultCalendar = cal;
},
m_defaultCalendar: null,
m_calIdToCalendar: {},
getCalendarByCalId:
function( calId )
{
if (calId == null || this.userId == calId) {
if (this.m_defaultCalendar == null)
this.m_defaultCalendar = new calWcapCalendar(this.userId);
return this.m_defaultCalendar;
}
else {
var key = encodeURIComponent(calId);
var ret = this.m_calIdToCalendar[key];
if (!ret) {
ret = new calWcapCalendar( calId, this );
this.m_calIdToCalendar[key] = ret;
}
return ret;
}
},
getCalendars:
function( out_count, bGetOwnedCals )
{
var list = this.getUserPreferences(
bGetOwnedCals ? "X-NSCP-WCAP-PREF-icsCalendarOwned"
: "X-NSCP-WCAP-PREF-icsSubscribed", {} );
var ret = [];
for each( var item in list ) {
var ar = item.split(',');
// ',', '$' are not encoded. ',' can be handled here. WTF.
for each ( a in ar ) {
var dollar = a.indexOf('$');
if (dollar >= 0) {
ret.push(
this.getCalendarByCalId( a.substring(0, dollar) ) );
}
}
}
out_count.value = ret.length;
return ret;
},
getOwnedCalendars:
function( out_count )
{
return this.getCalendars( out_count, true );
},
getSubscribedCalendars:
function( out_count )
{
return this.getCalendars( out_count, false );
},
createCalendar:
function( calId, name, bAllowDoubleBooking, bSetCalProps, bAddToSubscribed )
{
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 );
this.m_userPrefs = null; // reread prefs
return this.getCalendarByCalId( this.userId + ":" + calId );
}
catch (exc) {
this.notifyError( exc );
throw exc;
}
},
deleteCalendar:
function( calId, bRemoveFromSubscribed )
{
try {
var url = this.getCommandUrl( "deletecalendar" );
url += ("&unsubscribe=" + (bRemoveFromSubscribed ? "1" : "0"));
url += ("&calid=" + encodeURIComponent(calId));
this.issueSyncRequest( url + "&fmt-out=text%2Fxml", stringToXml );
this.m_userPrefs = null; // reread prefs
this.m_calIdToCalendar[encodeURIComponent(calId)] = null;
}
catch (exc) {
this.notifyError( exc );
throw exc;
}
},
modifyCalendarSubscriptions:
function( calIds, bSubscribe )
{
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 );
this.m_userPrefs = null; // reread prefs
}
catch (exc) {
this.notifyError( exc );
throw exc;
}
},
subscribeToCalendars:
function( count, calIds )
{
this.modifyCalendarSubscriptions( calIds, true );
},
unsubscribeFromCalendars:
function( count, calIds )
{
this.modifyCalendarSubscriptions( calIds, false );
},
m_userPrefs: null,
getUserPreferences:
function( prefName, out_count )
{
try {
if (this.m_userPrefs == null) {
var url = this.getCommandUrl( "get_userprefs" );
url += ("&userid=" + encodeURIComponent(this.userId));
this.m_userPrefs = this.issueSyncRequest(
url + "&fmt-out=text%2Fxml", stringToXml );
}
var ret = [];
var nodeList = this.m_userPrefs.getElementsByTagName(prefName);
for ( var i = 0; i < nodeList.length; ++i ) {
ret.push( trimString(nodeList.item(i).textContent) );
}
out_count.value = ret.length;
return ret;
}
catch (exc) {
this.notifyError( exc );
throw exc;
}
},
getFreeBusyTimes_resp:
function( wcapResponse, calId, iListener, requestId )
{
try {
var xml = wcapResponse.data; // first statement, may throw
if (iListener != null) {
var ret = [];
var nodeList = xml.getElementsByTagName("FB");
for ( var i = 0; i < nodeList.length; ++i ) {
var item = nodeList.item(i);
var str = item.textContent;
var slash = str.indexOf( '/' );
var start = new CalDateTime();
start.icalString = str.substr( 0, slash );
var end = new CalDateTime();
end.icalString = str.substr( slash + 1 );
var entry = {
isBusyEntry:
(item.attributes.getNamedItem("FBTYPE").nodeValue
== "BUSY"),
dtRangeStart: start,
dtRangeEnd: end
};
ret.push( entry );
}
iListener.onGetFreeBusyTimes(
Components.results.NS_OK,
requestId, calId, ret.length, ret );
}
if (LOG_LEVEL > 0) {
this.log( "getFreeBusyTimes_resp() calId=" + calId + ", " +
getWcapRequestStatusString(xml) );
}
}
catch (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, [] );
}
},
getFreeBusyTimes:
function( calId, rangeStart, rangeEnd, bBusyOnly, iListener,
bAsync, requestId )
{
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"));
url += ("&dtstart=" + zRangeStart);
url += ("&dtend=" + zRangeEnd);
url += "&fmt-out=text%2Fxml";
var this_ = this;
function resp( wcapResponse ) {
this_.getFreeBusyTimes_resp(
wcapResponse, calId, iListener, requestId );
}
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;
}
}
};
g_httpHosts = [];
var g_httpHosts = [];
function confirmUnsecureLogin( uri )
{
var host = uri.hostPort;
@ -575,15 +1021,3 @@ function confirmUnsecureLogin( uri )
return bConfirmed;
}
g_sessions = {};
function getSession( uri )
{
var session = g_sessions[uri.spec];
if (!session) {
logMessage( "getSession()", "entering session for uri=" + uri.spec );
var session = new calWcapSession( uri );
g_sessions[uri.spec] = session;
}
return session;
}

View File

@ -299,6 +299,11 @@ function forEachIcalComponent( icalRootComp, componentType, func, maxResult )
}
}
function trimString( str )
{
return str.replace( /(^\s+|\s+$)/g, "" );
}
function getTime()
{
var ret = new CalDateTime();

View File

@ -51,6 +51,7 @@ XPIDLSRCS = calIWcapCalendar.idl \
calIWcapErrors.idl \
calIWcapFreeBusyEntry.idl \
calIWcapFreeBusyListener.idl \
calIWcapSession.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -38,9 +38,8 @@
* ***** END LICENSE BLOCK ***** */
#include "calICalendar.idl"
#include "calIWcapFreeBusyListener.idl"
#include "calIDateTime.idl"
#include "calIICSService.idl"
interface calIWcapSession;
/** Adds WCAP specific capabilities.
*/
@ -48,164 +47,46 @@
interface calIWcapCalendar : calICalendar
{
/**
* Current userId; if the user is not logged in, a dialog will prompt for.
* User session this calendar instance belongs to.
*/
readonly attribute string userId;
readonly attribute calIWcapSession session;
/**
* Calendar description.
*/
readonly attribute string description;
/**
* Current calId the calendar instance acts on; defaults to userId.
*/
attribute string calId;
/*readonly xxx todo*/ attribute string calId;
/**
* Whether the currently selected calendar belongs to user.
*/
readonly attribute boolean isOwnedCalendar;
// /**
// * Gets or sets this calendar's (calId) default timezone.
// */
// attribute string defaultTimezone;
/**
* Gets or sets this calendar's (calId) default timezone.
*/
readonly attribute string defaultTimezone;
/**
* Gets calendar properties for specified calId.
* Gets calendar properties.
* 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 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".
* valid characters for the calId parameter are:
* - Alphabet characters (A-Z, a-z)
* - Numeric characters (0-9)
* - Three special characters
* - Dash (-)
* - Underscore (_)
* - Period (.)
* @param name calendar's name, e.g. "My Work Cal"
* @param bAllowDoubleBooking whether double booking (events/todos) is
* allowed
* @param bSetCalProps whether properties of the new calendar are set
* @param bAddToSubscribed allows a user to specify if the newly
* created calendar should be added to the
* users subscribed calendar list
* @return calId of created calendar
*/
string createCalendar(
in string calId,
in string name,
in boolean bAllowDoubleBooking,
in boolean bSetCalProps,
in boolean bAddToSubscribed );
/**
* 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
* from subscription list
*/
void deleteCalendar(
in string calId,
in boolean bRemoveFromSubscribed );
/**
* Gets own calendars.
* An error is notified to all registered calIObservers, then thrown.
*
* @return owned calendars (string array of "calId1$Description1", ...)
*/
void getOwnedCalendars(
out unsigned long count,
[array, size_is(count), retval] out string ownCalendars );
/**
* Gets subscribed calendars.
* An error is notified to all registered calIObservers, then thrown.
*
* @return subscribed calendars (string array of "calId1$Description1",...)
*/
void getSubscribedCalendars(
out unsigned long count,
[array, size_is(count), retval] out string subscribedCalendars );
/**
* 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")
*/
void subscribeToCalendars(
in unsigned long count,
[array, size_is(count)] in string calIds );
/**
* 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")
*/
void unsubscribeFromCalendars(
in unsigned long count,
[array, size_is(count)] in string calIds );
/**
* Gets free-busy entries for calid.
* Results are notifies to passed listener instance.
* 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
* @param dtRangeEnd end time of free-busy search
* @param bBusyOnly whether to return busy entries only
* @param iListener listener receiving results
* @param bAsync whether the listener receives results asynchronously
* @param requestId request id to distinguish asynchronous requests
*/
void getFreeBusyTimes(
in string calId,
in calIDateTime dtRangeStart,
in calIDateTime dtRangeEnd,
in boolean bBusyOnly,
in calIWcapFreeBusyListener iListener,
in boolean bAsync,
in unsigned long requestId );
/** 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
@ -249,7 +130,13 @@ interface calIWcapCalendar : calICalendar
* user to other invitees, and is currently awaiting.
*/
const unsigned long ITEM_FILTER_REQUEST_WAITFORREPLY = 1 << 30;
/* xxx todo sync feature: separate into own interface? */
/** xxx todo: to be moved to calIOperationListener?
*/
const unsigned long SYNC = 5;
/**
* Syncs in changes since time <code>dtFrom</code>.
* The passed <code>iListener</code> receives a

View File

@ -38,6 +38,7 @@
* ***** END LICENSE BLOCK ***** */
#include "calIWcapFreeBusyEntry.idl"
#include "calIWcapCalendar.idl"
[scriptable, uuid(4498E0D0-04EC-43a3-92E0-560667696CF3)]
interface calIWcapFreeBusyListener : nsISupports

View File

@ -0,0 +1,228 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Sun Microsystems, Inc.
* Portions created by Sun Microsystems are Copyright (C) 2006 Sun
* Microsystems, Inc. All Rights Reserved.
*
* Original Author: Daniel Boelzle (daniel.boelzle@sun.com)
*
* Contributor(s):
*
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the NPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "calIWcapCalendar.idl"
#include "calIWcapFreeBusyListener.idl"
/**
* WCAP session.
*/
[scriptable, uuid(477B4534-C297-40a1-ADF2-5A7E2A81816A)]
interface calIWcapSession : nsISupports
{
/**
* Setting this URI causes the session to be disconnected.
*/
attribute nsIURI uri;
/**
* User that has established this session.
* Reading this attribute prompts for login if the session has not yet
* been established.
* An error is notified to all registered calIObservers, then thrown.
*/
readonly attribute string userId;
/**
* Explicitly performs a session establishment.
* Commonly not needed, because any attempt to get a calendar instance
* will establish a session automatically.
* If the user is alread logged in, she will be logged out before.
* UI will prompt for a userId and password.
* An error is notified to all registered calIObservers, then thrown.
*/
void login();
/**
* Explicitly performs a session logout.
* Commonly not needed, because the user will be logged out upon
* "network:offline-about-to-go-offline" and "quit-application"
* automatically.
* An error is notified to all registered calIObservers, then thrown.
*/
void logout();
/**
* Gets a text for an error code.
*
* @param rc error code defined in calIWcapErrors
* @return error string
* @exception NS_ERROR_INVALID_ARG
*/
string getWcapErrorString( in unsigned long rc );
/**
* The user's default calendar.
* An error is notified to all registered calIObservers, then thrown.
*/
readonly attribute calIWcapCalendar defaultCalendar;
/**
* Gets a calendar instance for the passed calId using this session.
* An error is notified to all registered calIObservers, then thrown.
*
* @param calId full calId (incl. "<user>:")
* @return calendar instance
*/
calIWcapCalendar getCalendarByCalId( in string calId );
/**
* Gets calendars where the user is the primary owner
* (including default calendar).
* An error is notified to all registered calIObservers, then thrown.
*
* @return array of owned calendars
*/
void getOwnedCalendars(
out unsigned long count,
[array, size_is(count), retval] out calIWcapCalendar ownedCals );
/**
* Gets subscribed calendars (may include calendars where the user
* is the primary owner).
* An error is notified to all registered calIObservers, then thrown.
*
* @return array of subscribed calendars
*/
void getSubscribedCalendars(
out unsigned long count,
[array, size_is(count), retval] out calIWcapCalendar subscribedCals );
/**
* Creates a new calendar for the session's 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".
* valid characters for the calId parameter are:
* - Alphabet characters (A-Z, a-z)
* - Numeric characters (0-9)
* - Three special characters
* - Dash (-)
* - Underscore (_)
* - Period (.)
* @param name calendar's name, e.g. "My Work Cal"
* @param bAllowDoubleBooking whether double booking (events/todos) is
* allowed
* @param bSetCalProps whether properties of the new calendar are set
* @param bAddToSubscribed allows a user to specify if the newly
* created calendar should be added to the
* users subscribed calendar list
* @return created calendar
*/
calIWcapCalendar createCalendar(
in string calId,
in string name,
in boolean bAllowDoubleBooking,
in boolean bSetCalProps,
in boolean bAddToSubscribed );
/**
* 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
* from subscription list
*/
void deleteCalendar(
in string calId,
in boolean bRemoveFromSubscribed );
/**
* 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")
*/
void subscribeToCalendars(
in unsigned long count,
[array, size_is(count)] in string calIds );
/**
* 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")
*/
void unsubscribeFromCalendars(
in unsigned long count,
[array, size_is(count)] in string calIds );
/**
* Gets the user's preferences.
* An error is notified to all registered calIObservers, then thrown.
*
* @param prefName preference name
* @return array of preference values
*/
void getUserPreferences(
in string prefName,
out unsigned long count,
[array, size_is(count), retval] out string properties );
/* xxx todo freebusy: separate into own interface? */
/**
* Gets free-busy entries for calid.
* Results are notifies to passed listener instance.
* 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
* @param dtRangeEnd end time of free-busy search
* @param bBusyOnly whether to return busy entries only
* @param iListener listener receiving results
* @param bAsync whether the listener receives results asynchronously
* @param requestId request id to distinguish asynchronous requests
*/
void getFreeBusyTimes(
in string calId,
in calIDateTime dtRangeStart,
in calIDateTime dtRangeEnd,
in boolean bBusyOnly,
in calIWcapFreeBusyListener iListener,
in boolean bAsync,
in unsigned long requestId );
};