bug 340949: WCAP provider contribution; initial check-in, not part of the build

This commit is contained in:
daniel.boelzle%sun.com 2006-06-28 17:01:38 +00:00
parent abefc19db2
commit 7e9a8b360f
14 changed files with 4596 additions and 0 deletions

View File

@ -0,0 +1,73 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 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 *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = public
MODULE = wcap
EXTRA_PP_COMPONENTS = \
calWcapUtils.js \
calWcapRequest.js \
calWcapErrors.js \
calWcapSession.js \
calWcapCalendarItems.js \
calWcapCalendar.js \
calWcapCachedCalendar.js \
calWcapCalendarModule.js \
$(NULL)
# minimum log level:
ifdef wcap_logging
ifeq (,$(findstring $(wcap_logging),1 2 3 4 5))
DEFINES += -DLOG_LEVEL=2
else
DEFINES += -DLOG_LEVEL=$(wcap_logging)
endif
else # ifdef wcap_logging
DEFINES += -DLOG_LEVEL=0
endif # ifdef wcap_logging
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,610 @@
/* -*- Mode: javascript; 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 ***** */
/**
* PROTOTYPE!
*/
// globals:
var g_localCals = {};
var g_localCalsLastSync = {};
function calWcapCachedCalendar() {
this.wrappedJSObject = this;
this.m_observers = [];
this.m_observerMultiplexer = new ObserverMultiplexer(this);
this.m_syncQueue = new RequestQueue();
}
calWcapCachedCalendar.prototype = {
m_ifaces: [ Components.interfaces.calIWcapCalendar,
Components.interfaces.calICalendar,
Components.interfaces.nsIInterfaceRequestor,
Components.interfaces.nsIClassInfo,
Components.interfaces.nsISupports ],
// 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.WcapCalendarInfo.classDescription;
},
get contractID() {
return calWcapCalendarModule.WcapCalendarInfo.contractID;
},
get classID() {
return calWcapCalendarModule.WcapCalendarInfo.classID;
},
getHelperForLanguage: function( language ) { return null; },
implementationLanguage:
Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
flags: 0,
// nsIInterfaceRequestor:
getInterface:
function( iid, instance )
{
return this.remoteCal.getInterface( iid, instance );
},
m_observerMultiplexer: null,
m_remoteCal: null,
get remoteCal() {
if (this.m_remoteCal == null)
this.remoteCal = new calWcapCalendar();
return this.m_remoteCal;
},
set remoteCal( cal ) {
if (this.m_remoteCal != null)
this.m_remoteCal.removeObserver( this.m_observerMultiplexer );
if (cal != null) {
cal.addObserver( this.m_observerMultiplexer );
cal.superCalendar = this;
}
this.m_remoteCal = cal;
},
getCalKey:
function()
{
// xxx todo: better eoncoding?
return encodeURIComponent( this.uri.spec /* i.e. remote uri */ +
"?calid=" + this.calId );
},
m_localCal: null,
get localCal() {
if (this.m_localCal == null) {
// xxx todo: sharing? storage cal_id: STRING?
// assure logged in, so userId/calId is properly set:
this.remoteCal.session.getSessionId();
// xxx todo: better eoncoding?
var key = this.getCalKey();
var cal = g_localCals[key];
if (! cal) {
this.log( "creating cache calendar for calId " + this.calId );
var uri;
if (CACHE == "memory") { // in-memory caching
uri = this.uri.clone();
uri.path += ("?calid=" + this.calId);
}
else {
// xxx todo: change storage cal to support STRING cal_id
var dbPath = CACHE_DIR.clone();
dbPath.append( key + ".sdb" );
uri = getIoService().newFileURI( dbPath );
}
this.log( "local cal uri: " + uri.spec );
try {
cal = getCalendarManager().createCalendar( CACHE, uri );
g_localCals[key] = cal;
}
catch (exc) {
this.notifyError( exc );
}
}
this.localCal = cal;
}
return this.m_localCal;
},
set localCal( cal ) {
if (cal != null) {
cal.suppressAlarms = this.remoteCal.suppressAlarms; // sync setting
cal.superCalendar = this;
}
this.m_localCal = cal;
},
toString:
function()
{
return "cached-wcap | " + this.remoteCal.toString();
},
log:
function( msg, context )
{
return this.remoteCal.log( msg, context ? context : this.toString() );
},
logError:
function( err, context )
{
return this.remoteCal.logError(
err, context ? context : this.toString() );
},
notifyError:
function( err )
{
debugger;
var str = this.logError( err );
this.notifyObservers( "onError",
[err instanceof Error ? -1 : err, str] );
},
// calIWcapCalendar:
// xxx todo: generic facade helpers for most function delegates
getWcapErrorString:
function( rc )
{
return this.remoteCal.getWcapErrorString(rc);
},
// xxx todo: which userId is used when for offline scheduling?
// if not logged in, no calId/userId is known... => UI
get calId() { return this.remoteCal.calId; },
set calId( id ) {
this.localCal = null; // disconnect
this.remoteCal.calId = id;
},
get userId() { return this.remoteCal.userId; },
get isOwnedCalendar() { return this.remoteCal.isOwnedCalendar; },
createCalendar:
function( calId, name, bAllowDoubleBooking, bSetCalProps, bAddToSubscribed )
{
return this.remoteCal.createCalendar(
calId, name, bAllowDoubleBooking, bSetCalProps, bAddToSubscribed );
},
deleteCalendar:
function( calId, bRemoveFromSubscribed )
{
this.remoteCal.deleteCalendar( calId, bRemoveFromSubscribed );
},
getOwnedCalendars:
function( out_count )
{
return this.remoteCal.getOwnedCalendars( out_count );
},
getSubscribedCalendars:
function( out_count )
{
return this.remoteCal.getSubscribedCalendars( out_count );
},
subscribeToCalendars:
function( count, calIds )
{
this.remoteCal.subscribeToCalendars( count, calIds );
},
unsubscribeFromCalendars:
function( count, calIds )
{
this.remoteCal.unsubscribeFromCalendars( count, calIds );
},
getFreeBusyTimes:
function( calId, rangeStart, rangeEnd, bBusyOnly, iListener,
bAsync, requestId )
{
return this.remoteCal.getFreeBusyTimes(
calId, rangeEnd, rangeEnd, bBusyOnly, iListener, bAsync, requestId);
},
get defaultTimezone() {
return this.remoteCal.defaultTimezone;
},
// set defaultTimezone( tzid ) {
// },
// calICalendar:
get name() {
return getCalendarManager().getCalendarPref( this, "NAME" );
},
set name( name ) {
getCalendarManager().setCalendarPref( this, "NAME", name );
},
get type() { return "wcap"; },
m_bReadOnly: false,
get readOnly() { return (this.m_bReadOnly || this.remoteCal.readOnly); },
set readOnly( bReadOnly ) { this.m_bReadOnly = bReadOnly; },
get uri() { return this.remoteCal.uri; },
set uri( thatUri ) {
this.localCal = null; // disconnect
this.remoteCal.uri = thatUri;
},
m_superCalendar: null,
get superCalendar() { return this.m_superCalendar || this; },
set superCalendar( cal ) { this.m_superCalendar = cal; },
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 );
}
},
removeObserver:
function( observer )
{
this.m_observers = this.m_observers.filter(
function(x) { return x != observer; } );
},
// xxx todo: batch currently not used
startBatch: function() { this.notifyObservers( "onStartBatch", [] ); },
endBatch: function() { this.notifyObservers( "onEndBatch", [] ); },
get suppressAlarms() { return this.remoteCal.suppressAlarms; },
set suppressAlarms( bSuppressAlarms ) {
this.remoteCal.suppressAlarms = bSuppressAlarms;
this.localCal.suppressAlarms = this.remoteCal.suppressAlarms;
},
get canRefresh() { return true; },
refresh:
function()
{
this.log( "refresh() call." );
if (this.remoteCal.canRefresh)
this.remoteCal.refresh();
if (this.localCal.canRefresh)
this.localCal.refresh();
// sync in changes to local calendar:
this.sync(null);
this.log( "refresh() returning." );
},
adoptItem:
function( item, iListener )
{
this.remoteCal.adoptItem( item, iListener );
},
addItem:
function( item, iListener )
{
this.remoteCal.addItem( item, iListener );
},
modifyItem:
function( newItem, oldItem, iListener )
{
this.remoteCal.modifyItem( newItem, oldItem, iListener );
},
deleteItem:
function( item, iListener )
{
this.remoteCal.deleteItem( item, iListener );
},
getItem:
function( id, iListener )
{
// xxx todo: testing
this.log( ">>>>>>>>>>>>>>>> getItem() call!");
this.refresh();
this.localCal.getItem( id, iListener );
this.log( "getItem() returning." );
},
getItems:
function( itemFilter, maxResult, rangeStart, rangeEnd, iListener )
{
this.log( "getItems():\n\titemFilter=" + itemFilter +
",\n\tmaxResult=" + maxResult +
",\n\trangeStart=" + getIcalUTC(rangeStart) +
",\n\trangeEnd=" + getIcalUTC(rangeEnd) );
var this_ = this;
this.sync(
{ // calIOperationListener:
onOperationComplete:
function( calendar, status, opType, id, detail )
{
if (iListener != null) {
if (status == Components.results.NS_OK) {
// delegate to local cal:
this_.log("begin localCal.getItems().");
this_.localCal.getItems(
itemFilter, maxResult, rangeStart, rangeEnd,
iListener );
this_.log("end localCal.getItems().");
}
else {
iListener.onOperationComplete(
calendar, status, opType, id, detail );
}
}
},
onGetResult:
function( calendar, status, itemType, detail, count, items )
{
this_.notifyError( "unexpected onGetResult upon sync!" );
}
} );
},
getStampFile:
function()
{
var stampFile = this.localCal.uri.QueryInterface(
Components.interfaces.nsIFileURL ).file.clone();
stampFile.leafName += ".last_sync";
return stampFile;
},
getStamp:
function()
{
var dtStamp = null;
if (CACHE == "memory") {
var stamp = g_localCalsLastSync[this.getCalKey()];
if (stamp) // return null if undefined
dtStamp = stamp;
}
else {
var stampFile = this.getStampFile();
if (stampFile.exists()) {
dtStamp = new CalDateTime();
dtStamp.jsDate = new Date(stampFile.lastModifiedTime); // is UTC
}
}
return dtStamp;
},
updateStamp:
function( dtStamp )
{
if (CACHE == "memory") {
g_localCalsLastSync[this.getCalKey()] = dtStamp.clone();
}
else {
var stampFile = this.getStampFile();
// xxx todo: setting lastModifiedTime does not work
// (at least not on Windows)
// stampFile.lastModifiedTime = (dtStamp.nativeTime / 1000);
// xxx todo: changes inbetween get lost!
if (stampFile.exists())
stampFile.remove(false);
stampFile.create(
Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0700 );
}
if (LOG_LEVEL > 0) {
var st = dtStamp;
if (stampFile) {
st = new CalDateTime();
st.jsDate = new Date(stampFile.lastModifiedTime); // is UTC
}
this.log( "updated stamp to " + dtStamp + "\n\tnew stamp: " + st );
}
},
m_syncQueue: null,
sync:
function( iListener )
{
this.log( "sync(): queueing request." );
// serialize sync() calls into queue:
var this_ = this;
this.m_syncQueue.postRequest(
function( requestToken ) {
this_.sync_req( requestToken, iListener );
} );
},
sync_req:
function( requestToken, iListener )
{
try {
var this_ = this;
var localCal = this.localCal;
var remoteCal = this.remoteCal;
var dtFrom = this.getStamp();
const SYNC = Components.interfaces.calIWcapCalendar.SYNC;
// first sync in changes from remote, then get items from locally:
remoteCal.syncChangesTo(
localCal, dtFrom,
{ // calIOperationListener:
onOperationComplete:
function( calendar, status, opType, id, detail )
{
try {
if (status == Components.results.NS_OK) {
if (opType == SYNC) {
// write stamp: only if necessary
if (dtFrom == null ||
dtFrom.compare(detail) != 0) {
this_.updateStamp( detail );
}
if (iListener != null) {
iListener.onOperationComplete(
this_.superCalendar,
Components.results.NS_OK,
SYNC, null, null );
}
}
else {
throw new Error(
"unexpected operation type! " +
"(expected SYNC)" );
}
}
else {
if (iListener != null) // forward errors:
iListener.onOperationComplete(
calendar, status,
opType, id, detail );
// already notified in wcap cal:
// this_.notifyError( detail );
}
}
catch (exc) {
if (iListener != null) {
iListener.onOperationComplete(
this_.superCalendar,
Components.results.NS_ERROR_FAILURE,
SYNC, null, exc );
}
this_.notifyError( exc );
}
this_.m_syncQueue.requestCompleted( requestToken );
},
onGetResult:
function( calendar, status, itemType, detail, count, items )
{
this_.notifyError( "unexpected onGetResult upon " +
"calling syncChangesTo()!" );
}
} );
}
catch (exc) {
if (iListener != null) {
iListener.onOperationComplete(
this.superCalendar, Components.results.NS_ERROR_FAILURE,
SYNC, null, exc );
}
this.notifyError( exc );
this.m_syncQueue.requestCompleted( requestToken );
}
this.log( "sync_req() returning." );
}
};
function ObserverMultiplexer( calendar ) {
this.wrappedJSObject = this;
this.m_calendar = calendar;
}
ObserverMultiplexer.prototype = {
m_calendar: null,
// calIObserver:
onStartBatch:
function()
{
this.m_calendar.notifyObservers( "onStartBatch", [] );
},
onEndBatch:
function()
{
this.m_calendar.notifyObservers( "onEndBatch", [] );
},
onLoad:
function()
{
this.m_calendar.notifyObservers( "onLoad", [] );
},
onAddItem:
function( item )
{
this.m_calendar.notifyObservers( "onAddItem", [item] );
},
onModifyItem:
function( newItem, oldItem )
{
this.m_calendar.notifyObservers( "onModifyItem", [newItem, oldItem] );
},
onDeleteItem:
function( item )
{
this.m_calendar.notifyObservers( "onDeleteItem", [item] );
},
onAlarm:
function( item )
{
this.m_calendar.notifyObservers( "onAlarm", [item] );
},
onError:
function( errNo, msg )
{
this.m_calendar.notifyObservers( "onError", [errNo, msg] );
}
};

