From ad2bdcb6c18f1e829aca9451bce108e41efa3cb5 Mon Sep 17 00:00:00 2001 From: "daniel.boelzle%sun.com" Date: Sun, 6 Aug 2006 14:14:25 +0000 Subject: [PATCH] Bug 340949: fixing attendee partstat UPDATE, empty VCALENDAR problem, orgUID, minor bugs, changing resource ids --- .../en-US/chrome/calendar/wcap.properties | 10 +- calendar/providers/wcap/calWcapCalendar.js | 40 +++--- .../providers/wcap/calWcapCalendarItems.js | 131 +++++++++--------- calendar/providers/wcap/calWcapErrors.js | 2 +- calendar/providers/wcap/calWcapSession.js | 14 +- calendar/providers/wcap/calWcapUtils.js | 8 +- .../wcap/public/calIWcapCalendar.idl | 5 + 7 files changed, 113 insertions(+), 97 deletions(-) diff --git a/calendar/locales/en-US/chrome/calendar/wcap.properties b/calendar/locales/en-US/chrome/calendar/wcap.properties index 4feb99df7c9..d6aa1ba5d9c 100644 --- a/calendar/locales/en-US/chrome/calendar/wcap.properties +++ b/calendar/locales/en-US/chrome/calendar/wcap.properties @@ -45,7 +45,7 @@ mandatoryHttpsError.text=Server %1$S needs to support HTTPS! # args: host noHttpsConfirmation.text=Insecure login on %1$S! Server does not support HTTPS. Continue? -noHttpsConfirmation.check=Don't ask again. +noHttpsConfirmation.check.text=Don't ask again. noHttpsConfirmation.label=Warning! # args: host @@ -57,9 +57,9 @@ insufficientWcapVersionError.text=Server %1$S (%2$S, v%3$S) has insufficient WCA # args: host, prodId, serverVersion, wcapVersion loginDialog.text=Server: %1$S (%2$S, v%3$S, WCAP v%4$S) -loginDialog.savePW.label=Save Password +loginDialog.check.text=Save Password loginDialog.label=Sun Java System Calendar Server WCAP login -privateItem.title=Private -confidentialItem.title=Confidential -busyItem.title=Busy +privateItem.title.text=Private +confidentialItem.title.text=Confidential +busyItem.title.text=Busy diff --git a/calendar/providers/wcap/calWcapCalendar.js b/calendar/providers/wcap/calWcapCalendar.js index 0a2fab2fce9..e27da319deb 100644 --- a/calendar/providers/wcap/calWcapCalendar.js +++ b/calendar/providers/wcap/calWcapCalendar.js @@ -116,8 +116,7 @@ calWcapCalendar.prototype = { function() { var str = this.session.toString(); - if (this.calId != this.session.userId) - str += (", calId=" + this.calId); + str += (", calId=" + this.calId); return str; }, log: @@ -184,8 +183,7 @@ calWcapCalendar.prototype = { // xxx todo: rework like in // https://bugzilla.mozilla.org/show_bug.cgi?id=257428 - m_bSuppressAlarms: true /* xxx todo: - off for now until all problems are solved */, + m_bSuppressAlarms: false, get suppressAlarms() { return (this.m_bSuppressAlarms || this.readOnly); }, @@ -209,18 +207,28 @@ calWcapCalendar.prototype = { // calendar has its own calICalendar object... // poking calId, so default calendar will then behave // like a subscribed one... - m_overriddencalId: null, m_calId: null, get calId() { - return this.m_overriddencalId || this.calId_; - }, - get calId_() { // the original (static) calId of this calendar var userId = this.session.userId; // assure being logged in return this.m_calId || userId; }, set calId( id ) { - this.log( "overriding calId to " + id ); - this.m_overriddencalId = id; + this.log( "setting calId to " + id ); + this.m_calId = id; + // refresh calprops: + this.m_calProps = null; + this.getCalProps_( true /* async */ ); + }, + + get ownerId() { + var ar = this.getCalendarProperties("X-NSCP-CALPROPS-PRIMARY-OWNER",{}); + if (ar.length < 1) { + this.notifyError( + "cannot determine primary owner of calendar " + this.calId ); + // fallback to userId: + return this.session.userId; + } + return ar[0]; }, get description() { @@ -239,16 +247,16 @@ calWcapCalendar.prototype = { ar = this.getCalendarProperties( "X-S1CS-CALPROPS-COMMON-NAME", {}); if (ar.length < 1) { - return this.calId_; // fallback, xxx todo calId_ + return this.calId; } } return ar[0]; }, get isOwnedCalendar() { - var userId = this.session.userId; - return (this.calId == userId || - this.calId.indexOf(userId + ":") == 0); + var ownerId = this.ownerId; + return (this.calId == ownerId || + this.calId.indexOf(ownerId + ":") == 0); }, getCalendarProperties: @@ -272,9 +280,7 @@ calWcapCalendar.prototype = { try { if (this.m_calProps == null) { var url = this.session.getCommandUrl( "get_calprops" ); - // xxx todo: for now this alwas gets the description of - // the original calId_ - url += ("&calid=" + encodeURIComponent(this.calId_)); + url += ("&calid=" + encodeURIComponent(this.calId)); url += "&fmt-out=text%2Fxml"; var this_ = this; function resp( wcapResponse ) { diff --git a/calendar/providers/wcap/calWcapCalendarItems.js b/calendar/providers/wcap/calWcapCalendarItems.js index 6049767949a..a2ac9145f4f 100644 --- a/calendar/providers/wcap/calWcapCalendarItems.js +++ b/calendar/providers/wcap/calWcapCalendarItems.js @@ -191,7 +191,7 @@ calWcapCalendar.prototype.getRecurrenceParams = function( } }; -calWcapCalendar.prototype.getStoreUrl = function( item ) +calWcapCalendar.prototype.getStoreUrl = function( item, oldItem ) { var bIsEvent = isEvent(item); var url = this.session.getCommandUrl( bIsEvent ? "storeevents" @@ -199,12 +199,10 @@ calWcapCalendar.prototype.getStoreUrl = function( item ) url += "&fetch=1&compressed=1&recurring=1"; url += ("&calid=" + encodeURIComponent(this.calId)); - // it is always safe to use orgCalId, - // because every user has a calId == userId - var orgCalid = ((item.organizer == null || item.organizer.id == null) - ? this.calId // sensible default - : item.organizer.id); - url += ("&orgCalid=" + encodeURIComponent(orgCalid)); + var ownerId = this.ownerId; + var orgUID = ((item.organizer == null || item.organizer.id == null) + ? ownerId : item.organizer.id); + url += ("&orgUID=" + encodeURIComponent(orgUID)); // xxx todo: default prio is 0 (5 in sjs cs) url += ("&priority=" + item.priority); @@ -277,40 +275,10 @@ calWcapCalendar.prototype.getStoreUrl = function( item ) url += encodeURIComponent( item.getProperty( "URL" ) ); } - // attendees: - var attendees = item.getAttendees({}); - var forceRSVP = false; - var dtstart = null; var dtend = null; // for alarmRelated if (bIsEvent) { - if (attendees != null && attendees.length > 0) { - // ORGANIZER is this cal? - if (orgCalid == this.calId) { - url += "&method=2"; // REQUEST - forceRSVP = true; - } - else { - var userId = this.session.userId; - if (userId == null) - userId = this.calId; // fallback - var i = 0; - for ( ; i < attendees.length; ++i ) { - if (attendees[i].id == userId) { - // REPLY for just this user: - url += "&method=4"; - attendees = [ attendees[i] ]; - break; - } - } - if (i >= attendees.length) { - // user not in list, don't write attendee list: - attendees = null; - } - } - } // else just PUBLISH (default) - dtstart = item.startDate; var dtend = item.endDate; url += ("&dtend=" + getIcalUTC(dtend)); @@ -407,14 +375,53 @@ calWcapCalendar.prototype.getStoreUrl = function( item ) } // attendees: - url += "&attendees="; - if (attendees != null) { - for ( var i = 0; i < attendees.length; ++i ) { - if (i > 0) - url += ";"; - url += this.encodeAttendee( attendees[i], forceRSVP ); + var attendees = item.getAttendees({}); + if (attendees.length > 0) { + // ORGANIZER is owner fo this cal? + if (!oldItem || orgUID == ownerId) { + url += "&method=2"; // REQUEST + url += "&attendees="; + for ( var i = 0; i < attendees.length; ++i ) { + if (i > 0) + url += ";"; + url += this.encodeAttendee( attendees[i], true /*forceRSVP*/ ); + } } - } + else { // attendee's calendar: + var attendee = item.getAttendeeById(ownerId); + if (attendee == null) { + this.logError( "not in attendee list, but in my cal?" ); + } + else { + this.log( "attendee: " + attendee.icalProperty.icalString ); + var oldAttendee = oldItem.getAttendeeById(ownerId); + if (!oldAttendee || + attendee.participationStatus != + oldAttendee.participationStatus) { + // REPLY for just this calendar owner: + url += "&method=4"; + url += ("&attendees=PARTSTAT=" + + attendee.participationStatus); + url += ("^" + ownerId); + } + else { + // UPDATE attendee's copy of item: + url += "&method=256"; + } + } + } + } // else use just PUBLISH (method=1) + + // xxx todo: however, sometimes socs just returns an empty calendar when + // nothing or only optional props like attendee ROLE has changed, + // although fetch=1. + // This also occurs when the event organizer is in the attendees + // list and switches its PARTSTAT too often... + // hack: ever changing dummy prop, then the cs engine seems to write + // every time. WTF. + url += ("&X-MOZ-WCAP-DUMMY=" + + "X-NSCP-ORIGINAL-OPERATION=X-NSCP-WCAP-PROPERTY-REPLACE^" + + getIcalUTC(getTime())); return url; }; @@ -473,7 +480,7 @@ calWcapCalendar.prototype.adoptItem = function( item, iListener ) // will most probably lead to error => existing parent } - var url = this.getStoreUrl( item ); + var url = this.getStoreUrl( item, null ); url += this.encodeRecurrenceParams( item ); // (WCAP_STORE_TYPE_CREATE) error if existing item: url += "&storetype=1"; @@ -503,9 +510,9 @@ calWcapCalendar.prototype.addItem = function( item, iListener ) }; calWcapCalendar.prototype.modifyItem_resp = function( - wcapResponse, newItem_, oldItem, iListener ) + wcapResponse, oldItem, iListener ) { - var newItem = null; + var item = null; try { var icalRootComp = wcapResponse.data; // first statement, may throw @@ -513,26 +520,19 @@ calWcapCalendar.prototype.modifyItem_resp = function( icalRootComp, Components.interfaces.calICalendar.ITEM_FILTER_ALL_ITEMS, 0, null, null ); + if (items.length < 1) + throw new Error("empty VCALENDAR returned!"); if (items.length > 1) this.notifyError( "unexpected number of items: " + items.length ); - if (items.length < 1) { - // however, sometimes socs just returns an empty calendar when - // nothing has changed, although fetch=1. - // This also occurs when the event organizer is in the attendees - // list and switches its PARTSTAT too often... WTF. - this.log( "empty VCALENDAR returned!" ); - newItem = newItem_; // fallback, assuming item has been written - } - else - newItem = items[0]; + item = items[0]; if (iListener != null) { iListener.onOperationComplete( this.superCalendar, Components.results.NS_OK, Components.interfaces.calIOperationListener.MODIFY, - newItem.id, newItem ); + item.id, item ); } - this.notifyObservers( "onModifyItem", [newItem, oldItem] ); + this.notifyObservers( "onModifyItem", [item, oldItem] ); // xxx todo: maybe log request status } catch (exc) { @@ -540,7 +540,7 @@ calWcapCalendar.prototype.modifyItem_resp = function( iListener.onOperationComplete( this.superCalendar, Components.results.NS_ERROR_FAILURE, Components.interfaces.calIOperationListener.MODIFY, - newItem == null ? null : newItem.id, exc ); + item == null ? null : item.id, exc ); } this.notifyError( exc ); } @@ -557,7 +557,7 @@ calWcapCalendar.prototype.modifyItem = function( if (!newItem.id) throw new Error("new item has no id!"); - var url = this.getStoreUrl( newItem ); + var url = this.getStoreUrl( newItem, oldItem ); url += ("&uid=" + newItem.id); if (newItem.parentItem == newItem) { // is master // (WCAP_STORE_TYPE_MODIFY) error if not existing: @@ -577,8 +577,7 @@ calWcapCalendar.prototype.modifyItem = function( this.session.issueAsyncRequest( url + "&fmt-out=text%2Fcalendar", stringToIcal, function( wcapResponse ) { - this_.modifyItem_resp( wcapResponse, - newItem, oldItem, iListener ); + this_.modifyItem_resp( wcapResponse, oldItem, iListener ); } ); } catch (exc) { @@ -1239,8 +1238,8 @@ calWcapCalendar.prototype.syncChangesTo = function( function( item ) { syncState.acquire(); this_.log( "adding " + item.id ); - // xxx todo: verify whether exceptions - // are written: + // xxx todo: verify whether exceptions have been + // written destCal.addItem( item, addItemListener ); } ); } ); @@ -1268,7 +1267,7 @@ calWcapCalendar.prototype.syncChangesTo = function( modifiedItems.push( item.id ); if (bAdd) { // xxx todo: verify whether exceptions - // are written: + // have been written this_.log( "adding " + item.id ); destCal.addItem( item, addItemListener ); } diff --git a/calendar/providers/wcap/calWcapErrors.js b/calendar/providers/wcap/calWcapErrors.js index 9be4ede69e8..4b42aac8370 100644 --- a/calendar/providers/wcap/calWcapErrors.js +++ b/calendar/providers/wcap/calWcapErrors.js @@ -183,7 +183,7 @@ function wcapErrorToString( rc ) function errorToString( err ) { - if (err instanceof String) + if (typeof(err) == "string") return err; if (err instanceof Error) return err.message; diff --git a/calendar/providers/wcap/calWcapSession.js b/calendar/providers/wcap/calWcapSession.js index 472331c5425..425030db5e9 100644 --- a/calendar/providers/wcap/calWcapSession.js +++ b/calendar/providers/wcap/calWcapSession.js @@ -518,7 +518,7 @@ calWcapSession.prototype = { "loginDialog.label"), loginText, outUser, outPW, getWcapBundle().GetStringFromName( - "loginDialog.savePW.label" ), + "loginDialog.check.text"), savePW )) { try { @@ -784,9 +784,13 @@ calWcapSession.prototype = { function( calId ) { var ret; - if (calId == null || this.userId == calId) { - if (this.m_defaultCalendar == null) - this.m_defaultCalendar = createWcapCalendar(this.userId, this); + // xxx todo: for now the default calendar (calId=null) + // is separated (own instance) from subscribed calendars + if (calId == null /*|| this.userId == calId*/) { + if (this.m_defaultCalendar == null) { + this.m_defaultCalendar = createWcapCalendar( + null/*this.userId*/, this); + } ret = this.m_defaultCalendar; } else { @@ -1053,7 +1057,7 @@ function confirmInsecureLogin( uri ) var bConfirmed = prompt.confirmCheck( bundle.GetStringFromName("noHttpsConfirmation.label"), bundle.formatStringFromName("noHttpsConfirmation.text", [host], 1), - bundle.GetStringFromName("noHttpsConfirmation.check"), + bundle.GetStringFromName("noHttpsConfirmation.check.text"), dontAskAgain ); if (dontAskAgain.value) { diff --git a/calendar/providers/wcap/calWcapUtils.js b/calendar/providers/wcap/calWcapUtils.js index 613573a5f96..908750bea06 100644 --- a/calendar/providers/wcap/calWcapUtils.js +++ b/calendar/providers/wcap/calWcapUtils.js @@ -347,9 +347,11 @@ catch (exc) { } // some string resources: -var g_privateItemTitle = getWcapBundle().GetStringFromName("privateItem.title"); +var g_privateItemTitle = getWcapBundle().GetStringFromName( + "privateItem.title.text"); var g_confidentialItemTitle = getWcapBundle().GetStringFromName( - "confidentialItem.title"); -var g_busyItemTitle = getWcapBundle().GetStringFromName("busyItem.title"); + "confidentialItem.title.text"); +var g_busyItemTitle = getWcapBundle().GetStringFromName( + "busyItem.title.text"); var g_busyPhantomItemUuidPrefix = ("PHANTOM_uuid" + getTime().icalString); diff --git a/calendar/providers/wcap/public/calIWcapCalendar.idl b/calendar/providers/wcap/public/calIWcapCalendar.idl index 8cc4fc36043..5cace7f7e10 100644 --- a/calendar/providers/wcap/public/calIWcapCalendar.idl +++ b/calendar/providers/wcap/public/calIWcapCalendar.idl @@ -56,6 +56,11 @@ interface calIWcapCalendar : calICalendar */ readonly attribute string calId; + /** + * UserId of primary owner of this calendar instance. + */ + readonly attribute string ownerId; + /** * Whether the currently selected calendar belongs to user. */