2006-06-28 21:01:38 +04:00
|
|
|
/* -*- 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 = {};
|
|
|
|
|
2006-07-24 18:44:03 +04:00
|
|
|
function calWcapSession() {
|
2006-06-28 21:01:38 +04:00
|
|
|
this.wrappedJSObject = this;
|
2006-07-24 18:44:03 +04:00
|
|
|
this.m_observers = [];
|
|
|
|
this.m_calIdToCalendar = {};
|
2006-06-28 21:01:38 +04:00
|
|
|
// 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"]
|
2006-07-24 18:44:03 +04:00
|
|
|
.getService(Components.interfaces.nsIObserverService);
|
2006-06-28 21:01:38 +04:00
|
|
|
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 = {
|
2006-07-24 18:44:03 +04:00
|
|
|
m_ifaces: [ Components.interfaces.calIWcapSession,
|
|
|
|
Components.interfaces.nsIInterfaceRequestor,
|
|
|
|
Components.interfaces.nsIClassInfo,
|
|
|
|
Components.interfaces.nsISupports ],
|
2006-06-28 21:01:38 +04:00
|
|
|
|
2006-07-24 18:44:03 +04:00
|
|
|
// nsISupports:
|
|
|
|
QueryInterface:
|
|
|
|
function( iid )
|
|
|
|
{
|
|
|
|
for each ( var iface in this.m_ifaces ) {
|
|
|
|
if (iid.equals( iface ))
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
|
|
|
},
|
|
|
|
|
|
|
|
// nsIClassInfo:
|
|
|
|
getInterfaces:
|
|
|
|
function( count )
|
|
|
|
{
|
|
|
|
count.value = this.m_ifaces.length;
|
|
|
|
return this.m_ifaces;
|
|
|
|
},
|
|
|
|
get classDescription() {
|
|
|
|
return calWcapCalendarModule.WcapSessionInfo.classDescription;
|
|
|
|
},
|
|
|
|
get contractID() {
|
|
|
|
return calWcapCalendarModule.WcapSessionInfo.contractID;
|
|
|
|
},
|
|
|
|
get classID() {
|
|
|
|
return calWcapCalendarModule.WcapSessionInfo.classID;
|
|
|
|
},
|
|
|
|
getHelperForLanguage: function( language ) { return null; },
|
|
|
|
implementationLanguage:
|
|
|
|
Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
|
|
|
|
flags: 0,
|
|
|
|
|
|
|
|
// nsIInterfaceRequestor:
|
|
|
|
getInterface:
|
|
|
|
function( iid, instance )
|
|
|
|
{
|
|
|
|
if (iid.equals(Components.interfaces.nsIAuthPrompt)) {
|
|
|
|
// use the window watcher service to get a nsIAuthPrompt impl
|
|
|
|
return getWindowWatcher().getNewAuthPrompter(null);
|
|
|
|
}
|
|
|
|
else if (iid.equals(Components.interfaces.nsIPrompt)) {
|
|
|
|
// use the window watcher service to get a nsIPrompt impl
|
|
|
|
return getWindowWatcher().getNewPrompter(null);
|
|
|
|
}
|
|
|
|
Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
|
|
|
|
return null;
|
|
|
|
},
|
2006-06-28 21:01:38 +04:00
|
|
|
|
|
|
|
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 );
|
|
|
|
},
|
2006-07-24 18:44:03 +04:00
|
|
|
logError:
|
|
|
|
function( err, context )
|
|
|
|
{
|
|
|
|
var str = ("error: " + errorToString(err));
|
|
|
|
Components.utils.reportError( this.log( str, context ) );
|
|
|
|
return str;
|
|
|
|
},
|
|
|
|
notifyError:
|
|
|
|
function( err )
|
|
|
|
{
|
|
|
|
debugger;
|
|
|
|
var str = this.logError( err );
|
|
|
|
this.notifyObservers( "onError",
|
|
|
|
[err instanceof Error ? -1 : err, str] );
|
|
|
|
},
|
2006-06-28 21:01:38 +04:00
|
|
|
|
2006-07-24 18:44:03 +04:00
|
|
|
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 )
|
2006-06-28 21:01:38 +04:00
|
|
|
{
|
2006-07-24 18:44:03 +04:00
|
|
|
if (this.m_observers.indexOf( observer ) == -1) {
|
|
|
|
this.m_observers.push( observer );
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
2006-07-24 18:44:03 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
removeObserver:
|
|
|
|
function( observer )
|
|
|
|
{
|
|
|
|
this.m_observers = this.m_observers.filter(
|
|
|
|
function(x) { return x != observer; } );
|
2006-06-28 21:01:38 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
// 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" );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
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;
|
2006-07-12 11:19:20 +04:00
|
|
|
var str = issueSyncRequest( url );
|
2006-06-28 21:01:38 +04:00
|
|
|
var icalRootComp = getIcsService().parseICS( str );
|
|
|
|
if (icalRootComp == null)
|
2006-07-12 11:19:20 +04:00
|
|
|
throw new Error("invalid data, expected ical!");
|
2006-06-28 21:01:38 +04:00
|
|
|
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();
|
2006-07-12 11:19:20 +04:00
|
|
|
var str = issueSyncRequest( url );
|
2006-06-28 21:01:38 +04:00
|
|
|
var icalRootComp = getIcsService().parseICS( str );
|
|
|
|
if (icalRootComp == null)
|
2006-07-12 11:19:20 +04:00
|
|
|
throw new Error("invalid data, expected ical!");
|
2006-06-28 21:01:38 +04:00
|
|
|
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;
|
|
|
|
},
|
|
|
|
|
2006-07-24 18:44:03 +04:00
|
|
|
m_sessionId: null,
|
|
|
|
m_bNoLoginsAnymore: false,
|
|
|
|
|
2006-06-28 21:01:38 +04:00
|
|
|
getSessionId:
|
|
|
|
function( timedOutSessionId )
|
|
|
|
{
|
|
|
|
if (this.m_bNoLoginsAnymore) {
|
|
|
|
this.log( "login has failed, no logins anymore for this user." );
|
2006-07-12 11:19:20 +04:00
|
|
|
throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED;
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
|
|
|
if (getIoService().offline) {
|
|
|
|
this.log( "in offline mode." );
|
2006-07-12 11:19:20 +04:00
|
|
|
throw NS_ERROR_OFFLINE;
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this.m_sessionId == null || this.m_sessionId == timedOutSessionId) {
|
2006-07-26 19:14:28 +04:00
|
|
|
// sync all execution for login to UI thread, using nsIRunnable:
|
|
|
|
|
|
|
|
// change from MOZILLA_1_8_BRANCH->TRUNK: probe xxx todo: test
|
2006-06-28 21:01:38 +04:00
|
|
|
var eventQueueService =
|
|
|
|
Components.classes["@mozilla.org/event-queue-service;1"]
|
|
|
|
.getService(Components.interfaces.nsIEventQueueService);
|
2006-07-26 19:14:28 +04:00
|
|
|
var target; // eventQueue or eventTarget
|
|
|
|
if (eventQueueService == null) {
|
|
|
|
// we are on the TRUNK:
|
|
|
|
var threadManager =
|
|
|
|
Components.classes["@mozilla.org/thread-manager;1"]
|
|
|
|
.getService(Components.interfaces.nsIThreadManager);
|
|
|
|
target = threadManager.mainThread;
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
2006-07-26 19:14:28 +04:00
|
|
|
else {
|
|
|
|
target = eventQueueService.getSpecialEventQueue(
|
|
|
|
Components.interfaces.
|
|
|
|
nsIEventQueueService.UI_THREAD_EVENT_QUEUE );
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
2006-07-26 19:14:28 +04:00
|
|
|
|
|
|
|
var proxyObjectManager =
|
|
|
|
Components.classes["@mozilla.org/xpcomproxy;1"]
|
|
|
|
.getService(Components.interfaces.nsIProxyObjectManager);
|
|
|
|
var this_ = this;
|
|
|
|
var proxy = proxyObjectManager.getProxyForObject(
|
|
|
|
target, Components.interfaces.nsIRunnable,
|
|
|
|
{ // need to implemented QueryInterface, because object param
|
|
|
|
// is not associated with iid:
|
|
|
|
QueryInterface: function( iid ) {
|
|
|
|
if (Components.interfaces.nsIRunnable.equals(iid) ||
|
|
|
|
Components.interfaces.nsISupports.equals(iid))
|
|
|
|
return this;
|
|
|
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
|
|
|
},
|
|
|
|
// nsIRunnable:
|
|
|
|
run: function() {
|
|
|
|
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 */);
|
|
|
|
// preread calprops for subscribed calendars:
|
|
|
|
var cals = this_.getSubscribedCalendars({});
|
|
|
|
for each ( cal in cals ) {
|
|
|
|
cal.getCalProps_(true /* async */);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Components.interfaces.nsIProxyObjectManager.INVOKE_SYNC );
|
|
|
|
// xxx todo: are rc/exceptions forwarded to current thread?
|
|
|
|
proxy.run();
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
2006-07-12 11:19:20 +04:00
|
|
|
if (this.m_sessionId == null) {
|
|
|
|
throw Components.interfaces.calIWcapErrors.WCAP_LOGIN_FAILED;
|
|
|
|
}
|
2006-06-28 21:01:38 +04:00
|
|
|
return this.m_sessionId;
|
|
|
|
},
|
|
|
|
getSessionId_:
|
|
|
|
function()
|
|
|
|
{
|
|
|
|
if (this.m_sessionId == null) {
|
|
|
|
|
|
|
|
var passwordManager =
|
|
|
|
Components.classes["@mozilla.org/passwordmanager;1"]
|
|
|
|
.getService(Components.interfaces.nsIPasswordManager);
|
|
|
|
|
2006-07-24 18:44:03 +04:00
|
|
|
var outUser = { value: this.userId };
|
2006-06-28 21:01:38 +04:00
|
|
|
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...
|
2006-07-12 11:19:20 +04:00
|
|
|
if (!confirmUnsecureLogin( loginUri )) {
|
2006-06-28 21:01:38 +04:00
|
|
|
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 {
|
2006-07-24 18:44:03 +04:00
|
|
|
this.login_( loginUri, outUser.value, outPW.value );
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
|
|
|
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:
|
2006-07-24 18:44:03 +04:00
|
|
|
this.login_( loginUri,
|
|
|
|
outUser.value, outPW.value );
|
2006-06-28 21:01:38 +04:00
|
|
|
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 {
|
2006-07-24 18:44:03 +04:00
|
|
|
this.login_( loginUri, outUser.value, outPW.value );
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
},
|
2006-07-24 18:44:03 +04:00
|
|
|
login_:
|
|
|
|
function( loginUri, user, pw )
|
|
|
|
{
|
|
|
|
if (this.m_sessionId != null) {
|
|
|
|
this.logout();
|
|
|
|
}
|
|
|
|
// currently, xml parsing at an early stage during process startup
|
|
|
|
// does not work reliably, so use libical parsing for now:
|
|
|
|
var str = issueSyncRequest(
|
|
|
|
loginUri.spec + "login.wcap?fmt-out=text%2Fcalendar&user=" +
|
|
|
|
encodeURIComponent(user) + "&password=" + encodeURIComponent(pw),
|
|
|
|
null /* receiverFunc */, false /* no logging */ );
|
|
|
|
var icalRootComp = getIcsService().parseICS( str );
|
|
|
|
checkWcapIcalErrno( icalRootComp );
|
|
|
|
var prop = icalRootComp.getFirstProperty( "X-NSCP-WCAP-SESSION-ID" );
|
|
|
|
if (prop == null)
|
|
|
|
throw new Error("missing X-NSCP-WCAP-SESSION-ID!");
|
|
|
|
this.m_sessionId = prop.value;
|
|
|
|
|
|
|
|
// var xml = issueSyncXMLRequest(
|
|
|
|
// loginUri.spec + "login.wcap?fmt-out=text%2Fxml&user=" +
|
|
|
|
// encodeURIComponent(user) + "&password=" + encodeURIComponent(pw) );
|
|
|
|
// checkWcapXmlErrno( xml );
|
|
|
|
// this.m_sessionId = xml.getElementsByTagName(
|
|
|
|
// "X-NSCP-WCAP-SESSION-ID" ).item(0).textContent;
|
|
|
|
this.m_userId = user;
|
|
|
|
this.log( "WCAP login succeeded." );
|
|
|
|
},
|
2006-06-28 21:01:38 +04:00
|
|
|
|
|
|
|
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:
|
2006-07-12 11:19:20 +04:00
|
|
|
var str = issueSyncRequest(
|
2006-06-28 21:01:38 +04:00
|
|
|
uri.spec + "version.wcap?fmt-out=text%2Fcalendar" );
|
|
|
|
var icalRootComp = getIcsService().parseICS( str );
|
|
|
|
if (icalRootComp == null)
|
2006-07-12 11:19:20 +04:00
|
|
|
throw new Error("invalid data, expected ical!");
|
2006-06-28 21:01:38 +04:00
|
|
|
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 );
|
|
|
|
},
|
|
|
|
|
2006-07-24 18:44:03 +04:00
|
|
|
getCommandUrl:
|
|
|
|
function( wcapCommand )
|
2006-06-28 21:01:38 +04:00
|
|
|
{
|
2006-07-24 18:44:03 +04:00
|
|
|
if (this.uri == null)
|
|
|
|
throw new Error("no URI!");
|
|
|
|
// ensure established session, so userId is set;
|
|
|
|
// (calId defaults to userId) if not set:
|
|
|
|
this.getSessionId();
|
|
|
|
return (this.uri.spec + wcapCommand + ".wcap?appid=mozilla-lightning");
|
|
|
|
},
|
|
|
|
|
|
|
|
issueRequest:
|
|
|
|
function( url, issueFunc, dataConvFunc, receiverFunc )
|
|
|
|
{
|
|
|
|
var sessionId = this.getSessionId();
|
|
|
|
|
|
|
|
var this_ = this;
|
|
|
|
issueFunc(
|
|
|
|
url + ("&id=" + sessionId),
|
|
|
|
function( data ) {
|
|
|
|
var wcapResponse = new WcapResponse();
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
wcapResponse.data = dataConvFunc(
|
|
|
|
data, wcapResponse );
|
|
|
|
}
|
|
|
|
catch (exc) {
|
|
|
|
if (exc == Components.interfaces.
|
|
|
|
calIWcapErrors.WCAP_LOGIN_FAILED) /* timeout */ {
|
|
|
|
// getting a new session will throw any exception in
|
|
|
|
// this block, thus it is notified into receiverFunc
|
|
|
|
this_.getSessionId(
|
|
|
|
sessionId /* (old) timed-out session */ );
|
|
|
|
// try again:
|
|
|
|
this_.issueRequest(
|
|
|
|
url, issueFunc, dataConvFunc, receiverFunc );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throw exc; // rethrow
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (exc) {
|
|
|
|
// setting the request's exception will rethrow exception
|
|
|
|
// when request's data is retrieved.
|
|
|
|
wcapResponse.exception = exc;
|
|
|
|
}
|
|
|
|
receiverFunc( wcapResponse );
|
|
|
|
} );
|
|
|
|
},
|
|
|
|
|
|
|
|
issueAsyncRequest:
|
|
|
|
function( url, dataConvFunc, receiverFunc )
|
|
|
|
{
|
|
|
|
this.issueRequest(
|
|
|
|
url, issueAsyncRequest, dataConvFunc, receiverFunc );
|
|
|
|
},
|
|
|
|
|
|
|
|
issueSyncRequest:
|
|
|
|
function( url, dataConvFunc, receiverFunc )
|
|
|
|
{
|
|
|
|
var ret = null;
|
|
|
|
this.issueRequest(
|
|
|
|
url, issueSyncRequest,
|
|
|
|
dataConvFunc,
|
|
|
|
function( wcapResponse ) {
|
|
|
|
if (receiverFunc) {
|
|
|
|
receiverFunc( wcapResponse );
|
|
|
|
}
|
|
|
|
ret = wcapResponse.data; // may throw
|
|
|
|
} );
|
|
|
|
return ret;
|
|
|
|
},
|
|
|
|
|
|
|
|
// calIWcapSession:
|
|
|
|
|
|
|
|
m_uri: null,
|
|
|
|
get uri() { return this.m_uri; },
|
|
|
|
set uri( thatUri )
|
|
|
|
{
|
|
|
|
if (this.m_uri == null || thatUri == null ||
|
|
|
|
!this.m_uri.equals(thatUri))
|
|
|
|
{
|
2006-06-28 21:01:38 +04:00
|
|
|
this.logout();
|
2006-07-24 18:44:03 +04:00
|
|
|
this.m_uri = null;
|
|
|
|
if (thatUri != null) {
|
|
|
|
// sensible default for user id login:
|
|
|
|
var username = decodeURIComponent( thatUri.username );
|
|
|
|
if (username != "") {
|
|
|
|
var nColon = username.indexOf(':');
|
|
|
|
this.m_userId =
|
|
|
|
(nColon >= 0 ? username.substr(0, nColon) : username);
|
|
|
|
}
|
|
|
|
this.m_uri = thatUri.clone();
|
|
|
|
this.m_uri.userPass = "";
|
|
|
|
}
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
2006-07-24 18:44:03 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
m_userId: null,
|
|
|
|
get userId() { return this.m_userId; },
|
2006-07-26 19:14:28 +04:00
|
|
|
|
|
|
|
get isLoggedIn() { return this.m_sessionId != null; },
|
|
|
|
|
2006-07-24 18:44:03 +04:00
|
|
|
login:
|
|
|
|
function()
|
|
|
|
{
|
|
|
|
this.logout(); // assure being logged out
|
|
|
|
this.getSessionId();
|
2006-06-28 21:01:38 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
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 {
|
2006-07-12 11:19:20 +04:00
|
|
|
checkWcapXmlErrno( issueSyncXMLRequest(url),
|
|
|
|
-1 /* logout successfull */ );
|
2006-06-28 21:01:38 +04:00
|
|
|
this.log( "WCAP logout succeeded." );
|
|
|
|
}
|
|
|
|
catch (exc) {
|
|
|
|
this.log( "WCAP logout failed: " + exc );
|
|
|
|
Components.utils.reportError( exc );
|
|
|
|
}
|
|
|
|
this.m_sessionId = null;
|
|
|
|
}
|
2006-07-24 18:44:03 +04:00
|
|
|
this.m_userId = null;
|
2006-06-28 21:01:38 +04:00
|
|
|
// ask next time we log in:
|
|
|
|
this.m_bNoLoginsAnymore = false;
|
2006-07-26 19:14:28 +04:00
|
|
|
if (this.uri != null) {
|
|
|
|
var this_ = this;
|
|
|
|
g_httpHosts = g_httpHosts.filter(
|
|
|
|
function(hostEntry) {
|
|
|
|
return (hostEntry.m_host != this_.uri.hostPort); } );
|
|
|
|
}
|
2006-07-24 18:44:03 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
getWcapErrorString:
|
|
|
|
function( rc )
|
|
|
|
{
|
|
|
|
return wcapErrorToString(rc);
|
|
|
|
},
|
|
|
|
|
|
|
|
get defaultCalendar() {
|
2006-07-26 19:14:28 +04:00
|
|
|
return this.getCalendarByCalId(null);
|
2006-07-24 18:44:03 +04:00
|
|
|
},
|
|
|
|
set defaultCalendar(cal) {
|
|
|
|
this.m_defaultCalendar = cal;
|
|
|
|
},
|
|
|
|
|
|
|
|
m_defaultCalendar: null,
|
|
|
|
m_calIdToCalendar: {},
|
|
|
|
getCalendarByCalId:
|
|
|
|
function( calId )
|
|
|
|
{
|
2006-07-26 19:14:28 +04:00
|
|
|
var ret;
|
2006-07-24 18:44:03 +04:00
|
|
|
if (calId == null || this.userId == calId) {
|
|
|
|
if (this.m_defaultCalendar == null)
|
2006-07-26 19:14:28 +04:00
|
|
|
this.m_defaultCalendar = new calWcapCalendar(this.userId, this);
|
|
|
|
ret = this.m_defaultCalendar;
|
2006-07-24 18:44:03 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
var key = encodeURIComponent(calId);
|
2006-07-26 19:14:28 +04:00
|
|
|
ret = this.m_calIdToCalendar[key];
|
2006-07-24 18:44:03 +04:00
|
|
|
if (!ret) {
|
2006-07-26 19:14:28 +04:00
|
|
|
ret = new calWcapCalendar(calId, this);
|
2006-07-24 18:44:03 +04:00
|
|
|
this.m_calIdToCalendar[key] = ret;
|
|
|
|
}
|
|
|
|
}
|
2006-07-26 19:14:28 +04:00
|
|
|
return ret;
|
2006-07-24 18:44:03 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
getCalendars:
|
|
|
|
function( out_count, bGetOwnedCals )
|
|
|
|
{
|
|
|
|
var list = this.getUserPreferences(
|
|
|
|
bGetOwnedCals ? "X-NSCP-WCAP-PREF-icsCalendarOwned"
|
|
|
|
: "X-NSCP-WCAP-PREF-icsSubscribed", {} );
|
|
|
|
var ret = [];
|
|
|
|
for each( var item in list ) {
|
|
|
|
var ar = item.split(',');
|
|
|
|
// ',', '$' are not encoded. ',' can be handled here. WTF.
|
|
|
|
for each ( a in ar ) {
|
|
|
|
var dollar = a.indexOf('$');
|
|
|
|
if (dollar >= 0) {
|
|
|
|
ret.push(
|
|
|
|
this.getCalendarByCalId( a.substring(0, dollar) ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out_count.value = ret.length;
|
|
|
|
return ret;
|
|
|
|
},
|
|
|
|
getOwnedCalendars:
|
|
|
|
function( out_count )
|
|
|
|
{
|
|
|
|
return this.getCalendars( out_count, true );
|
|
|
|
},
|
|
|
|
getSubscribedCalendars:
|
|
|
|
function( out_count )
|
|
|
|
{
|
|
|
|
return this.getCalendars( out_count, false );
|
|
|
|
},
|
|
|
|
|
|
|
|
createCalendar:
|
|
|
|
function( calId, name, bAllowDoubleBooking, bSetCalProps, bAddToSubscribed )
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
var url = this.getCommandUrl( "createcalendar" );
|
|
|
|
url += ("&allowdoublebook=" + (bAllowDoubleBooking ? "1" : "0"));
|
|
|
|
url += ("&set_calprops=" + (bSetCalProps ? "1" : "0"));
|
|
|
|
url += ("&subscribe=" + (bAddToSubscribed ? "1" : "0"));
|
|
|
|
url += ("&calid=" + encodeURIComponent(calId));
|
|
|
|
// xxx todo: name undocumented!
|
|
|
|
url += ("&name=" + encodeURIComponent(name));
|
|
|
|
// xxx todo: what about categories param???
|
|
|
|
this.issueSyncRequest( url + "&fmt-out=text%2Fxml", stringToXml );
|
|
|
|
this.m_userPrefs = null; // reread prefs
|
|
|
|
return this.getCalendarByCalId( this.userId + ":" + calId );
|
|
|
|
}
|
|
|
|
catch (exc) {
|
|
|
|
this.notifyError( exc );
|
|
|
|
throw exc;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
deleteCalendar:
|
|
|
|
function( calId, bRemoveFromSubscribed )
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
var url = this.getCommandUrl( "deletecalendar" );
|
|
|
|
url += ("&unsubscribe=" + (bRemoveFromSubscribed ? "1" : "0"));
|
|
|
|
url += ("&calid=" + encodeURIComponent(calId));
|
|
|
|
this.issueSyncRequest( url + "&fmt-out=text%2Fxml", stringToXml );
|
|
|
|
this.m_userPrefs = null; // reread prefs
|
|
|
|
this.m_calIdToCalendar[encodeURIComponent(calId)] = null;
|
|
|
|
}
|
|
|
|
catch (exc) {
|
|
|
|
this.notifyError( exc );
|
|
|
|
throw exc;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
modifyCalendarSubscriptions:
|
|
|
|
function( calIds, bSubscribe )
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
var url = this.getCommandUrl(
|
|
|
|
bSubscribe ? "subscribe_calendars" : "unsubscribe_calendars" );
|
|
|
|
var calId = "";
|
|
|
|
for ( var i = 0; i < calIds.length; ++i ) {
|
|
|
|
if (i > 0)
|
|
|
|
calId += ";";
|
|
|
|
calId += encodeURIComponent(calIds[i]);
|
|
|
|
}
|
|
|
|
url += ("&calid=" + calId);
|
|
|
|
this.issueSyncRequest( url + "&fmt-out=text%2Fxml", stringToXml );
|
|
|
|
this.m_userPrefs = null; // reread prefs
|
|
|
|
}
|
|
|
|
catch (exc) {
|
|
|
|
this.notifyError( exc );
|
|
|
|
throw exc;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
subscribeToCalendars:
|
|
|
|
function( count, calIds )
|
|
|
|
{
|
|
|
|
this.modifyCalendarSubscriptions( calIds, true );
|
|
|
|
},
|
|
|
|
|
|
|
|
unsubscribeFromCalendars:
|
|
|
|
function( count, calIds )
|
|
|
|
{
|
|
|
|
this.modifyCalendarSubscriptions( calIds, false );
|
|
|
|
},
|
|
|
|
|
|
|
|
m_userPrefs: null,
|
|
|
|
getUserPreferences:
|
|
|
|
function( prefName, out_count )
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
if (this.m_userPrefs == null) {
|
|
|
|
var url = this.getCommandUrl( "get_userprefs" );
|
|
|
|
url += ("&userid=" + encodeURIComponent(this.userId));
|
|
|
|
this.m_userPrefs = this.issueSyncRequest(
|
|
|
|
url + "&fmt-out=text%2Fxml", stringToXml );
|
|
|
|
}
|
|
|
|
var ret = [];
|
|
|
|
var nodeList = this.m_userPrefs.getElementsByTagName(prefName);
|
|
|
|
for ( var i = 0; i < nodeList.length; ++i ) {
|
|
|
|
ret.push( trimString(nodeList.item(i).textContent) );
|
|
|
|
}
|
|
|
|
out_count.value = ret.length;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
catch (exc) {
|
|
|
|
this.notifyError( exc );
|
|
|
|
throw exc;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
getFreeBusyTimes_resp:
|
|
|
|
function( wcapResponse, calId, iListener, requestId )
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
var xml = wcapResponse.data; // first statement, may throw
|
|
|
|
if (iListener != null) {
|
|
|
|
var ret = [];
|
|
|
|
var nodeList = xml.getElementsByTagName("FB");
|
|
|
|
for ( var i = 0; i < nodeList.length; ++i ) {
|
|
|
|
var item = nodeList.item(i);
|
|
|
|
var str = item.textContent;
|
|
|
|
var slash = str.indexOf( '/' );
|
|
|
|
var start = new CalDateTime();
|
|
|
|
start.icalString = str.substr( 0, slash );
|
|
|
|
var end = new CalDateTime();
|
|
|
|
end.icalString = str.substr( slash + 1 );
|
|
|
|
var entry = {
|
|
|
|
isBusyEntry:
|
|
|
|
(item.attributes.getNamedItem("FBTYPE").nodeValue
|
|
|
|
== "BUSY"),
|
|
|
|
dtRangeStart: start,
|
|
|
|
dtRangeEnd: end
|
|
|
|
};
|
|
|
|
ret.push( entry );
|
|
|
|
}
|
|
|
|
iListener.onGetFreeBusyTimes(
|
|
|
|
Components.results.NS_OK,
|
|
|
|
requestId, calId, ret.length, ret );
|
|
|
|
}
|
|
|
|
if (LOG_LEVEL > 0) {
|
|
|
|
this.log( "getFreeBusyTimes_resp() calId=" + calId + ", " +
|
|
|
|
getWcapRequestStatusString(xml) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (exc) {
|
|
|
|
const calIWcapErrors = Components.interfaces.calIWcapErrors;
|
|
|
|
switch (exc) {
|
|
|
|
case calIWcapErrors.WCAP_NO_ERRNO: // workaround
|
|
|
|
case calIWcapErrors.WCAP_ACCESS_DENIED_TO_CALENDAR:
|
|
|
|
case calIWcapErrors.WCAP_CALENDAR_DOES_NOT_EXIST:
|
|
|
|
this.log( "getFreeBusyTimes_resp() ignored: " +
|
|
|
|
errorToString(exc) ); // no error
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
this.notifyError( exc );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (iListener != null)
|
|
|
|
iListener.onGetFreeBusyTimes( exc, requestId, calId, 0, [] );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
getFreeBusyTimes:
|
|
|
|
function( calId, rangeStart, rangeEnd, bBusyOnly, iListener,
|
|
|
|
bAsync, requestId )
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
// assure DATETIMEs:
|
|
|
|
if (rangeStart != null && rangeStart.isDate) {
|
|
|
|
rangeStart = rangeStart.clone();
|
|
|
|
rangeStart.isDate = false;
|
|
|
|
}
|
|
|
|
if (rangeEnd != null && rangeEnd.isDate) {
|
|
|
|
rangeEnd = rangeEnd.clone();
|
|
|
|
rangeEnd.isDate = false;
|
|
|
|
}
|
|
|
|
var zRangeStart = getIcalUTC(rangeStart);
|
|
|
|
var zRangeEnd = getIcalUTC(rangeEnd);
|
|
|
|
this.log( "getFreeBusyTimes():\n\trangeStart=" + zRangeStart +
|
|
|
|
",\n\trangeEnd=" + zRangeEnd );
|
|
|
|
|
|
|
|
var url = this.getCommandUrl( "get_freebusy" );
|
|
|
|
url += ("&calid=" + encodeURIComponent(calId));
|
|
|
|
url += ("&busyonly=" + (bBusyOnly ? "1" : "0"));
|
|
|
|
url += ("&dtstart=" + zRangeStart);
|
|
|
|
url += ("&dtend=" + zRangeEnd);
|
|
|
|
url += "&fmt-out=text%2Fxml";
|
|
|
|
|
|
|
|
var this_ = this;
|
|
|
|
function resp( wcapResponse ) {
|
|
|
|
this_.getFreeBusyTimes_resp(
|
|
|
|
wcapResponse, calId, iListener, requestId );
|
|
|
|
}
|
|
|
|
if (bAsync)
|
|
|
|
this.issueAsyncRequest( url, stringToXml, resp );
|
|
|
|
else
|
|
|
|
this.issueSyncRequest( url, stringToXml, resp );
|
|
|
|
}
|
|
|
|
catch (exc) {
|
|
|
|
this.notifyError( exc );
|
|
|
|
if (iListener != null)
|
|
|
|
iListener.onGetFreeBusyTimes( exc, requestId, calId, 0, [] );
|
|
|
|
throw exc;
|
|
|
|
}
|
2006-06-28 21:01:38 +04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2006-07-24 18:44:03 +04:00
|
|
|
var g_httpHosts = [];
|
2006-06-28 21:01:38 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|