View File

@ -0,0 +1,591 @@
/* -*- Mode: javascript; 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 ***** */
function calWcapCalendar() {
this.wrappedJSObject = this;
this.m_observers = [];
}
calWcapCalendar.prototype = {
m_ifaces: [ Components.interfaces.calIWcapCalendar,
Components.interfaces.calICalendar,
Components.interfaces.nsIInterfaceRequestor,
Components.interfaces.nsIClassInfo,
Components.interfaces.nsISupports ],
// 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.WcapCalendarInfo.classDescription;
},
get contractID() {
return calWcapCalendarModule.WcapCalendarInfo.contractID;
},
get classID() {
return calWcapCalendarModule.WcapCalendarInfo.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()
{
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);
}
return str;
},
log:
function( msg, context )
{
return logMessage( context ? context : this.toString(), msg );
},
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.");
}
}
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] );
},
// calICalendar:
get name() {
return getCalendarManager().getCalendarPref( this, "NAME" );
},
set name( name ) {
getCalendarManager().setCalendarPref( this, "NAME", name );
},
get type() { return "wcap"; },
m_superCalendar: null,
get superCalendar() { return this.m_superCalendar || this; },
set superCalendar( cal ) { this.m_superCalendar = cal; },
m_bReadOnly: false,
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();
}
},
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 );
}
},
removeObserver:
function( observer )
{
this.m_observers = this.m_observers.filter(
function(x) { return x != observer; } );
},
// xxx todo: batch currently not used
startBatch: function() { this.notifyObservers( "onStartBatch", [] ); },
endBatch: function() { this.notifyObservers( "onEndBatch", [] ); },
m_bSuppressAlarms: true /* xxx todo:
off for now until all problems are solved */,
get suppressAlarms() {
return (this.m_bSuppressAlarms || this.readOnly);
},
set suppressAlarms( bSuppressAlarms ) {
this.m_bSuppressAlarms = bSuppressAlarms;
},
get canRefresh() { return false; },
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, ignoredWcapErrors )
{
var sessionId = this.session.getSessionId();
if (sessionId == null)
return; // return silently, ignore error
var this_ = this;
issueFunc(
url + ("&id=" + sessionId),
function( utf8Data ) {
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 again:
this_.issueRequest(
url, issueFunc, dataConvFunc,
receiverFunc, ignoredWcapErrors );
return;
} // else notify error
}
else if (ignoredWcapErrors) {
for each ( var err in ignoredWcapErrors ) {
if (err == errno) {
errno = 0; // patch to OK
break;
}
}
}
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;
}
receiverFunc( wcapResponse );
} );
},
issueAsyncRequest:
function( url, dataConvFunc, receiverFunc, ignoredWcapErrors )
{
this.issueRequest( url, issueAsyncUtf8Request,
dataConvFunc, receiverFunc, ignoredWcapErrors );
},
issueSyncRequest:
function( url, dataConvFunc, receiverFunc, ignoredWcapErrors )
{
var ret;
this.issueRequest(
url, issueSyncUtf8Request,
dataConvFunc,
function( wcapResponse ) {
ret = wcapResponse;
if (receiverFunc) {
receiverFunc( wcapResponse );
}
}, ignoredWcapErrors );
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 getWcapErrorCodeString(rc);
},
// 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
return this.m_calId || userId;
},
set calId( id ) {
this.log( "setting calId to " + id );
this.m_calId = id;
},
get userId() { return this.session.userId; },
get isOwnedCalendar() {
return (this.calId == this.userId ||
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);
},
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;
},
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 );
}
out_count.value = ret.length;
return ret;
},
getOwnedCalendars:
function( out_count )
{
return this.getCalIds( out_count, true );
},
getSubscribedCalendars:
function( out_count )
{
return this.getCalIds( out_count, false );
},
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]);
}
url += ("&calid=" + calId);
var xml = this.issueSyncRequest(
url + "&fmt-out=text%2Fxml", utf8ToXml ).data;
},
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
// don't notify if one of ignored errors: 28, 29
var errno = getWcapXmlErrno(xml);
if (errno == 0 && 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(
requestId, calId, ret.length, ret );
}
if (LOG_LEVEL > 0) {
this.log( "getFreeBusyTimes_resp() calId=" + calId + ", " +
getWcapRequestStatusString(xml) );
}
}
catch (exc) {
this.notifyError( exc );
}
},
getFreeBusyTimes:
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 {
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, utf8ToXml, resp,
[28 /* ignore ACCESS_DENIED_TO_CALENDAR */,
29 /* ignore CALENDAR_DOES_NOT_EXIST */] );
}
else {
this.issueSyncRequest(
url, utf8ToXml, resp,
[28 /* ignore ACCESS_DENIED_TO_CALENDAR */,
29 /* ignore CALENDAR_DOES_NOT_EXIST */] );
}
}
catch (exc) {
this.notifyError( exc );
throw exc;
}
},
// 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");
if (tzid.length < 1) {
return "UTC"; // fallback
}
return tzid[0];
},
// set defaultTimezone( tzid ) {
// if (this.readOnly)
// throw Components.interfaces.calIErrors.CAL_IS_READONLY;
// this.ensureOnline();
// // xxx todo:
// throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
// },
getAlignedTimezone:
function( tzid )
{
// check whether it is one of cs:
if (tzid.indexOf("/mozilla.org/20050126_1/") == 0 ||
!this.session.isSupportedTimezone(tzid)) {
// use calendar's default:
return this.defaultTimezone;
}
else // is ok (supported):
return tzid;
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
/* -*- Mode: javascript; 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 ***** */
var calWcapCalendarModule = {
WcapCalendarInfo: {
classDescription: "Sun Java System Calendar Server WCAP Provider",
contractID: "@mozilla.org/calendar/calendar;1?type=wcap",
classID: Components.ID("{CF4D93E5-AF79-451a-95F3-109055B32EF0}")
},
registerSelf:
function( compMgr, fileSpec, location, type )
{
compMgr = compMgr.QueryInterface(
Components.interfaces.nsIComponentRegistrar );
compMgr.registerFactoryLocation(
this.WcapCalendarInfo.classID,
this.WcapCalendarInfo.classDescription,
this.WcapCalendarInfo.contractID,
fileSpec, location, type );
},
m_scriptsLoaded: false,
getClassObject:
function( compMgr, cid, iid )
{
if (! this.m_scriptsLoaded) {
this.m_scriptsLoaded = true;
// load scripts:
const scripts = [ "calWcapUtils.js", "calWcapErrors.js",
"calWcapRequest.js", "calWcapSession.js",
"calWcapCalendar.js", "calWcapCalendarItems.js",
"calWcapCachedCalendar.js" ];
var scriptLoader =
Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.createInstance(Components.interfaces.mozIJSSubScriptLoader);
var ioService =
Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
for each ( var script in scripts ) {
var scriptFile = __LOCATION__.parent.clone();
scriptFile.append(script);
scriptLoader.loadSubScript(
ioService.newFileURI(scriptFile).spec, null );
}
init(); // init first time
}
if (! cid.equals( calWcapCalendar.prototype.classID ))
throw Components.results.NS_ERROR_NO_INTERFACE;
if (! iid.equals( Components.interfaces.nsIFactory ))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
return {
createInstance:
function( outer, iid ) {
if (outer != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
var cal;
switch (CACHE) {
case "memory":
case "storage":
cal = new calWcapCachedCalendar();
break;
default:
cal = new calWcapCalendar();
break;
}
return cal.QueryInterface( iid );
}
};
},
canUnload: function( compMgr ) { return true; }
};
/** module export */
function NSGetModule( compMgr, fileSpec ) {
return calWcapCalendarModule;
}

View File

@ -0,0 +1,244 @@
/* -*- Mode: javascript; 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 ***** */
//
// WCAP error handling helpers
//
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.",
/* 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.",
/* 5 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 6 */ Components.interfaces.calIWcapErrors.WCAP_DELETE_EVENTS_BY_ID_FAILED, "Command failed.",
/* 7 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 8 */ Components.interfaces.calIWcapErrors.WCAP_SETCALPROPS_FAILED, "Command failed.",
/* 9 */ Components.interfaces.calIWcapErrors.WCAP_FETCH_EVENTS_BY_ID_FAILED, "Command failed.",
/* 10 */ Components.interfaces.calIWcapErrors.WCAP_CREATECALENDAR_FAILED, "Command failed.",
/* 11 */ Components.interfaces.calIWcapErrors.WCAP_DELETECALENDAR_FAILED, "Command failed.",
/* 12 */ Components.interfaces.calIWcapErrors.WCAP_ADDLINK_FAILED, "Command failed.",
/* 13 */ Components.interfaces.calIWcapErrors.WCAP_FETCHBYDATERANGE_FAILED, "Command failed.",
/* 14 */ Components.interfaces.calIWcapErrors.WCAP_STOREEVENTS_FAILED, "Command failed.",
/* 15 */ Components.interfaces.calIWcapErrors.WCAP_STORETODOS_FAILED, "Command failed.",
/* 16 */ Components.interfaces.calIWcapErrors.WCAP_DELETE_TODOS_BY_ID_FAILED, "Command failed.",
/* 17 */ Components.interfaces.calIWcapErrors.WCAP_FETCH_TODOS_BY_ID_FAILED, "Command failed.",
/* 18 */ Components.interfaces.calIWcapErrors.WCAP_FETCHCOMPONENTS_FAILED_BAD_TZID, "Command failed to find correct tzid. Applies to fetchcomponents_by_range.wcap, fetchevents_by_id.wcap, fetchtodos_by_id.wcap.",
/* 19 */ Components.interfaces.calIWcapErrors.WCAP_SEARCH_CALPROPS_FAILED, "Command failed.",
/* 20 */ Components.interfaces.calIWcapErrors.WCAP_GET_CALPROPS_FAILED, "Command failed.",
/* 21 */ Components.interfaces.calIWcapErrors.WCAP_DELETECOMPONENTS_BY_RANGE_FAILED, "Command failed.",
/* 22 */ Components.interfaces.calIWcapErrors.WCAP_DELETEEVENTS_BY_RANGE_FAILED, "Command failed.",
/* 23 */ Components.interfaces.calIWcapErrors.WCAP_DELETETODOS_BY_RANGE_FAILED, "Command failed.",
/* 24 */ Components.interfaces.calIWcapErrors.WCAP_GET_ALL_TIMEZONES_FAILED, "Command failed.",
/* 25 */ Components.interfaces.calIWcapErrors.WCAP_CREATECALENDAR_ALREADY_EXISTS_FAILED, "The command createcalendar.wcap failed. A calendar with that name already exists in the database.",
/* 26 */ Components.interfaces.calIWcapErrors.WCAP_SET_USERPREFS_FAILED, "Command failed.",
/* 27 */ Components.interfaces.calIWcapErrors.WCAP_CHANGE_PASSWORD_FAILED, "Command failed.",
/* 28 */ Components.interfaces.calIWcapErrors.WCAP_ACCESS_DENIED_TO_CALENDAR, "Command failed. The user is denied access to a calendar.",
/* 29 */ Components.interfaces.calIWcapErrors.WCAP_CALENDAR_DOES_NOT_EXIST, "Command failed. The requested calendar does not exist in the database.",
/* 30 */ Components.interfaces.calIWcapErrors.WCAP_ILLEGAL_CALID_NAME, "createcalendar.wcap failed. Invalid calid passed in.",
/* 31 */ Components.interfaces.calIWcapErrors.WCAP_CANNOT_MODIFY_LINKED_EVENTS, "storeevents.wcap failed. The event to modify was a linked event.",
/* 32 */ Components.interfaces.calIWcapErrors.WCAP_CANNOT_MODIFY_LINKED_TODOS, "storetodos.wcap failed. The todo to modify was a linked todo.",
/* 33 */ Components.interfaces.calIWcapErrors.WCAP_CANNOT_SENT_EMAIL, "Command failed. Email notification failed. Usually caused by the server not being properly configured to send email. This can occur in storeevents.wcap, storetodos.wcap, deleteevents_by_id.wcap, deletetodos_by_id.wcap.",
/* 34 */ Components.interfaces.calIWcapErrors.WCAP_CALENDAR_DISABLED, "Command failed. The calendar is disabled in the database.",
/* 35 */ Components.interfaces.calIWcapErrors.WCAP_WRITE_IMPORT_FAILED, "Import failed when writing files to the server.",
/* 36 */ Components.interfaces.calIWcapErrors.WCAP_FETCH_BY_LAST_MODIFIED_FAILED, "Command failed.",
/* 37 */ Components.interfaces.calIWcapErrors.WCAP_CAPI_NOT_SUPPORTED, "Failed trying to read from unsupported format calendar data.",
/* 38 */ Components.interfaces.calIWcapErrors.WCAP_CALID_NOT_SPECIFIED, "Calendar ID was not specified.",
/* 39 */ Components.interfaces.calIWcapErrors.WCAP_GET_FREEBUSY_FAILED, "Command failed.",
/* 40 */ Components.interfaces.calIWcapErrors.WCAP_STORE_FAILED_DOUBLE_BOOKED, "If double booking is not allowed in this calendar, storeevents.wcap fails with this error when attempting to store an event in a time slot that was already filled.",
/* 41 */ Components.interfaces.calIWcapErrors.WCAP_FETCH_BY_ALARM_RANGE_FAILED, "Command failed.",
/* 42 */ Components.interfaces.calIWcapErrors.WCAP_FETCH_BY_ATTENDEE_ERROR_FAILED, "Command failed.",
/* 43 */ Components.interfaces.calIWcapErrors.WCAP_ATTENDEE_GROUP_EXPANSION_CLIPPED, "An LDAP group being expanded was too large and exceeded the maximum number allowed in an expansion. The expansion stopped at the specified maximum limit. The maximum limit defaults to 200. To change the maximum limit, set the server configuration preference calstore.group.attendee.maxsize.",
/* 44 */ Components.interfaces.calIWcapErrors.WCAP_USERPREFS_ACCESS_DENIED, "Either the server does not allow this administrator access to get or modify user preferences, or the requester is not an administrator.",
/* 45 */ Components.interfaces.calIWcapErrors.WCAP_NOT_ALLOWED_TO_REQUEST_PUBLISH, "The requester was not an organizer of the event, and, therefore, is not allowed to edit the component using the PUBLISH or REQUEST method.",
/* 46 */ Components.interfaces.calIWcapErrors.WCAP_INSUFFICIENT_PARAMETERS, "The caller tried to invoke verifyevents_by_ids.wcap, or verifytodos_by_ids.wcap with insufficient arguments (mismatched number of uids and rids).",
/* 47 */ Components.interfaces.calIWcapErrors.WCAP_MUSTBEOWNER_OPERATION, "The user needs to be an owner or co-owner of the calendar in questions to complete this operation. (Probably related to private or confidential component.)",
/* 48 */ Components.interfaces.calIWcapErrors.WCAP_DWP_CONNECTION_FAILED, "GSE scheduling engine failed to make connection to DWP.",
/* 49 */ Components.interfaces.calIWcapErrors.WCAP_DWP_MAX_CONNECTION_REACHED, "Reached the maximum number of connections. When some of the connections are freed, users can successfully connect. Same as error 11001.",
/* 50 */ Components.interfaces.calIWcapErrors.WCAP_DWP_CANNOT_RESOLVE_CALENDAR, "Front end cant resolve to a particular back end. Same as error 11002.",
/* 51 */ Components.interfaces.calIWcapErrors.WCAP_DWP_BAD_DATA, "Generic response. Check all DWP servers. One might be down. Same as error 11003.",
/* 52 */ Components.interfaces.calIWcapErrors.WCAP_BAD_COMMAND, "The command sent in was not recognized. This is an internal only error code. It should not appear in the error logs.",
/* 53 */ Components.interfaces.calIWcapErrors.WCAP_NOT_FOUND, "Returned for all errors from a write to the Berkeley DB. This is an internal only error code. It should not appear in the error logs.",
/* 54 */ Components.interfaces.calIWcapErrors.WCAP_WRITE_IMPORT_CANT_EXPAND_CALID, "Cant expand calid when importing file.",
/* 55 */ Components.interfaces.calIWcapErrors.WCAP_GETTIME_FAILED, "Get server time failed.",
/* 56 */ Components.interfaces.calIWcapErrors.WCAP_FETCH_DELETEDCOMPONENTS_FAILED, "fetch_deletedcomponents.wcap failed.",
/* 57 */ Components.interfaces.calIWcapErrors.WCAP_FETCH_DELETEDCOMPONENTS_PARTIAL_RESULT, "Success but partial result.",
/* 58 */ Components.interfaces.calIWcapErrors.WCAP_WCAP_NO_SUCH_FORMAT, "Returned in any of the commands when supplied fmt-out is not a supported format.",
/* 59 */ Components.interfaces.calIWcapErrors.WCAP_COMPONENT_NOT_FOUND, "Returned when a fetch or delete is attempted that does not exist.",
/* 60 */ Components.interfaces.calIWcapErrors.WCAP_BAD_ARGUMENTS, "Currently used when attendee or organizer specified does not have a valid email address.",
/* 61 */ Components.interfaces.calIWcapErrors.WCAP_GET_USERPREFS_FAILED, "get_userprefs.wcap failed. The following error conditions returns error code 61: LDAP access denied, no results found, LDAP limit exceeded, LDAP connection failed.",
/* 62 */ Components.interfaces.calIWcapErrors.WCAP_WCAP_MODIFY_NO_EVENT, "storeevents.wcap issued with storeytype set to 2 (WCAP_STORE_TYPE_MODIFY) and the event doesn\t exist.",
/* 63 */ Components.interfaces.calIWcapErrors.WCAP_WCAP_CREATE_EXISTS, "storeevents.wcap issued with storetype set to 1 (WCAP_STORE_TYPE_CREATE) and the event already exists.",
/* 64 */ Components.interfaces.calIWcapErrors.WCAP_WCAP_MODIFY_CANT_MAKE_COPY, "storevents.wcap issued and copy of event failed during processing.",
/* 65 */ Components.interfaces.calIWcapErrors.WCAP_STORE_FAILED_RECUR_SKIP, "One instance of a recurring event skips over another.",
/* 66 */ Components.interfaces.calIWcapErrors.WCAP_STORE_FAILED_RECUR_SAMEDAY, "Two instances of a recurring event cant occur on the same day.",
/* 67 */ Components.interfaces.calIWcapErrors.WCAP_BAD_ORG_ARGUMENTS, "Bad organizer arguments. orgCalid or orgEmail must be passed if any other \"org\" parameter is sent. That is, orgUID cant be sent alone on a storeevents.wcap or a storetodos.wcao command if it is trying about to \"create\" the event or task. Note, if no \"org\" information is passed, the organizer defaults to the calid being passed with the command.",
/* 68 */ Components.interfaces.calIWcapErrors.WCAP_STORE_FAILED_RECUR_PRIVACY, "Error returned if you try to change the privacy or transparency of a single instance in a recurring series.",
/* 69 */ Components.interfaces.calIWcapErrors.WCAP_LDAP_ERROR, "For get_calprops.wcap, when there is an error is getting LDAP derived token values (X-S1CS-CALPROPS-FB-INCLUDE, X-S1CS-CALPROPS-COMMON-NAME).",
/* 70 */ Components.interfaces.calIWcapErrors.WCAP_GET_INVITE_COUNT_FAILED, "Error in getting invite count (for get_calprops.wcap and fetchcomponents_by_range.wcap commands).",
/* 71 */ Components.interfaces.calIWcapErrors.WCAP_LIST_FAILED, "list.wcap failed.",
/* 72 */ Components.interfaces.calIWcapErrors.WCAP_LIST_SUBSCRIBED_FAILED, "list_subscribed.wcap failed.",
/* 73 */ Components.interfaces.calIWcapErrors.WCAP_SUBSCRIBE_FAILED, "subscribe.wcap failed.",
/* 74 */ Components.interfaces.calIWcapErrors.WCAP_UNSUBSCRIBE_FAILED, "unsubscribe.wcap failed.",
/* 75 */ Components.interfaces.calIWcapErrors.WCAP_ANONYMOUS_NOT_ALLOWED, "Command cannot be executed as anonymous. Used only for list.wcap, list_subscribed.wcap, subscribe.wcap, and unsubscribe.wcap commands.",
/* 76 */ Components.interfaces.calIWcapErrors.WCAP_ACCESS_DENIED, "Generated if a non-administrator user tries to read or set the calendar-owned list or the calendar-subscribed list of some other user, or if the option is not turned on in the server.",
/* 77 */ Components.interfaces.calIWcapErrors.WCAP_BAD_IMPORT_ARGUMENTS, "Incorrect parameter received by import.wcap.",
/* 78 */ Components.interfaces.calIWcapErrors.WCAP_READONLY_DATABASE, "Database is in read-only mode (returned for all attempts to write to the database).",
/* 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.",
/* 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.",
/* 91 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 92 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 93 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 94 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 95 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 96 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 97 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 98 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 99 */ Components.results.NS_ERROR_INVALID_ARG, "No WCAP error code.",
/* 11000 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_MAX_CONNECTION_REACHED, "Maximum connections to back-end database reached. As connections are freed up, users can connect to the back-end.",
/* 11001 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_CANNOT_CONNECT, "Cannot connect to back-end server. Back-end machine might be down or DWP server is not up and running.",
/* 11002 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_CANNOT_RESOLVE_CALENDAR, "Front-end cant resolve calendar to a particular back-end server.",
/* 11003 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_BAD_DATA, "Bad data received from DWP connection. This is a generic formatting error. Check all DWP servers. One might be down.",
/* 11004 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_DWPHOST_CTX_DOES_NOT_EXIST, "For the back-end host, context doesn\t exist in the context table.",
/* 11005 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_HOSTNAME_NOT_RESOLVABLE, "DNS or NIS files, or hostname resolver is not set up properly or machine does not exist.",
/* 11006 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_NO_DATA, "No data was received from reading the calendar properties from the DWP connection.",
/* 11007 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_AUTH_FAILED, "DWP authentication failed.",
/* 11008 */ Components.interfaces.calIWcapErrors.WCAP_CDWP_ERR_CHECKVERSION_FAILED, "DWP version check failed."
];
function getWcapErrorIndex( errno )
{
var index = -1;
if (errno >= -1 && errno <= 81)
index = (errno + 1);
else if (errno >= 11000 && errno <= 11008)
index = (errno - 11000 + 100 + 1);
if (index >= 0 &&
g_wcapErrorCodes[index * 2] != Components.results.NS_ERROR_INVALID_ARG)
{
return index;
}
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];
}
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;
}
}
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;
}
}
function checkWcapErrno( errno, expectedErrno )
{
if (expectedErrno == undefined) {
expectedErrno = 0;
}
if (errno != expectedErrno) {
throw getWcapErrorCode(errno);
}
}
function checkWcapXmlErrno( xml, expectedErrno )
{
checkWcapErrno( getWcapXmlErrno(xml), expectedErrno );
}
function checkWcapIcalErrno( icalRootComp, expectedErrno )
{
checkWcapErrno( getWcapIcalErrno(icalRootComp), expectedErrno );
}

