Bug 340949: no more event queue locking, minor fixes and cosmetics
git-svn-id: svn://10.0.0.236/trunk@215316 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
bf5bdadd37
commit
a2836b3103
@ -57,6 +57,20 @@ function calWcapCalendar( calId, session ) {
|
||||
this.m_calId = calId;
|
||||
this.m_session = session;
|
||||
this.m_bSuppressAlarms = SUPPRESS_ALARMS;
|
||||
|
||||
// init queued calls:
|
||||
this.adoptItem = makeQueuedCall(this.session.asyncQueue,
|
||||
this, this.adoptItem_queued);
|
||||
this.modifyItem = makeQueuedCall(this.session.asyncQueue,
|
||||
this, this.modifyItem_queued);
|
||||
this.deleteItem = makeQueuedCall(this.session.asyncQueue,
|
||||
this, this.deleteItem_queued);
|
||||
this.getItem = makeQueuedCall(this.session.asyncQueue,
|
||||
this, this.getItem_queued);
|
||||
this.getItems = makeQueuedCall(this.session.asyncQueue,
|
||||
this, this.getItems_queued);
|
||||
this.syncChangesTo = makeQueuedCall(this.session.asyncQueue,
|
||||
this, this.syncChangesTo_queued);
|
||||
}
|
||||
calWcapCalendar.prototype = {
|
||||
m_ifaces: [ Components.interfaces.calIWcapCalendar,
|
||||
@ -237,7 +251,8 @@ calWcapCalendar.prototype = {
|
||||
this.m_bReadOnly ||
|
||||
// xxx todo: check write permissions in advance
|
||||
// alarms only for own calendars:
|
||||
!this.isOwnedCalendar);
|
||||
// xxx todo: assume alarms if not logged in already
|
||||
(this.session.isLoggedIn && !this.isOwnedCalendar));
|
||||
},
|
||||
set suppressAlarms( bSuppressAlarms ) {
|
||||
this.m_bSuppressAlarms = bSuppressAlarms;
|
||||
@ -249,6 +264,14 @@ calWcapCalendar.prototype = {
|
||||
this.log("refresh()");
|
||||
},
|
||||
|
||||
getCommandUrl:
|
||||
function( wcapCommand )
|
||||
{
|
||||
var url = this.session.getCommandUrl(wcapCommand);
|
||||
url += ("&calid=" + encodeURIComponent(this.calId));
|
||||
return url;
|
||||
},
|
||||
|
||||
// calIWcapCalendar:
|
||||
|
||||
m_session: null,
|
||||
@ -261,14 +284,16 @@ calWcapCalendar.prototype = {
|
||||
// like a subscribed one...
|
||||
m_calId: null,
|
||||
get calId() {
|
||||
return this.m_calId || this.session.defaultCalId;
|
||||
if (this.m_calId)
|
||||
return this.m_calId;
|
||||
this.session.assureLoggedIn();
|
||||
return this.session.defaultCalId;
|
||||
},
|
||||
set calId( id ) {
|
||||
this.log( "setting calId to " + id );
|
||||
this.m_calId = id;
|
||||
// refresh calprops:
|
||||
this.m_calProps = null;
|
||||
this.getCalProps_( true /* async */ );
|
||||
this.getCalProps_( true /*async*/, true /*refresh*/ );
|
||||
},
|
||||
|
||||
get ownerId() {
|
||||
@ -328,12 +353,12 @@ calWcapCalendar.prototype = {
|
||||
},
|
||||
m_calProps: null,
|
||||
getCalProps_:
|
||||
function( bAsync )
|
||||
function( bAsync, bRefresh )
|
||||
{
|
||||
this.session.assureLoggedIn();
|
||||
try {
|
||||
if (this.m_calProps == null) {
|
||||
var url = this.session.getCommandUrl( "get_calprops" );
|
||||
url += ("&calid=" + encodeURIComponent(this.calId));
|
||||
if (bRefresh || !this.m_calProps) {
|
||||
var url = this.getCommandUrl( "get_calprops" );
|
||||
url += "&fmt-out=text%2Fxml";
|
||||
var this_ = this;
|
||||
function resp( wcapResponse ) {
|
||||
@ -366,7 +391,8 @@ calWcapCalendar.prototype = {
|
||||
// readOnly attribute, thus we would run into endless recursion here
|
||||
this.m_bReadOnly = true;
|
||||
this.logError( exc );
|
||||
throw exc;
|
||||
if (!bAsync)
|
||||
throw exc;
|
||||
}
|
||||
return this.m_calProps;
|
||||
},
|
||||
|
||||
@ -61,7 +61,7 @@ calWcapCalendar.prototype.encodeAttendee = function(
|
||||
ret += ("^ROLE=" + attendee.role);
|
||||
if (attendee.commonName != null)
|
||||
ret += ("^CN=" + encodeURIComponent(attendee.commonName));
|
||||
ret += ("^" + attendee.id);
|
||||
ret += ("^" + encodeURIComponent(attendee.id));
|
||||
return ret;
|
||||
};
|
||||
|
||||
@ -196,12 +196,10 @@ calWcapCalendar.prototype.storeItem = function( item, oldItem, receiverFunc )
|
||||
var bIsEvent = isEvent(item);
|
||||
var bIsParent = isParent(item);
|
||||
|
||||
var url = this.session.getCommandUrl( bIsEvent ? "storeevents"
|
||||
: "storetodos" );
|
||||
url += ("&calid=" + encodeURIComponent(this.calId));
|
||||
var url = this.getCommandUrl( bIsEvent ? "storeevents" : "storetodos" );
|
||||
|
||||
if (oldItem) { // modifying
|
||||
url += ("&uid=" + item.id);
|
||||
url += ("&uid=" + encodeURIComponent(item.id));
|
||||
if (bIsParent) {
|
||||
// (WCAP_STORE_TYPE_MODIFY) error if not existing:
|
||||
url += "&storetype=2";
|
||||
@ -359,7 +357,7 @@ calWcapCalendar.prototype.storeItem = function( item, oldItem, receiverFunc )
|
||||
url += ("&X-NSCP-DTEND-TZID=" +
|
||||
"X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-REPLACE^" +
|
||||
encodeURIComponent(this.getAlignedTimezone(dtend.timezone)));
|
||||
this.log("dtstart=" + dtstart + "\ndtend=" + dtend);
|
||||
this.log("dtstart=" + dtstart + "\ndtend=" + dtend, item.id);
|
||||
bIsAllDay = (dtstart.isDate && dtend.isDate);
|
||||
}
|
||||
else { // calITodo:
|
||||
@ -581,7 +579,7 @@ calWcapCalendar.prototype.adoptItem_resp = function(
|
||||
}
|
||||
};
|
||||
|
||||
calWcapCalendar.prototype.adoptItem = function( item, listener )
|
||||
calWcapCalendar.prototype.adoptItem_queued = function( item, listener )
|
||||
{
|
||||
this.log( "adoptItem() call: " + item.title );
|
||||
try {
|
||||
@ -659,7 +657,8 @@ calWcapCalendar.prototype.modifyItem_resp = function(
|
||||
}
|
||||
};
|
||||
|
||||
calWcapCalendar.prototype.modifyItem = function( newItem, oldItem, listener )
|
||||
calWcapCalendar.prototype.modifyItem_queued = function(
|
||||
newItem, oldItem, listener )
|
||||
{
|
||||
this.log( "modifyItem() call: " + newItem.id );
|
||||
try {
|
||||
@ -719,7 +718,7 @@ calWcapCalendar.prototype.deleteItem_resp = function(
|
||||
}
|
||||
};
|
||||
|
||||
calWcapCalendar.prototype.deleteItem = function( item, listener )
|
||||
calWcapCalendar.prototype.deleteItem_queued = function( item, listener )
|
||||
{
|
||||
this.log( "deleteItem() call: " + item.id );
|
||||
try {
|
||||
@ -727,10 +726,9 @@ calWcapCalendar.prototype.deleteItem = function( item, listener )
|
||||
if (item.id == null)
|
||||
throw new Components.Exception("no item id!");
|
||||
|
||||
var url = this.session.getCommandUrl(
|
||||
var url = this.getCommandUrl(
|
||||
isEvent(item) ? "deleteevents_by_id" : "deletetodos_by_id" );
|
||||
url += ("&calid=" + encodeURIComponent(this.calId));
|
||||
url += ("&uid=" + item.id);
|
||||
url += ("&uid=" + encodeURIComponent(item.id));
|
||||
|
||||
if (isParent(item)) // delete THIS AND ALL:
|
||||
url += "&mod=4&rid=0";
|
||||
@ -760,6 +758,20 @@ calWcapCalendar.prototype.parseItems = function(
|
||||
icalRootComp, itemFilter, maxResult, rangeStart, rangeEnd,
|
||||
bLeaveMutable )
|
||||
{
|
||||
var items = [];
|
||||
this.parseItems_(
|
||||
function(srcItems) { items = items.concat(srcItems) },
|
||||
icalRootComp, items, maxResult, rangeStart, rangeEnd,
|
||||
bLeaveMutable);
|
||||
return items;
|
||||
};
|
||||
|
||||
calWcapCalendar.prototype.parseItems_ = function(
|
||||
receiverFunc,
|
||||
icalRootComp, itemFilter, maxResult, rangeStart, rangeEnd,
|
||||
bLeaveMutable )
|
||||
{
|
||||
var nItems = 0;
|
||||
var unexpandedItems = [];
|
||||
var uid2parent = {};
|
||||
var excItems = [];
|
||||
@ -845,36 +857,14 @@ calWcapCalendar.prototype.parseItems = function(
|
||||
var ar = contactsProp.value.split(":");
|
||||
if (ar.length > 1) {
|
||||
var lastAck = ar[1];
|
||||
if (lastAck.length > 0) {
|
||||
var dtLastAck = new CalDateTime();
|
||||
dtLastAck.icalString = lastAck; // TZID is UTC
|
||||
dtLastAck.normalize();
|
||||
// shift to alarm comp:
|
||||
item.alarmLastAck = dtLastAck;
|
||||
if (lastAck.length > 0) { // shift to alarm comp:
|
||||
item.alarmLastAck = getDatetimeFromIcalString(
|
||||
lastAck); // TZID is UTC
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item.calendar = this_.superCalendar;
|
||||
var rid = subComp.getFirstProperty("RECURRENCE-ID");
|
||||
if (rid == null) {
|
||||
unexpandedItems.push( item );
|
||||
if (item.recurrenceInfo != null)
|
||||
uid2parent[item.id] = item;
|
||||
}
|
||||
else {
|
||||
// xxx todo: IMO ought not be needed here: TZID is UTC
|
||||
var dtrid = getDatetimeFromIcalProp(rid);
|
||||
if (LOG_LEVEL > 1) {
|
||||
this_.log( "exception item: rid=" + dtrid.icalString );
|
||||
}
|
||||
item.recurrenceId = dtrid;
|
||||
// force no recurrence info:
|
||||
item.recurrenceInfo = null;
|
||||
excItems.push( item );
|
||||
}
|
||||
|
||||
if (item.title == null) {
|
||||
if (!item.title) {
|
||||
// assumed to look at a subscribed calendar,
|
||||
// so patch title for private items:
|
||||
switch (item.privacy) {
|
||||
@ -886,65 +876,105 @@ calWcapCalendar.prototype.parseItems = function(
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
item.calendar = this_.superCalendar;
|
||||
var rid = item.recurrenceId;
|
||||
if (rid) {
|
||||
if (LOG_LEVEL > 1) {
|
||||
this_.log( "exception item: " + item.title +
|
||||
"\nrid=" + rid.icalString,
|
||||
"item.id=" + item.id );
|
||||
}
|
||||
excItems.push( item );
|
||||
}
|
||||
else if (item.recurrenceInfo) {
|
||||
unexpandedItems.push( item );
|
||||
uid2parent[item.id] = item;
|
||||
}
|
||||
else if (maxResult == 0 || nItems < maxResult) {
|
||||
if (LOG_LEVEL > 2) {
|
||||
this_.log( "item: " + item.title + "\n" +
|
||||
item.icalString );
|
||||
}
|
||||
if (!bLeaveMutable)
|
||||
item.makeImmutable();
|
||||
receiverFunc( [item] );
|
||||
}
|
||||
}
|
||||
},
|
||||
maxResult );
|
||||
|
||||
|
||||
// tag "exceptions", i.e. items with rid:
|
||||
for each ( var item in excItems ) {
|
||||
var parent = uid2parent[item.id];
|
||||
if (parent == null) {
|
||||
this.logError( "parseItems(): no parent item for rid=" +
|
||||
item.recurrenceId );
|
||||
}
|
||||
else {
|
||||
if (parent) {
|
||||
item.parentItem = parent;
|
||||
item.makeImmutable();
|
||||
parent.recurrenceInfo.modifyException( item );
|
||||
}
|
||||
else {
|
||||
this.logError( "parseItems(): no parent item for " + item.title +
|
||||
", rid=" + item.recurrenceId.icalString,
|
||||
"item.id=" + item.id );
|
||||
// xxx todo: due to a server bug, in some scenarions the returned
|
||||
// data is lacking the parent item, leave parentItem open
|
||||
if (!bLeaveMutable)
|
||||
item.makeImmutable();
|
||||
receiverFunc( [item] );
|
||||
}
|
||||
}
|
||||
|
||||
var items = [];
|
||||
for ( var i = 0;
|
||||
(i < unexpandedItems.length) &&
|
||||
(maxResult == 0 || items.length < maxResult);
|
||||
++i )
|
||||
if (itemFilter & Components.interfaces.calICalendar
|
||||
.ITEM_FILTER_CLASS_OCCURRENCES)
|
||||
{
|
||||
var item = unexpandedItems[i];
|
||||
if (!bLeaveMutable)
|
||||
item.makeImmutable();
|
||||
if (item.recurrenceInfo != null &&
|
||||
(itemFilter & Components.interfaces.calICalendar
|
||||
.ITEM_FILTER_CLASS_OCCURRENCES))
|
||||
{
|
||||
for each ( var item in unexpandedItems ) {
|
||||
if (maxResult != 0 && nItems >= maxResult)
|
||||
break;
|
||||
if (!bLeaveMutable)
|
||||
item.makeImmutable();
|
||||
var occurrences = item.recurrenceInfo.getOccurrences(
|
||||
rangeStart, rangeEnd,
|
||||
maxResult == 0 ? 0 : maxResult - items.length,
|
||||
maxResult == 0 ? 0 : maxResult - nItems,
|
||||
{} );
|
||||
if (LOG_LEVEL > 1) {
|
||||
this.log( "item: " + item.title + " has " +
|
||||
occurrences.length.toString() + " occurrences." );
|
||||
if (LOG_LEVEL > 2) {
|
||||
for each ( var occ in occurrences ) {
|
||||
this.log("item: " + occ.title + "\n" + occ.icalString);
|
||||
}
|
||||
}
|
||||
}
|
||||
// only proxies returned:
|
||||
items = items.concat( occurrences );
|
||||
}
|
||||
else {
|
||||
items.push( item );
|
||||
receiverFunc( occurrences );
|
||||
nItems += occurrences.length;
|
||||
}
|
||||
}
|
||||
|
||||
if (LOG_LEVEL > 1) {
|
||||
this.log( "parseItems(): returned " + items.length + " items" );
|
||||
else {
|
||||
if (maxResult != 0 &&
|
||||
(nItems + unexpandedItems.length) > maxResult) {
|
||||
unexpandedItems.length = (maxResult - nItems);
|
||||
}
|
||||
if (!bLeaveMutable) {
|
||||
for each ( var item in unexpandedItems ) {
|
||||
item.makeImmutable();
|
||||
}
|
||||
}
|
||||
if (LOG_LEVEL > 2) {
|
||||
for each ( var item in items ) {
|
||||
for each ( var item in unexpandedItems ) {
|
||||
this.log( "item: " + item.title + "\n" + item.icalString );
|
||||
}
|
||||
}
|
||||
receiverFunc( unexpandedItems );
|
||||
nItems += unexpandedItems.length;
|
||||
}
|
||||
|
||||
if (LOG_LEVEL > 1) {
|
||||
this.log( "parseItems_(): notified " + nItems + " items" );
|
||||
}
|
||||
return items;
|
||||
};
|
||||
|
||||
calWcapCalendar.prototype.getItem = function( id, listener )
|
||||
calWcapCalendar.prototype.getItem_queued = function( id, listener )
|
||||
{
|
||||
// xxx todo: test
|
||||
// xxx todo: howto detect whether to call
|
||||
@ -983,18 +1013,17 @@ calWcapCalendar.prototype.getItem = function( id, listener )
|
||||
|
||||
var params = ("&relativealarm=1&compressed=1&recurring=1" +
|
||||
"&fmt-out=text%2Fcalendar");
|
||||
params += ("&calid=" + encodeURIComponent(this.calId));
|
||||
params += ("&uid=" + id);
|
||||
params += ("&uid=" + encodeURIComponent(id));
|
||||
try {
|
||||
// most common: event
|
||||
this.session.issueSyncRequest(
|
||||
this.session.getCommandUrl( "fetchevents_by_id" ) + params,
|
||||
this.getCommandUrl( "fetchevents_by_id" ) + params,
|
||||
stringToIcal, syncResponseFunc );
|
||||
}
|
||||
catch (exc) {
|
||||
// try again, may be a task:
|
||||
this.session.issueSyncRequest(
|
||||
this.session.getCommandUrl( "fetchtodos_by_id" ) + params,
|
||||
this.getCommandUrl( "fetchtodos_by_id" ) + params,
|
||||
stringToIcal, syncResponseFunc );
|
||||
}
|
||||
}
|
||||
@ -1077,28 +1106,36 @@ calWcapCalendar.prototype.getItems_resp = function(
|
||||
};
|
||||
this.session.getFreeBusyTimes(
|
||||
this.calId, rangeStart, rangeEnd, true /*bBusyOnly*/,
|
||||
freeBusyListener,
|
||||
true /*bAsync*/, 0 /*requestId*/ );
|
||||
freeBusyListener, true/*async*/, 0 /*requestId*/ );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var icalRootComp = wcapResponse.data; // first statement, may throw
|
||||
|
||||
var items = this.parseItems(
|
||||
icalRootComp, itemFilter, maxResult, rangeStart, rangeEnd );
|
||||
|
||||
if (listener != null) {
|
||||
listener.onGetResult( this.superCalendar, Components.results.NS_OK,
|
||||
Components.interfaces.calIItemBase,
|
||||
this.log( "getItems(): success." ),
|
||||
items.length, items );
|
||||
if (listener) {
|
||||
var this_ = this;
|
||||
function deliverItems(items) {
|
||||
listener.onGetResult(
|
||||
this_.superCalendar, Components.results.NS_OK,
|
||||
Components.interfaces.calIItemBase,
|
||||
"WCAP getItems_resp()",
|
||||
items.length, items );
|
||||
}
|
||||
this.parseItems_(
|
||||
deliverItems,
|
||||
icalRootComp, itemFilter, maxResult, rangeStart, rangeEnd );
|
||||
listener.onOperationComplete(
|
||||
this.superCalendar, Components.results.NS_OK,
|
||||
Components.interfaces.calIOperationListener.GET,
|
||||
items.length == 1 ? items[0].id : null, null );
|
||||
this.log( items.length.toString() + " items delivered." );
|
||||
null, null );
|
||||
}
|
||||
else {
|
||||
// just to check returned data:
|
||||
this.parseItems(
|
||||
icalRootComp, itemFilter, maxResult, rangeStart, rangeEnd );
|
||||
}
|
||||
this.log( "getItems(): success." );
|
||||
}
|
||||
catch (exc) {
|
||||
if (listener != null) {
|
||||
@ -1143,7 +1180,7 @@ function getItemFilterUrlPortions( itemFilter )
|
||||
return url;
|
||||
}
|
||||
|
||||
calWcapCalendar.prototype.getItems = function(
|
||||
calWcapCalendar.prototype.getItems_queued = function(
|
||||
itemFilter, maxResult, rangeStart, rangeEnd, listener )
|
||||
{
|
||||
// assure DATETIMEs:
|
||||
@ -1162,17 +1199,15 @@ calWcapCalendar.prototype.getItems = function(
|
||||
",\n\trangeStart=" + zRangeStart +
|
||||
",\n\trangeEnd=" + zRangeEnd );
|
||||
try {
|
||||
var url = this.session.getCommandUrl( "fetchcomponents_by_range" );
|
||||
var url = this.getCommandUrl( "fetchcomponents_by_range" );
|
||||
url += ("&relativealarm=1&compressed=1&recurring=1" +
|
||||
"&fmt-out=text%2Fcalendar&calid=" +
|
||||
encodeURIComponent(this.calId));
|
||||
"&fmt-out=text%2Fcalendar");
|
||||
|
||||
// setting component-type, compstate filters:
|
||||
url += getItemFilterUrlPortions(itemFilter);
|
||||
|
||||
if (maxResult > 0)
|
||||
url += ("&maxResult=" + maxResult);
|
||||
// xxx todo: correctly normalized dates to zulu time?
|
||||
url += ("&dtstart=" + zRangeStart);
|
||||
url += ("&dtend=" + zRangeEnd);
|
||||
|
||||
@ -1203,6 +1238,7 @@ calWcapCalendar.prototype.getItems = function(
|
||||
this.log( "getItems() returning." );
|
||||
};
|
||||
|
||||
|
||||
function SyncState( finishFunc, abortFunc ) {
|
||||
this.m_finishFunc = finishFunc;
|
||||
this.m_abortFunc = abortFunc;
|
||||
@ -1214,9 +1250,7 @@ SyncState.prototype = {
|
||||
m_exc: null,
|
||||
|
||||
acquire: function() { /*this.checkAborted();*/ ++this.m_state; },
|
||||
release:
|
||||
function()
|
||||
{
|
||||
release: function() {
|
||||
/*this.checkAborted();*/
|
||||
--this.m_state;
|
||||
// logMessage( "sync-state", "m_state = " + this.m_state );
|
||||
@ -1229,9 +1263,9 @@ SyncState.prototype = {
|
||||
if (this.m_exc)
|
||||
throw this.m_exc;
|
||||
},
|
||||
get hasAborted() { return this.m_exc != null; },
|
||||
get isAborted() { return this.m_exc != null; },
|
||||
abort: function( exc ) {
|
||||
if (!this.hasAborted) // store only first error that has occurred
|
||||
if (!this.isAborted) // store only first error that has occurred
|
||||
this.m_exc = exc;
|
||||
this.m_abortFunc( exc );
|
||||
}
|
||||
@ -1273,14 +1307,11 @@ calWcapCalendar.prototype.syncChangesTo_resp = function(
|
||||
{
|
||||
try {
|
||||
var icalRootComp = wcapResponse.data; // first statement, may throw
|
||||
var items = this.parseItems(
|
||||
var items = this.parseItems_(
|
||||
function(items) { items.forEach(func) },
|
||||
icalRootComp,
|
||||
Components.interfaces.calICalendar.ITEM_FILTER_ALL_ITEMS,
|
||||
0, null, null );
|
||||
for each ( var item in items ) {
|
||||
// xxx todo: ignore single errors and continue?
|
||||
func( item );
|
||||
}
|
||||
}
|
||||
catch (exc) {
|
||||
syncState.abort( exc );
|
||||
@ -1288,11 +1319,10 @@ calWcapCalendar.prototype.syncChangesTo_resp = function(
|
||||
syncState.release();
|
||||
};
|
||||
|
||||
calWcapCalendar.prototype.syncChangesTo = function(
|
||||
calWcapCalendar.prototype.syncChangesTo_queued = function(
|
||||
destCal, itemFilter, dtFrom_, listener )
|
||||
{
|
||||
var dtFrom = dtFrom_;
|
||||
// this.ensureOnline();
|
||||
if (dtFrom) {
|
||||
dtFrom = dtFrom.clone();
|
||||
// assure DATETIMEs:
|
||||
@ -1322,8 +1352,8 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
var syncState = new SyncState(
|
||||
// finishFunc:
|
||||
function() {
|
||||
if (listener != null) {
|
||||
if (syncState.hasAborted) {
|
||||
if (listener) {
|
||||
if (syncState.isAborted) {
|
||||
this_.log( "firing SYNC failed!" );
|
||||
listener.onOperationComplete(
|
||||
this_.superCalendar,
|
||||
@ -1340,7 +1370,7 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
},
|
||||
// abortFunc:
|
||||
function( exc ) {
|
||||
if (listener != null) {
|
||||
if (listener) {
|
||||
listener.onOperationComplete(
|
||||
this_.superCalendar,
|
||||
Components.results.NS_ERROR_FAILURE,
|
||||
@ -1353,17 +1383,17 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
Components.interfaces.calIOperationListener.ADD, syncState );
|
||||
var modifiedItems = [];
|
||||
|
||||
this.log( "syncChangesTo(): getting last modifications..." );
|
||||
this.log( "getting last modifications...", "syncChangesTo()" );
|
||||
var modifyItemListener = new FinishListener(
|
||||
Components.interfaces.calIOperationListener.MODIFY, syncState );
|
||||
var params = ("&relativealarm=1&compressed=1&recurring=1&calid=" +
|
||||
encodeURIComponent(this.calId));
|
||||
params += ("&fmt-out=text%2Fcalendar&dtstart=" + zdtFrom);
|
||||
params += ("&dtend=" + getIcalUTC( this.session.getServerTime(now) ));
|
||||
var params = ("&relativealarm=1&compressed=1&recurring=1" +
|
||||
"&fmt-out=text%2Fcalendar");
|
||||
params += ("&dtstart=" + zdtFrom);
|
||||
params += ("&dtend=" + getIcalUTC(this.session.getServerTime(now)));
|
||||
|
||||
syncState.acquire();
|
||||
this.session.issueAsyncRequest(
|
||||
this.session.getCommandUrl("fetchcomponents_by_lastmod") +
|
||||
this.getCommandUrl("fetchcomponents_by_lastmod") +
|
||||
params + getItemFilterUrlPortions(itemFilter),
|
||||
stringToIcal,
|
||||
function( wcapResponse ) {
|
||||
@ -1377,7 +1407,8 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
if (bAdd) {
|
||||
// xxx todo: verify whether exceptions
|
||||
// have been written
|
||||
this_.log( "new item: " + item.id );
|
||||
this_.log( "new item: " + item.id,
|
||||
"syncChangesTo_resp()" );
|
||||
if (destCal) {
|
||||
syncState.acquire();
|
||||
destCal.addItem( item, addItemListener );
|
||||
@ -1386,7 +1417,8 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
calObserver.onAddItem( item );
|
||||
}
|
||||
else {
|
||||
this_.log( "modified item: " + item.id );
|
||||
this_.log( "modified item: " + item.id,
|
||||
"syncChangesTo_resp()" );
|
||||
if (destCal) {
|
||||
syncState.acquire();
|
||||
destCal.modifyItem( item, null,
|
||||
@ -1398,12 +1430,12 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
} );
|
||||
} );
|
||||
|
||||
this.log( "syncChangesTo(): getting deleted items..." );
|
||||
this.log( "getting deleted items...", "syncChangesTo()" );
|
||||
var deleteItemListener = new FinishListener(
|
||||
Components.interfaces.calIOperationListener.DELETE, syncState );
|
||||
syncState.acquire();
|
||||
this.session.issueAsyncRequest(
|
||||
this.session.getCommandUrl("fetch_deletedcomponents") + params +
|
||||
this.getCommandUrl("fetch_deletedcomponents") + params +
|
||||
getItemFilterUrlPortions( itemFilter & // only component-type
|
||||
Components.interfaces.calICalendar
|
||||
.ITEM_FILTER_TYPE_ALL ),
|
||||
@ -1414,14 +1446,15 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
function( item ) {
|
||||
// don't delete anything that has been touched
|
||||
// by lastmods:
|
||||
for each ( var mid in modifiedItems ) {
|
||||
if (item.id == mid) {
|
||||
this_.log( "skipping deletion of " + item.id );
|
||||
return;
|
||||
}
|
||||
if (modifiedItems.some(
|
||||
function(mid) { return (item.id == mid); } )) {
|
||||
this_.log( "skipping deletion of " + item.id,
|
||||
"syncChangesTo_resp()" );
|
||||
return;
|
||||
}
|
||||
if (isParent(item)) {
|
||||
this_.log( "deleted item: " + item.id );
|
||||
this_.log( "deleted item: " + item.id,
|
||||
"syncChangesTo_resp()" );
|
||||
if (destCal) {
|
||||
syncState.acquire();
|
||||
destCal.deleteItem(
|
||||
@ -1436,7 +1469,8 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
var parent = item.parentItem.clone();
|
||||
parent.recurrenceInfo.removeOccurrenceAt(
|
||||
item.recurrenceId );
|
||||
this_.log( "modified parent: " + parent.id );
|
||||
this_.log( "modified parent: " + parent.id,
|
||||
"syncChangesTo_resp()" );
|
||||
if (destCal) {
|
||||
syncState.acquire();
|
||||
destCal.modifyItem( parent, item,
|
||||
@ -1459,7 +1493,7 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
SYNC, null, dtFrom_ /* pass original stamp:
|
||||
=> empty sync range */ );
|
||||
}
|
||||
this.logError( "syncChangesTo() ignored: " + errorToString(exc) );
|
||||
this.logError("ignored: " + errorToString(exc), "syncChangesTo()");
|
||||
}
|
||||
else {
|
||||
if (listener) {
|
||||
@ -1470,6 +1504,6 @@ calWcapCalendar.prototype.syncChangesTo = function(
|
||||
this.notifyError( exc );
|
||||
}
|
||||
}
|
||||
this.log( "syncChangesTo() returning." );
|
||||
this.log( "finished.", "syncChangesTo()" );
|
||||
};
|
||||
|
||||
|
||||
@ -57,6 +57,7 @@ var CalTodo;
|
||||
var CalDateTime;
|
||||
var CalDuration;
|
||||
var XmlHttpRequest;
|
||||
var Timer;
|
||||
|
||||
// some string resources:
|
||||
var g_privateItemTitle;
|
||||
@ -70,9 +71,6 @@ var CACHE = "off";
|
||||
// denotes where to host local storage calendar(s)
|
||||
var CACHE_DIR = null;
|
||||
|
||||
// timeout for sync network requests (in secs):
|
||||
var SYNC_REQUESTS_TIMEOUT = 10;
|
||||
|
||||
// logging:
|
||||
#expand var LOG_LEVEL = __LOG_LEVEL__;
|
||||
var LOG_TIMEZONE = null;
|
||||
@ -95,6 +93,8 @@ function initWcapProvider()
|
||||
"@mozilla.org/calendar/duration;1", "calIDuration" );
|
||||
XmlHttpRequest = new Components.Constructor(
|
||||
"@mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest" );
|
||||
Timer = new Components.Constructor(
|
||||
"@mozilla.org/timer;1", "nsITimer" );
|
||||
|
||||
// some string resources:
|
||||
g_privateItemTitle = getWcapBundle().GetStringFromName(
|
||||
@ -105,9 +105,6 @@ function initWcapProvider()
|
||||
"busyItem.title.text");
|
||||
g_busyPhantomItemUuidPrefix = ("PHANTOM_uuid" + getTime().icalString);
|
||||
|
||||
SYNC_REQUESTS_TIMEOUT = getPref(
|
||||
"calendar.wcap.sync_request_timeout", 10);
|
||||
|
||||
LOG_TIMEZONE = getPref("calendar.timezone.local", null);
|
||||
|
||||
var logLevel = getPref("calendar.wcap.log_level", null);
|
||||
@ -192,7 +189,7 @@ var calWcapCalendarModule = { // nsIModule:
|
||||
|
||||
WcapSessionInfo: {
|
||||
classDescription: "Sun Java System Calendar Server WCAP Session",
|
||||
contractID: "@mozilla.org/calendar/session;1?type=wcap",
|
||||
contractID: "@mozilla.org/calendar/wcap/session;1",
|
||||
classID: Components.ID("{CBF803FD-4469-4999-AE39-367AF1C7B077}")
|
||||
},
|
||||
|
||||
|
||||
@ -175,11 +175,19 @@ function streamToString( inStream, charset )
|
||||
var convStream =
|
||||
Components.classes["@mozilla.org/intl/converter-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIConverterInputStream);
|
||||
convStream.init( inStream, charset, 0, 0x0000 );
|
||||
var str = "";
|
||||
var str_ = {};
|
||||
while (convStream.readString( -1, str_ )) {
|
||||
str += str_.value;
|
||||
try {
|
||||
convStream.init( inStream, charset, 0, 0x0000 );
|
||||
var str = "";
|
||||
var str_ = {};
|
||||
while (convStream.readString( -1, str_ )) {
|
||||
str += str_.value;
|
||||
}
|
||||
}
|
||||
catch (exc) {
|
||||
throw new Components.Exception(
|
||||
"error converting stream: " + errorToString(exc) +
|
||||
"\ncharset: " + charset +
|
||||
"\npartially read string: " + str, exc );
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@ -192,24 +200,12 @@ function issueSyncRequest( url, receiverFunc, bLogging )
|
||||
logMessage( "issueSyncRequest( \"" + url + "\" )",
|
||||
"opening channel." );
|
||||
}
|
||||
|
||||
var channel = getIoService().newChannel(
|
||||
url, "" /* charset */, null /* baseURI */ );
|
||||
channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
|
||||
var timer = Components.classes["@mozilla.org/timer;1"]
|
||||
.createInstance(Components.interfaces.nsITimer);
|
||||
timer.initWithCallback(
|
||||
{ // nsITimerCallback:
|
||||
notify: function( timer_ ) {
|
||||
if (channel.isPending())
|
||||
channel.cancel(NS_BINDING_FAILED);
|
||||
}
|
||||
},
|
||||
SYNC_REQUESTS_TIMEOUT * 1000,
|
||||
Components.interfaces.nsITimer.TYPE_ONE_SHOT );
|
||||
var stream = channel.open();
|
||||
timer.cancel();
|
||||
|
||||
var stream = channel.open();
|
||||
var status = channel.status;
|
||||
if (status == Components.results.NS_OK) {
|
||||
var charset = channel.contentCharset;
|
||||
|
||||
@ -45,6 +45,13 @@ function calWcapSession() {
|
||||
this.wrappedJSObject = this;
|
||||
this.m_observers = [];
|
||||
this.m_calIdToCalendar = {};
|
||||
this.m_asyncQueue = new AsyncQueue();
|
||||
this.m_calPropsTimer = new Timer();
|
||||
|
||||
// init queued calls:
|
||||
this.getFreeBusyTimes = makeQueuedCall(this.asyncQueue,
|
||||
this, this.getFreeBusyTimes_queued);
|
||||
|
||||
// listen for shutdown, being logged out:
|
||||
// network:offline-about-to-go-offline will be fired for
|
||||
// XPCOM shutdown, too.
|
||||
@ -57,7 +64,11 @@ function calWcapSession() {
|
||||
observerService.addObserver( this, "network:offline-about-to-go-offline",
|
||||
false /* don't hold weakly: xxx todo */ );
|
||||
}
|
||||
|
||||
calWcapSession.prototype = {
|
||||
m_asyncQueue: null,
|
||||
get asyncQueue() { return this.m_asyncQueue; },
|
||||
|
||||
m_ifaces: [ Components.interfaces.calIWcapSession,
|
||||
Components.interfaces.nsIInterfaceRequestor,
|
||||
Components.interfaces.nsIClassInfo,
|
||||
@ -270,6 +281,7 @@ calWcapSession.prototype = {
|
||||
|
||||
m_sessionId: null,
|
||||
m_bNoLoginsAnymore: false,
|
||||
m_calPropsTimer: null,
|
||||
|
||||
getSessionId:
|
||||
function( timedOutSessionId )
|
||||
@ -290,74 +302,83 @@ calWcapSession.prototype = {
|
||||
|
||||
if (!this.m_sessionId || this.m_sessionId == timedOutSessionId) {
|
||||
|
||||
var this_ = this;
|
||||
lockedExec(
|
||||
function() {
|
||||
if (!this_.m_bNoLoginsAnymore &&
|
||||
(!this_.m_sessionId ||
|
||||
this_.m_sessionId == timedOutSessionId)) {
|
||||
|
||||
try {
|
||||
this_.m_sessionId = null;
|
||||
if (timedOutSessionId != null) {
|
||||
this_.log( "session timeout; " +
|
||||
"prompting to reconnect." );
|
||||
var prompt =
|
||||
getWindowWatcher().getNewPrompter(null);
|
||||
var bundle = getWcapBundle();
|
||||
if (!prompt.confirm(
|
||||
bundle.GetStringFromName(
|
||||
"reconnectConfirmation.label"),
|
||||
bundle.formatStringFromName(
|
||||
"reconnectConfirmation.text",
|
||||
[this_.uri.hostPort], 1 ) )) {
|
||||
this_.log( "reconnect cancelled." );
|
||||
throw new Components.Exception(
|
||||
"Login failed. Invalid session ID.",
|
||||
Components.interfaces.
|
||||
calIWcapErrors.WCAP_LOGIN_FAILED );
|
||||
}
|
||||
}
|
||||
|
||||
var sessionUri = this_.uri.clone();
|
||||
sessionUri.userPass = "";
|
||||
if (sessionUri.scheme.toLowerCase() != "https" &&
|
||||
sessionUri.port == -1 /* no port specified */)
|
||||
{
|
||||
// silently probe for https support:
|
||||
try { // enforce https:
|
||||
sessionUri.scheme = "https";
|
||||
this_.getSessionId_(sessionUri);
|
||||
}
|
||||
catch (exc) {
|
||||
// restore scheme:
|
||||
sessionUri.scheme = this_.uri.scheme;
|
||||
if (testResultCode(
|
||||
exc, Components.interfaces.
|
||||
calIWcapErrors.WCAP_LOGIN_FAILED))
|
||||
throw exc; // forward login failures
|
||||
// but ignore connection errors
|
||||
}
|
||||
}
|
||||
if (!this_.m_sessionId)
|
||||
this_.getSessionId_(sessionUri);
|
||||
}
|
||||
catch (exc) {
|
||||
this_.m_bNoLoginsAnymore = true;
|
||||
this_.logError( exc );
|
||||
this_.log( "no logins anymore." );
|
||||
throw exc;
|
||||
}
|
||||
|
||||
this_.getServerTimeDiff(true /* refresh */);
|
||||
this_.getSupportedTimezones(true /* refresh */);
|
||||
// preread calprops for subscribed calendars:
|
||||
var cals = this_.getSubscribedCalendars({});
|
||||
for each ( cal in cals ) {
|
||||
cal.getCalProps_(true /* async */);
|
||||
}
|
||||
try {
|
||||
this.m_sessionId = null;
|
||||
if (timedOutSessionId) {
|
||||
this.log( "session timeout; prompting to reconnect." );
|
||||
var prompt = getWindowWatcher().getNewPrompter(null);
|
||||
var bundle = getWcapBundle();
|
||||
if (!prompt.confirm(
|
||||
bundle.GetStringFromName(
|
||||
"reconnectConfirmation.label"),
|
||||
bundle.formatStringFromName(
|
||||
"reconnectConfirmation.text",
|
||||
[this.uri.hostPort], 1 ) )) {
|
||||
this.log( "reconnect cancelled." );
|
||||
throw new Components.Exception(
|
||||
"Login failed. Invalid session ID.",
|
||||
Components.interfaces.
|
||||
calIWcapErrors.WCAP_LOGIN_FAILED );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
var sessionUri = this.uri.clone();
|
||||
sessionUri.userPass = "";
|
||||
if (sessionUri.scheme.toLowerCase() != "https" &&
|
||||
sessionUri.port == -1 /* no port specified */)
|
||||
{
|
||||
// silently probe for https support:
|
||||
try { // enforce https:
|
||||
sessionUri.scheme = "https";
|
||||
this.getSessionId_(sessionUri);
|
||||
}
|
||||
catch (exc) {
|
||||
// restore scheme:
|
||||
sessionUri.scheme = this.uri.scheme;
|
||||
if (testResultCode( exc, Components.interfaces.
|
||||
calIWcapErrors.WCAP_LOGIN_FAILED))
|
||||
throw exc; // forward login failures
|
||||
// but ignore connection errors
|
||||
}
|
||||
}
|
||||
if (!this.m_sessionId)
|
||||
this.getSessionId_(sessionUri);
|
||||
}
|
||||
catch (exc) {
|
||||
this.m_bNoLoginsAnymore = true;
|
||||
this.logError( exc );
|
||||
this.log( "no logins anymore." );
|
||||
throw exc;
|
||||
}
|
||||
|
||||
this.getServerTimeDiff(true /* refresh */);
|
||||
|
||||
if (!timedOutSessionId) // timezones don't change that frequently
|
||||
this.getSupportedTimezones(true /* refresh */);
|
||||
|
||||
// invalidate calprops of all calendars:
|
||||
var cals = this.getSubscribedCalendars({});
|
||||
for each ( cal in cals ) {
|
||||
cal.m_calProps = null;
|
||||
}
|
||||
|
||||
this.m_calPropsTimer.initWithCallback(
|
||||
{ // nsITimerCallback:
|
||||
m_pos: 0,
|
||||
m_session: this,
|
||||
notify: function(timer_) {
|
||||
var cals = this.m_session.getSubscribedCalendars({});
|
||||
var c = (cals.length - this.m_pos);
|
||||
if (c > 5)
|
||||
c = 5;
|
||||
while (c--)
|
||||
cals[this.m_pos++].getCalProps_(true /*async*/);
|
||||
if (this.m_pos >= cals.length)
|
||||
timer_.cancel();
|
||||
}
|
||||
},
|
||||
15 * 1000,
|
||||
Components.interfaces.nsITimer.TYPE_REPEATING_SLACK );
|
||||
}
|
||||
|
||||
if (!this.m_sessionId) {
|
||||
@ -518,7 +539,7 @@ calWcapSession.prototype = {
|
||||
this.m_sessionId = prop.value;
|
||||
this.m_userId = user;
|
||||
this.m_sessionUri = sessionUri;
|
||||
this.log( "WCAP login succeeded, setting sessionUri to " +
|
||||
this.log( "login succeeded, setting sessionUri to " +
|
||||
this.sessionUri.spec );
|
||||
return true;
|
||||
},
|
||||
@ -538,7 +559,7 @@ calWcapSession.prototype = {
|
||||
icalRootComp = getIcsService().parseICS( str );
|
||||
}
|
||||
catch (exc) {
|
||||
this.log( exc ); // soft error; request denied etc.
|
||||
this.log( errorToString(exc) ); // soft error; request denied etc.
|
||||
throw new Components.Exception(
|
||||
getWcapBundle().formatStringFromName(
|
||||
"accessingServerFailedError.text", [uri.hostPort], 1 ),
|
||||
@ -689,6 +710,16 @@ calWcapSession.prototype = {
|
||||
return ((list && list.length > 0) ? list[0] : this.userId);
|
||||
},
|
||||
|
||||
assureLoggedIn:
|
||||
function()
|
||||
{
|
||||
if (!this.isLoggedIn) {
|
||||
throw new Components.Exception(
|
||||
"Not logged in yet.",
|
||||
Components.results.NS_ERROR_NOT_AVAILABLE);
|
||||
}
|
||||
},
|
||||
|
||||
get isLoggedIn() { return this.m_sessionId != null; },
|
||||
|
||||
login:
|
||||
@ -712,10 +743,10 @@ calWcapSession.prototype = {
|
||||
try {
|
||||
checkWcapXmlErrno( issueSyncXMLRequest(url),
|
||||
-1 /* logout successfull */ );
|
||||
this.log( "WCAP logout succeeded." );
|
||||
this.log( "logout succeeded." );
|
||||
}
|
||||
catch (exc) {
|
||||
this.log( "WCAP logout failed: " + exc );
|
||||
this.log( "logout failed: " + exc );
|
||||
Components.utils.reportError( exc );
|
||||
}
|
||||
this.m_sessionId = null;
|
||||
@ -802,6 +833,7 @@ calWcapSession.prototype = {
|
||||
function( calId, name, bAllowDoubleBooking, bSetCalProps, bAddToSubscribed )
|
||||
{
|
||||
try {
|
||||
this.assureLoggedIn();
|
||||
var url = this.getCommandUrl( "createcalendar" );
|
||||
url += ("&allowdoublebook=" + (bAllowDoubleBooking ? "1" : "0"));
|
||||
url += ("&set_calprops=" + (bSetCalProps ? "1" : "0"));
|
||||
@ -824,6 +856,7 @@ calWcapSession.prototype = {
|
||||
function( calId, bRemoveFromSubscribed )
|
||||
{
|
||||
try {
|
||||
this.assureLoggedIn();
|
||||
var url = this.getCommandUrl( "deletecalendar" );
|
||||
url += ("&unsubscribe=" + (bRemoveFromSubscribed ? "1" : "0"));
|
||||
url += ("&calid=" + encodeURIComponent(calId));
|
||||
@ -841,6 +874,7 @@ calWcapSession.prototype = {
|
||||
function( calIds, bSubscribe )
|
||||
{
|
||||
try {
|
||||
this.assureLoggedIn();
|
||||
var url = this.getCommandUrl(
|
||||
bSubscribe ? "subscribe_calendars" : "unsubscribe_calendars" );
|
||||
var calId = "";
|
||||
@ -849,7 +883,7 @@ calWcapSession.prototype = {
|
||||
calId += ";";
|
||||
calId += encodeURIComponent(calIds[i]);
|
||||
}
|
||||
url += ("&calid=" + calId);
|
||||
url += ("&calid=" + encodeURIComponent(calId));
|
||||
this.issueSyncRequest( url + "&fmt-out=text%2Fxml", stringToXml );
|
||||
this.m_userPrefs = null; // reread prefs
|
||||
}
|
||||
@ -877,6 +911,7 @@ calWcapSession.prototype = {
|
||||
{
|
||||
try {
|
||||
if (this.m_userPrefs == null) {
|
||||
this.assureLoggedIn();
|
||||
var url = this.getCommandUrl( "get_userprefs" );
|
||||
url += ("&userid=" + encodeURIComponent(this.userId));
|
||||
this.m_userPrefs = this.issueSyncRequest(
|
||||
@ -908,10 +943,8 @@ calWcapSession.prototype = {
|
||||
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 start = getDatetimeFromIcalString(str.substr(0, slash));
|
||||
var end = getDatetimeFromIcalString(str.substr(slash + 1));
|
||||
var entry = {
|
||||
isBusyEntry:
|
||||
(item.attributes.getNamedItem("FBTYPE").nodeValue
|
||||
@ -926,8 +959,9 @@ calWcapSession.prototype = {
|
||||
requestId, calId, ret.length, ret );
|
||||
}
|
||||
if (LOG_LEVEL > 0) {
|
||||
this.log( "getFreeBusyTimes_resp() calId=" + calId + ", " +
|
||||
getWcapRequestStatusString(xml) );
|
||||
this.log( "calId=" + calId + ", " +
|
||||
getWcapRequestStatusString(xml),
|
||||
"getFreeBusyTimes_resp()" );
|
||||
}
|
||||
}
|
||||
catch (exc) {
|
||||
@ -948,9 +982,8 @@ calWcapSession.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
getFreeBusyTimes:
|
||||
function( calId, rangeStart, rangeEnd, bBusyOnly, listener,
|
||||
bAsync, requestId )
|
||||
getFreeBusyTimes_queued:
|
||||
function( calId, rangeStart, rangeEnd, bBusyOnly, listener, b, requestId )
|
||||
{
|
||||
try {
|
||||
// assure DATETIMEs:
|
||||
@ -964,9 +997,11 @@ calWcapSession.prototype = {
|
||||
}
|
||||
var zRangeStart = getIcalUTC(rangeStart);
|
||||
var zRangeEnd = getIcalUTC(rangeEnd);
|
||||
this.log( "getFreeBusyTimes():\n\trangeStart=" + zRangeStart +
|
||||
",\n\trangeEnd=" + zRangeEnd );
|
||||
this.log( "\n\trangeStart=" + zRangeStart +
|
||||
",\n\trangeEnd=" + zRangeEnd,
|
||||
"getFreeBusyTimes()" );
|
||||
|
||||
this.assureLoggedIn();
|
||||
var url = this.getCommandUrl( "get_freebusy" );
|
||||
url += ("&calid=" + encodeURIComponent(calId));
|
||||
url += ("&busyonly=" + (bBusyOnly ? "1" : "0"));
|
||||
@ -979,18 +1014,14 @@ calWcapSession.prototype = {
|
||||
this_.getFreeBusyTimes_resp(
|
||||
wcapResponse, calId, listener, requestId );
|
||||
}
|
||||
if (bAsync)
|
||||
this.issueAsyncRequest( url, stringToXml, resp );
|
||||
else
|
||||
this.issueSyncRequest( url, stringToXml, resp );
|
||||
this.issueAsyncRequest( url, stringToXml, resp );
|
||||
}
|
||||
catch (exc) {
|
||||
this.notifyError( exc );
|
||||
if (listener != null)
|
||||
listener.onGetFreeBusyTimes( exc, requestId, calId, 0, [] );
|
||||
throw exc;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
var g_confirmedHttpLogins = null;
|
||||
|
||||
@ -121,54 +121,6 @@ function getCalendarManager()
|
||||
return g_calendarManager;
|
||||
};
|
||||
|
||||
var g_bInitedLockedExec = false;
|
||||
var g_eventQueueService = null;
|
||||
var g_threadManager = null;
|
||||
|
||||
/** Locks event dispatching for the current event queue while the passed
|
||||
function is executed.
|
||||
|
||||
xxx todo: this hinders timeeout events for sync requests
|
||||
to be dispatched!
|
||||
*/
|
||||
function lockedExec( func )
|
||||
{
|
||||
if (!g_bInitedLockedExec) {
|
||||
try {
|
||||
var cl = Components.classes["@mozilla.org/event-queue-service;1"];
|
||||
if (cl) {
|
||||
g_eventQueueService =
|
||||
cl.getService(Components.interfaces.nsIEventQueueService);
|
||||
}
|
||||
}
|
||||
catch (exc) { // eventQueue has vanished on trunk
|
||||
}
|
||||
if (!g_eventQueueService) {
|
||||
g_threadManager =
|
||||
Components.classes["@mozilla.org/thread-manager;1"]
|
||||
.getService(Components.interfaces.nsIThreadManager);
|
||||
}
|
||||
g_bInitedLockedExec = true;
|
||||
}
|
||||
|
||||
var queue;
|
||||
var ret;
|
||||
if (g_eventQueueService)
|
||||
queue = g_eventQueueService.pushThreadEventQueue();
|
||||
else // we are on trunk using nsIThreadInternal
|
||||
g_threadManager.currentThread.pushEventQueue(null);
|
||||
try {
|
||||
ret = func();
|
||||
}
|
||||
finally {
|
||||
if (g_eventQueueService)
|
||||
g_eventQueueService.popThreadEventQueue(queue);
|
||||
else // we are on trunk using nsIThreadInternal
|
||||
g_threadManager.currentThread.popEventQueue();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
var g_wcapBundle = null;
|
||||
function getWcapBundle()
|
||||
{
|
||||
@ -204,10 +156,6 @@ function isParent( item )
|
||||
throw new Components.Exception(
|
||||
"proxy has different id than its parent!");
|
||||
}
|
||||
if (item.parentItem.recurrenceId) {
|
||||
throw new Components.Exception("parent has recurrenceId: " +
|
||||
item.parentItem.recurrenceId);
|
||||
}
|
||||
return (!item.recurrenceId);
|
||||
}
|
||||
|
||||
@ -259,20 +207,25 @@ function getIcalUTC( dt )
|
||||
}
|
||||
}
|
||||
|
||||
function getDatetimeFromIcalProp( prop )
|
||||
function getDatetimeFromIcalString( val )
|
||||
{
|
||||
if (!prop)
|
||||
return null;
|
||||
var val = prop.valueAsIcalString;
|
||||
if (val.length == 0 || val == "0")
|
||||
if (!val || val.length == 0 || val == "0")
|
||||
return null;
|
||||
// assuming timezone is known:
|
||||
var dt = new CalDateTime();
|
||||
dt.icalString = val;
|
||||
// dt.makeImmutable();
|
||||
// if (dt.icalString != val)
|
||||
// logMessage("date-time error", dt.icalString + " vs. " + val);
|
||||
return dt;
|
||||
}
|
||||
|
||||
function getDatetimeFromIcalProp( prop )
|
||||
{
|
||||
if (!prop)
|
||||
return null;
|
||||
return getDatetimeFromIcalString(prop.valueAsIcalString);
|
||||
}
|
||||
|
||||
function getPref(prefName, defaultValue)
|
||||
{
|
||||
const nsIPrefBranch = Components.interfaces.nsIPrefBranch;
|
||||
@ -316,3 +269,124 @@ function setPref(prefName, value)
|
||||
}
|
||||
}
|
||||
|
||||
function AsyncQueue()
|
||||
{
|
||||
this.wrappedJSObject = this;
|
||||
this.m_queue = [];
|
||||
}
|
||||
AsyncQueue.prototype = {
|
||||
m_queue: null,
|
||||
|
||||
m_proxy: null,
|
||||
get proxy() {
|
||||
if (!this.m_proxy) {
|
||||
var eventTarget = null;
|
||||
try {
|
||||
var eventQueueService =
|
||||
Components.classes["@mozilla.org/event-queue-service;1"]
|
||||
.getService(Components.interfaces.nsIEventQueueService);
|
||||
eventTarget = eventQueueService.createThreadEventQueue(
|
||||
Components.classes["@mozilla.org/thread;1"]
|
||||
.createInstance(Components.interfaces.nsIThread), true);
|
||||
}
|
||||
catch (exc) { // eventQueue has vanished on trunk:
|
||||
var threadManager =
|
||||
Components.classes["@mozilla.org/thread-manager;1"]
|
||||
.getService(Components.interfaces.nsIThreadManager);
|
||||
eventTarget = threadManager.newThread(0);
|
||||
}
|
||||
var proxyMgr = Components.classes["@mozilla.org/xpcomproxy;1"]
|
||||
.getService(Components.interfaces.nsIProxyObjectManager);
|
||||
this.m_proxy = proxyMgr.getProxyForObject(
|
||||
eventTarget, Components.interfaces.nsIRunnable, this,
|
||||
Components.interfaces.nsIProxyObjectManager.INVOKE_ASYNC );
|
||||
}
|
||||
return this.m_proxy;
|
||||
},
|
||||
|
||||
queuedExec:
|
||||
function(func)
|
||||
{
|
||||
this.m_queue.push(func);
|
||||
if (LOG_LEVEL > 1)
|
||||
logMessage("enqueued: q=" + this.m_queue.length);
|
||||
if (this.m_queue.length == 1) {
|
||||
this.proxy.run(); // empty queue
|
||||
}
|
||||
},
|
||||
|
||||
m_ifaces: [ Components.interfaces.nsIRunnable,
|
||||
Components.interfaces.nsISecurityCheckedComponent,
|
||||
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 "Async Queue";
|
||||
},
|
||||
get contractID() {
|
||||
return "@mozilla.org/calendar/calendar/wcap/async-queue;1";
|
||||
},
|
||||
get classID() {
|
||||
return Components.ID("{C50F7442-C43E-43f6-AA3F-1ADB87E7A962}");
|
||||
},
|
||||
getHelperForLanguage: function( language ) { return null; },
|
||||
implementationLanguage:
|
||||
Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
|
||||
flags: 0,
|
||||
|
||||
// nsISecurityCheckedComponent;
|
||||
canCreateWrapper: function(iid) { return "AllAccess"; },
|
||||
canCallMethod: function(iid, methodName) { return "AllAccess"; },
|
||||
canGetProperty: function(iid, propertyName) { return "AllAccess"; },
|
||||
canSetProperty: function(iid, propertyName) { return "AllAccess"; },
|
||||
|
||||
// nsIRunnable:
|
||||
run:
|
||||
function() {
|
||||
while (this.m_queue.length > 0) {
|
||||
if (LOG_LEVEL > 1)
|
||||
logMessage("queue exec: " + this.m_queue.length);
|
||||
try {
|
||||
this.m_queue[0]();
|
||||
}
|
||||
catch (exc) { // swallow all exceptions,
|
||||
// they does not belong to this call
|
||||
debugger;
|
||||
var msg = errorToString(exc);
|
||||
Components.utils.reportError(
|
||||
logMessage("error: " + msg, "swallowed exception") );
|
||||
}
|
||||
// don't remove element unless func has been executed:
|
||||
this.m_queue.shift();
|
||||
if (LOG_LEVEL > 1)
|
||||
logMessage("dequeued: " + this.m_queue.length);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function makeQueuedCall(asyncQueue, obj, func)
|
||||
{
|
||||
return function() {
|
||||
var args = [];
|
||||
for ( var i = 0; i < arguments.length; ++i )
|
||||
args.push(arguments[i]);
|
||||
asyncQueue.queuedExec( function() { func.apply(obj, args); } );
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,6 +53,7 @@ interface calIWcapCalendar : calICalendar
|
||||
|
||||
/**
|
||||
* Current calId the calendar instance acts on; defaults to userId.
|
||||
* @exception may throw an NS_ERROR_NOT_AVAILABLE of not logged in
|
||||
*/
|
||||
readonly attribute string calId;
|
||||
|
||||
|
||||
@ -196,18 +196,15 @@ interface calIWcapSession : nsISupports
|
||||
/* xxx todo freebusy: separate into own interface? */
|
||||
/**
|
||||
* Gets free-busy entries for calid.
|
||||
* Results are notifies to passed listener instance.
|
||||
* Results are notified to passed listener instance.
|
||||
* An error is notified to all registered calIObservers and
|
||||
* to calIWcapFreeBusyListener::onGetFreeBusyTimes with rc != NS_OK.
|
||||
* Additionally, when an error occurs within getFreeBusyTimes,
|
||||
* the error is also thrown.
|
||||
*
|
||||
* @param calId a calid or "mailto:rfc822addr"
|
||||
* @param dtRangeStart start time of free-busy search
|
||||
* @param dtRangeEnd end time of free-busy search
|
||||
* @param bBusyOnly whether to return busy entries only
|
||||
* @param listener listener receiving results
|
||||
* @param bAsync whether the listener receives results asynchronously
|
||||
* @param requestId request id to distinguish asynchronous requests
|
||||
*/
|
||||
void getFreeBusyTimes(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user