View File

@ -0,0 +1,241 @@
/* -*- Mode: javascript; 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 ***** */
//
// WCAP request helpers
//
function getWcapRequestStatusString( xml )
{
var str = "request status: ";
var items = xml.getElementsByTagName("RSTATUS");
if (items != null && items.length > 0)
str += items.item(0).textContent;
else
str += "none";
return str;
}
// response object for Calendar.issueRequest()
function WcapResponse() {
}
WcapResponse.prototype = {
m_response: null,
m_exc: null,
get data() {
if (this.m_exc != null)
throw this.m_exc;
return this.m_data;
},
set data(d) {
this.m_data = d;
this.m_exc = null;
},
set exception(exc) {
this.m_exc = exc;
}
};
function utf8ToIcal( utf8Data, wcapResponse )
{
if (!utf8Data || utf8Data == "")
return 1; // assuming session timeout
var icalRootComp = getIcsService().parseICS( utf8Data );
wcapResponse.data = icalRootComp;
return getWcapIcalErrno( icalRootComp );
}
function utf8ToXml( utf8Data, wcapResponse )
{
if (!utf8Data || utf8Data == "")
return 1; // assuming session timeout
var xml = getDomParser().parseFromString( utf8Data, "text/xml");
wcapResponse.data = xml;
return getWcapXmlErrno( xml );
}
function Utf8Reader( url, receiverFunc ) {
this.wrappedJSObject = this;
this.m_url = url;
this.m_receiverFunc = receiverFunc;
}
Utf8Reader.prototype = {
m_url: null,
m_receiverFunc: null,
// nsIUnicharStreamLoaderObserver:
onDetermineCharset:
function( loader, context, firstSegment, length )
{
return "UTF-8";
},
onStreamComplete:
function( loader, context, status, /* nsIUnicharInputStream */ unicharData )
{
if (status == Components.results.NS_OK) {
var str = "";
var str_ = {};
while (unicharData.readString( -1, str_ )) {
str += str_.value;
}
if (LOG_LEVEL > 1) {
logMessage( "issueAsyncUtf8Request( \"" + this.m_url + "\" )",
"request result: " + str );
}
this.m_receiverFunc( str );
}
}
};
function issueAsyncUtf8Request( url, receiverFunc )
{
var reader = null;
if (receiverFunc != null) {
reader = new Utf8Reader( url, receiverFunc );
}
var loader =
Components.classes["@mozilla.org/network/unichar-stream-loader;1"]
.createInstance(Components.interfaces.nsIUnicharStreamLoader);
logMessage( "issueAsyncUtf8Request( \"" + url + "\" )", "opening channel.");
var channel = getIoService().newChannel(
url, "UTF-8" /* charset */, null /* baseURI */ );
loader.init( channel, reader, null /* context */, 0 /* segment size */ );
}
function streamToUtf8String( inStream )
{
// byte-array to utf8 string:
var convStream =
Components.classes["@mozilla.org/intl/converter-input-stream;1"]
.createInstance(Components.interfaces.nsIConverterInputStream);
convStream.init( inStream, "UTF-8", 0, 0x0000 );
var str = "";
var str_ = {};
while (convStream.readString( -1, str_ )) {
str += str_.value;
}
return str;
}
function issueSyncUtf8Request( url, receiverFunc, bLogging )
{
if (bLogging == undefined)
bLogging = true;
if (bLogging && LOG_LEVEL > 0) {
logMessage( "issueSyncUtf8Request( \"" + url + "\" )",
"opening channel." );
}
var channel = getIoService().newChannel(
url, "UTF-8" /* charset */, null /* baseURI */ );
var stream = channel.open();
var status = channel.status;
if (status == Components.results.NS_OK) {
var str = streamToUtf8String( stream );
if (bLogging && LOG_LEVEL > 1) {
logMessage( "issueSyncUtf8Request( \"" + url + "\" )",
"returned: " + str );
}
if (receiverFunc != null) {
receiverFunc( str );
}
return str;
}
else if (bLogging && LOG_LEVEL > 0) {
logMessage( "issueSyncUtf8Request( \"" + url + "\" )",
"failed: " + status );
}
return null;
}
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;
}
return null;
}
// response object for Calendar.issueRequest()
function RequestQueue() {
this.m_requests = [];
}
RequestQueue.prototype = {
m_requests: null,
m_token: 0,
postRequest:
function( func )
{
var token = this.m_token;
this.m_token += 1;
this.m_requests.push( { m_token: token, m_func: func } );
var len = this.m_requests.length;
logMessage( "RequestQueue::postRequest()",
"queueing request. token=" + token +
", open requests=" + len );
if (len == 1) {
func( token );
}
},
requestCompleted:
function( requestToken )
{
var len_ = this.m_requests.length;
this.m_requests = this.m_requests.filter(
function(x) { return x.m_token != requestToken; } );
var len = this.m_requests.length;
logMessage( "RequestQueue::requestCompleted()",
"token=" + requestToken +
((len > 0 && len_ == len) ? "(expired !!!)" : "") +
", open requests=" + len );
if (len > 0) {
var entry = this.m_requests[0];
entry.m_func( entry.m_token );
}
}
};

View File

@ -0,0 +1,593 @@
/* -*- Mode: javascript; 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 ***** */
// globals:
var g_serverTimeDiffs = {};
var g_allSupportedTimezones = {};
function calWcapSession( thatUri ) {
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 = "";
// 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);
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,
get uri() { return this.m_uri; },
toString:
function( msg )
{
var str = this.uri.spec;
if (this.m_userId != null) {
str += (", userId=" + this.userId);
}
if (this.m_sessionId == null) {
str += (getIoService().offline ? ", offline" : ", not logged in");
}
// else {
// str += (", session-id=" + this.m_sessionId);
// }
return str;
},
log:
function( msg )
{
return logMessage( this.toString(), msg );
},
// nsISupports:
QueryInterface:
function( iid )
{
if (iid.equals(Components.interfaces.nsIObserver) ||
iid.equals(Components.interfaces.nsISupports)) {
return this;
}
else
throw Components.results.NS_ERROR_NO_INTERFACE;
},
// nsIObserver:
observe:
function( subject, topic, data )
{
this.log( "observing: " + topic + ", data: " + data );
if (topic == "network:offline-about-to-go-offline") {
this.logout();
}
else if (topic == "quit-application") {
// xxx todo: valid upon notification?
var observerService =
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.removeObserver(
this, "quit-application" );
observerService.removeObserver(
this, "network:offline-about-to-go-offline" );
}
},
get userId() { return this.m_userId; },
getSupportedTimezones:
function( bRefresh )
{
var key = this.uri.hostPort;
if ((bRefresh || !g_allSupportedTimezones[key]) &&
this.m_sessionId != null)
{
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 icalRootComp = getIcsService().parseICS( str );
if (icalRootComp == null)
throw new Error("invalid data!");
checkWcapIcalErrno( icalRootComp );
var tzids = [];
var this_ = this;
forEachIcalComponent(
icalRootComp, "VTIMEZONE",
function( subComp ) {
try {
var tzCal = getIcsService().createIcalComponent(
"VCALENDAR" );
subComp = subComp.clone();
tzCal.addSubcomponent( subComp );
getIcsService().addTimezone( tzCal, "", "" );
tzids.push( subComp.getFirstProperty("TZID").value );
}
catch (exc) { // ignore errors:
this_.log( "error: " + exc );
}
} );
g_allSupportedTimezones[key] = tzids;
}
return g_allSupportedTimezones[key];
},
getServerTime:
function( localTime )
{
var ret = (localTime ? localTime.clone() : getTime());
ret.addDuration( this.getServerTimeDiff() );
return ret;
},
getServerTimeDiff:
function( bRefresh )
{
var key = this.uri.hostPort;
if ((bRefresh || !g_serverTimeDiffs[key]) &&
this.m_sessionId != null) {
var url = this.uri.spec +
// xxx todo: assuming same diff for all calids:
"gettime.wcap?appid=mozilla-lightning" +
"&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 icalRootComp = getIcsService().parseICS( str );
if (icalRootComp == null)
throw new Error("invalid data!");
checkWcapIcalErrno( icalRootComp );
var serverTime = getDatetimeFromIcalProp(
icalRootComp.getFirstProperty( "X-NSCP-WCAPTIME" ) );
var diff = serverTime.subtractDate( localTime );
this.log( "server time diff is: " + diff );
g_serverTimeDiffs[key] = diff;
}
return g_serverTimeDiffs[key];
},
isSupportedTimezone:
function( tzid )
{
var tzids = this.getSupportedTimezones();
for each ( var id in tzids ) {
if (id == tzid)
return true;
}
return false;
},
getRealmName:
function( uri )
{
// xxx todo: realm names must not have a trailing slash
var realm = uri.spec;
if (realm[realm.length - 1] == '/')
realm = realm.substr(0, realm.length - 1);
return realm;
},
getSessionId:
function( timedOutSessionId )
{
if (this.m_bNoLoginsAnymore) {
this.log( "login has failed, no logins anymore for this user." );
return null;
}
if (getIoService().offline) {
this.log( "in offline mode." );
return null;
}
if (this.m_sessionId == null || this.m_sessionId == timedOutSessionId) {
// xxx todo: ask dmose how to do better...
// possible HACK here, because of lack of sync possibilities:
// when we run into executing dialogs, the js runtime
// concurrently executes (another getItems() request).
// That concurrent request needs to wait for the first login
// attempt to finish.
// Creating a thread event queue somehow hinders the js engine
// from scheduling another js execution.
var eventQueueService =
Components.classes["@mozilla.org/event-queue-service;1"]
.getService(Components.interfaces.nsIEventQueueService);
var eventQueue = eventQueueService.pushThreadEventQueue();
try {
if (this.m_sessionId == null ||
this.m_sessionId == timedOutSessionId)
{
if (timedOutSessionId != null) {
this.m_sessionId = null;
this.log( "session timeout; prompting to reconnect." );
var prompt = getWindowWatcher().getNewPrompter(null);
var bundle = getBundle();
if (! prompt.confirm(
bundle.GetStringFromName(
"reconnectConfirmation.label" ),
bundle.formatStringFromName(
"reconnectConfirmation.text",
[this.uri.hostPort], 1 ) )) {
this.m_bNoLoginsAnymore = true;
}
}
if (! this.m_bNoLoginsAnymore)
this.getSessionId_();
this.getSupportedTimezones( true /* refresh */ );
this.getServerTimeDiff( true /* refresh */ );
}
}
catch (exc) {
eventQueueService.popThreadEventQueue( eventQueue );
throw exc;
}
eventQueueService.popThreadEventQueue( eventQueue );
}
return this.m_sessionId;
},
getSessionId_:
function()
{
if (this.m_sessionId == null) {
var passwordManager =
Components.classes["@mozilla.org/passwordmanager;1"]
.getService(Components.interfaces.nsIPasswordManager);
var outUser = { value: this.m_userId };
var outPW = { value: null };
var enumerator = passwordManager.enumerator;
var realm = this.getRealmName(this.uri);
while (enumerator.hasMoreElements()) {
var pwEntry = enumerator.getNext().QueryInterface(
Components.interfaces.nsIPassword );
if (LOG_LEVEL > 1) {
this.log( "pw entry:\n\thost=" + pwEntry.host +
"\n\tuser=" + pwEntry.user );
}
if (pwEntry.host == realm) { // found an entry matching URI:
outUser.value = pwEntry.user;
outPW.value = pwEntry.password;
break;
}
}
var loginUri = this.uri.clone();
if (loginUri.scheme.toLowerCase() != "https") {
if (loginUri.port == -1) {
// no https, but no port specified
// => enforce login via https:
loginUri.scheme = "https";
}
else {
// user has specified a specific port, but no https:
// => leave it to her whether to connect...
if (! confirmUnsecureLogin( loginUri )) {
this.m_bNoLoginsAnymore = true;
this.log( "user rejected unsecure login." );
return null;
}
}
}
if (outUser.value == null || outPW.value == null) {
this.log( "no password entry found." );
}
else {
this.log( "password entry found for user " + outUser.value );
try {
this.login( loginUri, outUser.value, outPW.value );
}
catch (exc) { // ignore silently
}
}
if (this.m_sessionId == null) {
// preparing login:
var loginText = null;
try {
loginText = this.getServerInfo( loginUri );
if (loginText == null) {
if (loginUri.scheme.toLowerCase() == "https") {
// gathering server info via https has failed,
// try http:
loginUri.scheme = "http";
loginText = this.getServerInfo( loginUri );
}
if (loginText == null) {
throw new Error(
getBundle().formatStringFromName(
"accessingServerFailedError.text",
[loginUri.hostPort], 1 ) );
}
if (this.uri.scheme.toLowerCase() == "https") {
// user specified https, so http is no option:
loginText = null;
throw new Error(
getBundle() .formatStringFromName(
"mandatoryHttpsError.text",
[loginUri.hostPort], 1 ) );
}
// http possible, ask for it:
if (confirmUnsecureLogin( loginUri )) {
if (outPW.value != null) {
// user/pw has been found previously,
// but no login was possible,
// try again using http here:
this.login( loginUri,
outUser.value, outPW.value );
if (this.m_sessionId != null)
return this.m_sessionId;
}
}
else {
this.m_bNoLoginsAnymore = true;
this.log( "user rejected unsecure login." );
return null;
}
}
}
catch (exc) {
Components.utils.reportError( exc );
if (loginText == null) {
// accessing server or invalid protocol,
// no logins anymore:
this.m_bNoLoginsAnymore = true;
throw exc; // propagate error message
}
// else maybe user pw has changed or similar...
}
if (outPW.value != null) {
// login failed before, so try to remove from pw db:
try {
passwordManager.removeUser(
this.getRealmName(this.uri), outUser.value );
}
catch (exc) {
this.log( "error removing from pw db: " + exc );
}
}
var savePW = { value: false };
while (this.m_sessionId == null) {
var prompt = getWindowWatcher().getNewPrompter(null);
if (prompt.promptUsernameAndPassword(
getBundle().GetStringFromName("loginDialog.label"),
loginText, outUser, outPW,
getBundle().GetStringFromName(
"loginDialog.savePW.label" ),
savePW ))
{
try {
this.login( loginUri, outUser.value, outPW.value );
}
catch (exc) {
Components.utils.reportError( exc );
// xxx todo: UI?
}
}
else { // dialog cancelled, don't login anymore:
this.m_bNoLoginsAnymore = true;
this.log( "login cancelled, will not prompt again." );
break;
}
}
if (this.m_sessionId != null && savePW.value) {
// save pw under session uri:
passwordManager.addUser( this.getRealmName(this.uri),
outUser.value, outPW.value );
}
}
}
return this.m_sessionId;
},
getServerInfo:
function( uri )
{
loginTextVars = [uri.hostPort];
var loginText;
var wcapVersion;
try {
// currently, xml parsing at an early stage during process startup
// does not work reliably, so use libical parsing for now:
var str = issueSyncUtf8Request(
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!");
var prop = icalRootComp.getFirstProperty( "PRODID" );
if (prop == null)
throw new Error("missing PRODID!");
loginTextVars.push( prop.value );
var prop = icalRootComp.getFirstProperty( "X-NSCP-SERVERVERSION" );
if (prop == null)
throw new Error("missing X-NSCP-SERVERVERSION!");
loginTextVars.push( prop.value );
var prop = icalRootComp.getFirstProperty( "X-NSCP-WCAPVERSION" );
if (prop == null)
throw new Error("missing X-NSCP-WCAPVERSION!");
wcapVersion = prop.value;
loginTextVars.push( wcapVersion );
// var xml = issueSyncXMLRequest(
// uri.spec + "version.wcap?fmt-out=text%2Fxml" );
// wcapVersion = xml.getElementsByTagName(
// "X-NSCP-WCAPVERSION" ).item(0).textContent;
// if (wcapVersion == undefined || wcapVersion == "")
// throw new Error("invalid response!");
// serverInfo =
// ("Server-Info: " +
// xml.getElementsByTagName(
// "iCal" ).item(0).attributes.getNamedItem(
// "prodid" ).value +
// ", v" + xml.getElementsByTagName(
// "X-NSCP-SERVERVERSION" ).item(0).textContent +
// ", WCAP v" + wcapVersion);
}
catch (exc) {
this.log( "error: " + exc );
return null;
}
if (parseInt(wcapVersion) < 2.0) {
this.log( "parsed server WCAP major: " + parseInt(wcapVersion) );
throw new Error(
getBundle("insufficientWcapVersionError.text", loginTextVars) );
}
return getBundle().formatStringFromName(
"loginDialog.text", loginTextVars, loginTextVars.length );
},
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 = issueSyncUtf8Request(
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" );
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." );
},
logout:
function()
{
if (this.m_sessionId != null) {
// although io service's offline flag is already
// set BEFORE notification (about to go offline, nsIOService.cpp).
// WTF.
var url = (this.uri.spec +
"logout.wcap?fmt-out=text%2Fxml&id=" + this.m_sessionId);
try {
checkWcapXmlErrno( issueSyncXMLRequest(url), -1 );
this.log( "WCAP logout succeeded." );
}
catch (exc) {
this.log( "WCAP logout failed: " + exc );
Components.utils.reportError( exc );
}
this.m_sessionId = 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;
}
};
g_httpHosts = [];
function confirmUnsecureLogin( uri )
{
var host = uri.hostPort;
for each ( var hostEntry in g_httpHosts ) {
if (hostEntry.m_host == host) {
return hostEntry.m_bConfirmed;
}
}
var prompt = getWindowWatcher().getNewPrompter(null);
var bundle = getBundle();
var bConfirmed = prompt.confirm(
bundle.GetStringFromName("noHttpsConfirmation.label"),
bundle.formatStringFromName("noHttpsConfirmation.text", [host], 1) );
// save decision for all calendars:
g_httpHosts.push(
{ m_host: host, m_bConfirmed: bConfirmed } );
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

@ -0,0 +1,335 @@
/* -*- Mode: javascript; 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 ***** */
// globals:
// ctors:
var CalEvent;
var CalTodo;
var CalDateTime;
var XmlHttpRequest;
// preferences:
// memory|storage:
var CACHE = "off"; // xxx todo: off by default for now
// denotes where to host local storage calendar(s)
var CACHE_DIR = null;
// logging:
#expand var LOG_LEVEL = __LOG_LEVEL__;
var LOG_TIMEZONE = null;
var LOG_FILE_STREAM = null;
function logMessage( context, msg )
{
if (LOG_LEVEL > 0) {
var now = getTime();
if (LOG_TIMEZONE != null)
now = now.getInTimezone(LOG_TIMEZONE);
var str = ("\n### WCAP log " + now + "\n### [" + context + "]\n### " +
(msg ? msg : ""));
getConsoleService().logStringMessage( str );
str += "\n\n";
dump( str );
if (LOG_FILE_STREAM != null) {
try {
// xxx todo?
// assuming ANSI chars here, for logging sufficient:
LOG_FILE_STREAM.write( str, str.length );
}
catch (exc) { // catching any io errors here:
var err = ("error writing log file: " + exc);
Components.utils.reportError( exc );
getConsoleService().logStringMessage( err );
dump( err + "\n\n" );
}
}
return str;
}
else
return msg;
}
function init()
{
try {
// ctors:
CalEvent = new Components.Constructor(
"@mozilla.org/calendar/event;1", "calIEvent" );
CalTodo = new Components.Constructor(
"@mozilla.org/calendar/todo;1", "calITodo" );
CalDateTime = new Components.Constructor(
"@mozilla.org/calendar/datetime;1", "calIDateTime" );
XmlHttpRequest = new Components.Constructor(
"@mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest" );
var prefService =
Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
var prefCalBranch = prefService.getBranch("calendar.");
try {
LOG_TIMEZONE = prefCalBranch.getCharPref("timezone.local");
}
catch (exc) {
}
var logLevel = 0;
try {
logLevel = prefCalBranch.getIntPref( "wcap.log_level" );
}
catch (exc) {
}
if (logLevel > LOG_LEVEL) {
LOG_LEVEL = logLevel;
}
if (LOG_LEVEL > 0) {
try {
var logFileName = prefCalBranch.getCharPref("wcap.log_file");
if (logFileName != null) {
// set up file:
var logFile =
Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
logFile.initWithPath( logFileName );
// create output stream:
var logFileStream = Components.classes[
"@mozilla.org/network/file-output-stream;1"]
.createInstance(
Components.interfaces.nsIFileOutputStream);
logFileStream.init(
logFile,
0x02 /* PR_WRONLY */ |
0x08 /* PR_CREATE_FILE */ |
0x10 /* PR_APPEND */,
0700 /* read, write, execute/search by owner */,
0 /* unused */ );
LOG_FILE_STREAM = logFileStream;
}
}
catch (exc) {
}
logMessage( "init()",
"################################# NEW LOG " +
"#################################" );
}
// init cache dir directory:
try {
CACHE = prefCalBranch.getCharPref( "wcap.cache" );
}
catch (exc) {
}
logMessage( "calendar.wcap.cache", CACHE );
if (CACHE == "storage") {
var cacheDir = null;
try {
var sCacheDir = prefCalBranch.getCharPref( "wcap.cache_dir" );
cacheDir = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
cacheDir.initWithPath( sCacheDir );
}
catch (exc) { // not found: default to wcap/ directory in profile
var dirService = Components.classes[
"@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties);
cacheDir = dirService.get(
"ProfD", Components.interfaces.nsILocalFile );
cacheDir.append( "wcap" );
}
CACHE_DIR = cacheDir;
logMessage( "calendar.wcap.cache_dir", CACHE_DIR.path );
if (! CACHE_DIR.exists()) {
CACHE_DIR.create(
Components.interfaces.nsIFile.DIRECTORY_TYPE,
0700 /* read, write, execute/search by owner */ );
}
}
}
catch (exc) {
logMessage( "error in init()", exc );
}
}
// late-init service accessors:
var g_consoleService = null;
function getConsoleService()
{
if (g_consoleService == null) {
g_consoleService = Components.classes["@mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService);
}
return g_consoleService;
}
var g_windowWatcher = null;
function getWindowWatcher()
{
if (g_windowWatcher == null) {
g_windowWatcher =
Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
}
return g_windowWatcher;
}
var g_ioService = null;
function getIoService()
{
if (g_ioService == null) {
g_ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
}
return g_ioService;
}
var g_icsService = null;
function getIcsService()
{
if (g_icsService == null) {
g_icsService = Components.classes["@mozilla.org/calendar/ics-service;1"]
.getService(Components.interfaces.calIICSService);
}
return g_icsService;
}
var g_domParser = null;
function getDomParser()
{
if (g_domParser == null) {
g_domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
.getService(Components.interfaces.nsIDOMParser);
}
return g_domParser;
}
var g_calendarManager = null;
function getCalendarManager()
{
if (g_calendarManager == null) {
g_calendarManager =
Components.classes["@mozilla.org/calendar/manager;1"]
.getService(Components.interfaces.calICalendarManager);
}
return g_calendarManager;
};
var g_bundle = null;
function getBundle()
{
if (g_bundle == null) {
var stringBundleService =
Components.classes["@mozilla.org/intl/stringbundle;1"]
.getService(Components.interfaces.nsIStringBundleService);
g_bundle = stringBundleService.createBundle(
"chrome://calendar/locale/wcap.properties" );
}
return g_bundle;
}
function isEvent( item )
{
var bRet = (item instanceof Components.interfaces.calIEvent);
if (!bRet && !(item instanceof Components.interfaces.calITodo)) {
throw new Error("item is no calIEvent nor calITodo!");
}
return bRet;
}
function forEachIcalComponent( icalRootComp, componentType, func, maxResult )
{
var itemCount = 0;
// libical returns the vcalendar component if there is just
// one vcalendar. If there are multiple vcalendars, it returns
// an xroot component, with those vcalendar childs. We need to
// handle both.
for ( var calComp = (icalRootComp.componentType == "VCALENDAR"
? icalRootComp
: icalRootComp.getFirstSubcomponent("VCALENDAR"));
calComp != null && (!maxResult || itemCount < maxResult);
calComp = icalRootComp.getNextSubcomponent("VCALENDAR") )
{
for ( var subComp = calComp.getFirstSubcomponent(componentType);
subComp != null && (!maxResult || itemCount < maxResult);
subComp = calComp.getNextSubcomponent(componentType) )
{
func( subComp );
++itemCount;
}
}
}
function getTime()
{
var ret = new CalDateTime();
ret.jsDate = new Date();
return ret;
}
function getIcalUTC( dt )
{
if (! dt)
return "0";
else {
var dtz = dt.timezone;
if (dtz == "UTC" || dtz == "floating")
return dt.icalString;
else
return dt.getInTimezone("UTC").icalString;
}
}
function getDatetimeFromIcalProp( prop )
{
if (! prop)
return null;
var val = prop.valueAsIcalString;
if (val.length == 0 || val == "0")
return null;
// assuming timezone is known:
var dt = new CalDateTime();
dt.icalString = val;
// dt.makeImmutable();
return dt;
}

View File

@ -0,0 +1,56 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 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 *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = wcap
XPIDL_MODULE = wcap
XPIDLSRCS = calIWcapCalendar.idl \
calIWcapErrors.idl \
calIWcapFreeBusyEntry.idl \
calIWcapFreeBusyListener.idl \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,198 @@
/* -*- 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 "calICalendar.idl"
#include "calIWcapFreeBusyListener.idl"
#include "calIDateTime.idl"
#include "calIICSService.idl"
/** Adds WCAP specific capabilities.
*/
[scriptable, uuid(21A189DF-6C92-41f6-9E2B-1929EF25CAEE)]
interface calIWcapCalendar : calICalendar
{
/**
* Current userId; if the user is not logged in, a dialog will prompt for.
*/
readonly attribute string userId;
/**
* Current calId the calendar instance acts on; defaults to userId.
*/
attribute string calId;
/**
* Whether the currently selected calendar belongs to user.
*/
readonly attribute boolean isOwnedCalendar;
/**
* Gets or sets this calendar's (calId) default timezone.
*/
readonly attribute string defaultTimezone;
/**
* Gets a text for an error code.
*
* @param rc error code defined in calIWcapErrors
* @return error string
* @exception Components.results.NS_ERROR_INVALID_ARG
*/
string getWcapErrorString( in unsigned long rc );
/**
* Creates a new calendar for user.
*
* @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.
*
* @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.
*
* @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.
*
* @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).
*
* @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).
*
* @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.
* Errors are always notified to all registered calIObservers,
* and rethrown in calling thread (only).
*
* @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;
/**
* Syncs in changes since time <code>dtFrom</code>.
* The passed <code>iListener</code> receives a
* <code>SYNC</code> with timestamp as detail.
*
* @param destCal destination calendar to write changes to
* @param dtFrom start time to sync changes from,
* if null all items are synced in
* @param iListener operation listener for SYNC operation
*/
void syncChangesTo(
in calICalendar destCal,
in calIDateTime dtFrom,
in calIOperationListener iListener );
};

View File

@ -0,0 +1,220 @@
/* -*- 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 "calIErrors.idl"
/** WCAP error codes.
*/
[scriptable, uuid(2ADC008C-A7A6-4f9a-91C8-A99742B68F3D)]
interface calIWcapErrors : calIErrors
{
/* 1 */ const unsigned long WCAP_LOGIN_FAILED =
WCAP_ERROR_BASE + 1;
/* 2 */ const unsigned long WCAP_LOGIN_OK_DEFAULT_CALENDAR_NOT_FOUND =
WCAP_ERROR_BASE + 2;
/* 6 */ const unsigned long WCAP_DELETE_EVENTS_BY_ID_FAILED =
WCAP_ERROR_BASE + 6;
/* 8 */ const unsigned long WCAP_SETCALPROPS_FAILED =
WCAP_ERROR_BASE + 8;
/* 9 */ const unsigned long WCAP_FETCH_EVENTS_BY_ID_FAILED =
WCAP_ERROR_BASE + 9;
/* 10 */ const unsigned long WCAP_CREATECALENDAR_FAILED =
WCAP_ERROR_BASE + 10;
/* 11 */ const unsigned long WCAP_DELETECALENDAR_FAILED =
WCAP_ERROR_BASE + 11;
/* 12 */ const unsigned long WCAP_ADDLINK_FAILED =
WCAP_ERROR_BASE + 12;
/* 13 */ const unsigned long WCAP_FETCHBYDATERANGE_FAILED =
WCAP_ERROR_BASE + 13;
/* 14 */ const unsigned long WCAP_STOREEVENTS_FAILED =
WCAP_ERROR_BASE + 14;
/* 15 */ const unsigned long WCAP_STORETODOS_FAILED =
WCAP_ERROR_BASE + 15;
/* 16 */ const unsigned long WCAP_DELETE_TODOS_BY_ID_FAILED =
WCAP_ERROR_BASE + 16;
/* 17 */ const unsigned long WCAP_FETCH_TODOS_BY_ID_FAILED =
WCAP_ERROR_BASE + 17;
/* 18 */ const unsigned long WCAP_FETCHCOMPONENTS_FAILED_BAD_TZID =
WCAP_ERROR_BASE + 18;
/* 19 */ const unsigned long WCAP_SEARCH_CALPROPS_FAILED =
WCAP_ERROR_BASE + 19;
/* 20 */ const unsigned long WCAP_GET_CALPROPS_FAILED =
WCAP_ERROR_BASE + 20;
/* 21 */ const unsigned long WCAP_DELETECOMPONENTS_BY_RANGE_FAILED =
WCAP_ERROR_BASE + 21;
/* 22 */ const unsigned long WCAP_DELETEEVENTS_BY_RANGE_FAILED =
WCAP_ERROR_BASE + 22;
/* 23 */ const unsigned long WCAP_DELETETODOS_BY_RANGE_FAILED =
WCAP_ERROR_BASE + 23;
/* 24 */ const unsigned long WCAP_GET_ALL_TIMEZONES_FAILED =
WCAP_ERROR_BASE + 24;
/* 25 */ const unsigned long WCAP_CREATECALENDAR_ALREADY_EXISTS_FAILED =
WCAP_ERROR_BASE + 25;
/* 26 */ const unsigned long WCAP_SET_USERPREFS_FAILED =
WCAP_ERROR_BASE + 26;
/* 27 */ const unsigned long WCAP_CHANGE_PASSWORD_FAILED =
WCAP_ERROR_BASE + 27;
/* 28 */ const unsigned long WCAP_ACCESS_DENIED_TO_CALENDAR =
WCAP_ERROR_BASE + 28;
/* 29 */ const unsigned long WCAP_CALENDAR_DOES_NOT_EXIST =
WCAP_ERROR_BASE + 29;
/* 30 */ const unsigned long WCAP_ILLEGAL_CALID_NAME =
WCAP_ERROR_BASE + 30;
/* 31 */ const unsigned long WCAP_CANNOT_MODIFY_LINKED_EVENTS =
WCAP_ERROR_BASE + 31;
/* 32 */ const unsigned long WCAP_CANNOT_MODIFY_LINKED_TODOS =
WCAP_ERROR_BASE + 32;
/* 33 */ const unsigned long WCAP_CANNOT_SENT_EMAIL =
WCAP_ERROR_BASE + 33;
/* 34 */ const unsigned long WCAP_CALENDAR_DISABLED =
WCAP_ERROR_BASE + 34;
/* 35 */ const unsigned long WCAP_WRITE_IMPORT_FAILED =
WCAP_ERROR_BASE + 35;
/* 36 */ const unsigned long WCAP_FETCH_BY_LAST_MODIFIED_FAILED =
WCAP_ERROR_BASE + 36;
/* 37 */ const unsigned long WCAP_CAPI_NOT_SUPPORTED =
WCAP_ERROR_BASE + 37;
/* 38 */ const unsigned long WCAP_CALID_NOT_SPECIFIED =
WCAP_ERROR_BASE + 38;
/* 39 */ const unsigned long WCAP_GET_FREEBUSY_FAILED =
WCAP_ERROR_BASE + 39;
/* 40 */ const unsigned long WCAP_STORE_FAILED_DOUBLE_BOOKED =
WCAP_ERROR_BASE + 40;
/* 41 */ const unsigned long WCAP_FETCH_BY_ALARM_RANGE_FAILED =
WCAP_ERROR_BASE + 41;
/* 42 */ const unsigned long WCAP_FETCH_BY_ATTENDEE_ERROR_FAILED =
WCAP_ERROR_BASE + 42;
/* 43 */ const unsigned long WCAP_ATTENDEE_GROUP_EXPANSION_CLIPPED =
WCAP_ERROR_BASE + 43;
/* 44 */ const unsigned long WCAP_USERPREFS_ACCESS_DENIED =
WCAP_ERROR_BASE + 44;
/* 45 */ const unsigned long WCAP_NOT_ALLOWED_TO_REQUEST_PUBLISH =
WCAP_ERROR_BASE + 45;
/* 46 */ const unsigned long WCAP_INSUFFICIENT_PARAMETERS =
WCAP_ERROR_BASE + 46;
/* 47 */ const unsigned long WCAP_MUSTBEOWNER_OPERATION =
WCAP_ERROR_BASE + 47;
/* 48 */ const unsigned long WCAP_DWP_CONNECTION_FAILED =
WCAP_ERROR_BASE + 48;
/* 49 */ const unsigned long WCAP_DWP_MAX_CONNECTION_REACHED =
WCAP_ERROR_BASE + 49;
/* 50 */ const unsigned long WCAP_DWP_CANNOT_RESOLVE_CALENDAR =
WCAP_ERROR_BASE + 50;
/* 51 */ const unsigned long WCAP_DWP_BAD_DATA =
WCAP_ERROR_BASE + 51;
/* 52 */ const unsigned long WCAP_BAD_COMMAND =
WCAP_ERROR_BASE + 52;
/* 53 */ const unsigned long WCAP_NOT_FOUND =
WCAP_ERROR_BASE + 53;
/* 54 */ const unsigned long WCAP_WRITE_IMPORT_CANT_EXPAND_CALID =
WCAP_ERROR_BASE + 54;
/* 55 */ const unsigned long WCAP_GETTIME_FAILED =
WCAP_ERROR_BASE + 55;
/* 56 */ const unsigned long WCAP_FETCH_DELETEDCOMPONENTS_FAILED =
WCAP_ERROR_BASE + 56;
/* 57 */ const unsigned long WCAP_FETCH_DELETEDCOMPONENTS_PARTIAL_RESULT =
WCAP_ERROR_BASE + 57;
/* 58 */ const unsigned long WCAP_WCAP_NO_SUCH_FORMAT =
WCAP_ERROR_BASE + 58;
/* 59 */ const unsigned long WCAP_COMPONENT_NOT_FOUND =
WCAP_ERROR_BASE + 59;
/* 60 */ const unsigned long WCAP_BAD_ARGUMENTS =
WCAP_ERROR_BASE + 60;
/* 61 */ const unsigned long WCAP_GET_USERPREFS_FAILED =
WCAP_ERROR_BASE + 61;
/* 62 */ const unsigned long WCAP_WCAP_MODIFY_NO_EVENT =
WCAP_ERROR_BASE + 62;
/* 63 */ const unsigned long WCAP_WCAP_CREATE_EXISTS =
WCAP_ERROR_BASE + 63;
/* 64 */ const unsigned long WCAP_WCAP_MODIFY_CANT_MAKE_COPY =
WCAP_ERROR_BASE + 64;
/* 65 */ const unsigned long WCAP_STORE_FAILED_RECUR_SKIP =
WCAP_ERROR_BASE + 65;
/* 66 */ const unsigned long WCAP_STORE_FAILED_RECUR_SAMEDAY =
WCAP_ERROR_BASE + 66;
/* 67 */ const unsigned long WCAP_BAD_ORG_ARGUMENTS =
WCAP_ERROR_BASE + 67;
/* 68 */ const unsigned long WCAP_STORE_FAILED_RECUR_PRIVACY =
WCAP_ERROR_BASE + 68;
/* 69 */ const unsigned long WCAP_LDAP_ERROR =
WCAP_ERROR_BASE + 69;
/* 70 */ const unsigned long WCAP_GET_INVITE_COUNT_FAILED =
WCAP_ERROR_BASE + 70;
/* 71 */ const unsigned long WCAP_LIST_FAILED =
WCAP_ERROR_BASE + 71;
/* 72 */ const unsigned long WCAP_LIST_SUBSCRIBED_FAILED =
WCAP_ERROR_BASE + 72;
/* 73 */ const unsigned long WCAP_SUBSCRIBE_FAILED =
WCAP_ERROR_BASE + 73;
/* 74 */ const unsigned long WCAP_UNSUBSCRIBE_FAILED =
WCAP_ERROR_BASE + 74;
/* 75 */ const unsigned long WCAP_ANONYMOUS_NOT_ALLOWED =
WCAP_ERROR_BASE + 75;
/* 76 */ const unsigned long WCAP_ACCESS_DENIED =
WCAP_ERROR_BASE + 76;
/* 77 */ const unsigned long WCAP_BAD_IMPORT_ARGUMENTS =
WCAP_ERROR_BASE + 77;
/* 78 */ const unsigned long WCAP_READONLY_DATABASE =
WCAP_ERROR_BASE + 78;
/* 79 */ const unsigned long WCAP_ATTENDEE_NOT_ALLOWED_TO_REQUEST_ON_MODIFY=
WCAP_ERROR_BASE + 79;
/* 80 */ const unsigned long WCAP_TRANSP_RESOURCE_NOT_ALLOWED =
WCAP_ERROR_BASE + 80;
/* 81 */ const unsigned long WCAP_RECURRING_COMPONENT_NOT_FOUND =
WCAP_ERROR_BASE + 81;
/* 11000 */ const unsigned long WCAP_CDWP_ERR_MAX_CONNECTION_REACHED =
WCAP_ERROR_BASE + 100;
/* 11001 */ const unsigned long WCAP_CDWP_ERR_CANNOT_CONNECT =
WCAP_ERROR_BASE + 101;
/* 11002 */ const unsigned long WCAP_CDWP_ERR_CANNOT_RESOLVE_CALENDAR =
WCAP_ERROR_BASE + 102;
/* 11003 */ const unsigned long WCAP_CDWP_ERR_BAD_DATA =
WCAP_ERROR_BASE + 103;
/* 11004 */ const unsigned long WCAP_CDWP_ERR_DWPHOST_CTX_DOES_NOT_EXIST =
WCAP_ERROR_BASE + 104;
/* 11005 */ const unsigned long WCAP_CDWP_ERR_HOSTNAME_NOT_RESOLVABLE =
WCAP_ERROR_BASE + 105;
/* 11006 */ const unsigned long WCAP_CDWP_ERR_NO_DATA =
WCAP_ERROR_BASE + 106;
/* 11007 */ const unsigned long WCAP_CDWP_ERR_AUTH_FAILED =
WCAP_ERROR_BASE + 107;
/* 11008 */ const unsigned long WCAP_CDWP_ERR_CHECKVERSION_FAILED =
WCAP_ERROR_BASE + 108;
};

View File

@ -0,0 +1,60 @@
/* -*- 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 "calIDateTime.idl"
[scriptable, uuid(DC94074D-733C-4957-B5CC-BA7641BD269D)]
interface calIWcapFreeBusyEntry : nsISupports
{
/**
* Whether the specified range states a busy time.
*/
readonly attribute boolean isBusyEntry;
/**
* Start date of range.
*/
readonly attribute calIDateTime dtRangeStart;
/**
* (Excluded) end date of range.
*/
readonly attribute calIDateTime dtRangeEnd;
};

View File

@ -0,0 +1,59 @@
/* -*- 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 "calIWcapFreeBusyEntry.idl"
[scriptable, uuid(4498E0D0-04EC-43a3-92E0-560667696CF3)]
interface calIWcapFreeBusyListener : nsISupports
{
/**
* Callback receiving free-busy entries.
*
* @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 unsigned long requestId,
in string calId,
in unsigned long count,
[array, size_is(count)] in calIWcapFreeBusyEntry entries );
};