Fix bug 428392 - Accepting Events not adding event to calender - falsely reporting "not an attendee". r=ctalbert

This commit is contained in:
mozilla%kewis.ch 2008-04-28 11:18:27 +00:00
Родитель f77453869b
Коммит 79f422b4c1
9 изменённых файлов: 113 добавлений и 81 удалений

Просмотреть файл

@ -128,6 +128,8 @@ interface calICalendar : nsISupports
* e.g. this generally applies to network calendars; * e.g. this generally applies to network calendars;
* default is true (if not present). * default is true (if not present).
* [boolean] cache.enabled If true, the calendar is cached; default is false. * [boolean] cache.enabled If true, the calendar is cached; default is false.
* [string] itip.transportType If the provider implements a custom calIItipTransport
* this is the "type" used in the contract id.
* *
* The following calendar capabilities can be used to inform the UI or backend * The following calendar capabilities can be used to inform the UI or backend
* that certain features are not supported. If not otherwise mentioned, not * that certain features are not supported. If not otherwise mentioned, not

Просмотреть файл

@ -21,6 +21,7 @@
* Contributor(s): * Contributor(s):
* Clint Talbert <ctalbert.moz@gmail.com> * Clint Talbert <ctalbert.moz@gmail.com>
* Matthew Willis <lilmatt@mozilla.com> * Matthew Willis <lilmatt@mozilla.com>
* Philipp Kewisch <mozilla@kewis.ch>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -111,6 +112,13 @@ interface calIItipItem : nsISupports
*/ */
attribute calICalendar targetCalendar; attribute calICalendar targetCalendar;
/**
* The identity this item was received on. Helps to determine which
* attendee to manipulate. This should be the full email address of the
* attendee that is considered to be the local user.
*/
attribute AUTF8String identity;
/** /**
* localStatus: The response that the user has made to the invitation in * localStatus: The response that the user has made to the invitation in
* this ItipItem. * this ItipItem.

Просмотреть файл

@ -20,6 +20,7 @@
* *
* Contributor(s): * Contributor(s):
* Clint Talbert <ctalbert.moz@gmail.com> * Clint Talbert <ctalbert.moz@gmail.com>
* Philipp Kewisch <mozilla@kewis.ch>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -51,9 +52,19 @@ interface calIItipTransport : nsISupports
/** /**
* Default identity for me within this transport. For example, this is * Default identity for me within this transport. For example, this is
* your default email address in Thunderbird. * your default email address in Thunderbird.
*
* XXX This should probably go away, using the default identity is far
* from practical. Only user right now is calUtils's sendItipInvitation.
* See bug 431126.
*/ */
readonly attribute AUTF8String defaultIdentity; readonly attribute AUTF8String defaultIdentity;
/**
* Scheme to be used to prefix attendees. For example, the Email transport
* should reuturn "mailto".
*/
readonly attribute AUTF8String scheme;
/** /**
* Sending identity. This can be set to change the "sender" identity from * Sending identity. This can be set to change the "sender" identity from
* defaultIdentity above. * defaultIdentity above.

Просмотреть файл

@ -21,6 +21,7 @@
* Contributor(s): * Contributor(s):
* Clint Talbert <ctalbert.moz@gmail.com> * Clint Talbert <ctalbert.moz@gmail.com>
* Matthew Willis <lilmatt@mozilla.com> * Matthew Willis <lilmatt@mozilla.com>
* Philipp Kewisch <mozilla@kewis.ch>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -146,6 +147,14 @@ calItipItem.prototype = {
return (this.mTargetCalendar = aValue); return (this.mTargetCalendar = aValue);
}, },
mIdentity: null,
get identity() {
return this.mIdentity;
},
set identity(aValue) {
return (this.mIdentity = aValue);
},
mLocalStatus: null, mLocalStatus: null,
get localStatus() { get localStatus() {
return this.mLocalStatus; return this.mLocalStatus;

Просмотреть файл

@ -22,6 +22,7 @@
* Clint Talbert <ctalbert.moz@gmail.com> * Clint Talbert <ctalbert.moz@gmail.com>
* Eva Or <evaor1012@yahoo.ca> * Eva Or <evaor1012@yahoo.ca>
* Matthew Willis <lilmatt@mozilla.com> * Matthew Willis <lilmatt@mozilla.com>
* Philipp Kewisch <mozilla@kewis.ch>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -139,32 +140,29 @@ calItipProcessor.prototype = {
// Check to see if we have an existing item or not, then continue // Check to see if we have an existing item or not, then continue
// processing appropriately // processing appropriately
var i =0; for (var i = 0; i < itemList.length; i++) {
while (calItem) { this._isExistingItem(itemList[i], aItipItem, recvMethod, respMethod,
this._isExistingItem(calItem, recvMethod, respMethod, targetCalendar, targetCalendar, aListener);
aListener);
++i;
calItem = itemList[i];
} }
// Send the appropriate response // Send the appropriate response
// figure out a good way to determine when a response is needed! // figure out a good way to determine when a response is needed!
if (recvMethod != respMethod) { if (recvMethod != respMethod) {
this._getTransport().simpleSendResponse(respItipItem); this._getTransport(targetCalendar).simpleSendResponse(respItipItem);
} }
}, },
/* Continue processing the iTip Item now that we have determined whether /* Continue processing the iTip Item now that we have determined whether
* there is an existing item or not. * there is an existing item or not.
*/ */
_continueProcessingItem: function cipCPI(newItem, existingItem, recvMethod, respMethod, _continueProcessingItem: function cipCPI(newItem, existingItem, aItipItem,
calAction, targetCalendar, aListener) { recvMethod, respMethod, calAction,
var transport = this._getTransport(); targetCalendar, aListener) {
switch (recvMethod) { switch (recvMethod) {
case "REQUEST": case "REQUEST":
// Only add to calendar if we accepted invite // Only add to calendar if we accepted invite
var replyStat = this._getReplyStatus(newItem, var replyStat = this._getReplyStatus(newItem,
transport.defaultIdentity); aItipItem.identity);
if (replyStat == "DECLINED") { if (replyStat == "DECLINED") {
break; break;
} }
@ -194,6 +192,7 @@ calItipProcessor.prototype = {
recvMethod); recvMethod);
} }
// TODO bug 431127: This is email specific -> Move to transport
// When replying, the reply must only contain the ORGANIZER and the // When replying, the reply must only contain the ORGANIZER and the
// status of the ATTENDEE that represents ourselves. Therefore we must // status of the ATTENDEE that represents ourselves. Therefore we must
// remove all other ATTENDEEs from the itipItem we send back. // remove all other ATTENDEEs from the itipItem we send back.
@ -201,22 +200,15 @@ calItipProcessor.prototype = {
// Get the id that represents me. // Get the id that represents me.
// XXX Note that this doesn't take into consideration invitations // XXX Note that this doesn't take into consideration invitations
// sent to email aliases. (ex: lilmatt vs mwillis) // sent to email aliases. (ex: lilmatt vs mwillis)
var me;
var idPrefix;
if (transport.type == "email") {
me = transport.defaultIdentity;
idPrefix = "mailto:";
} else {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
}
var attendees = newItem.getAttendees({}); var attendees = newItem.getAttendees({});
var transport = this._getTransport(newItem.calendar);
for each (var attendee in attendees) { for each (var attendee in attendees) {
// Leave the ORGANIZER alone. // Leave the ORGANIZER alone.
if (!attendee.isOrganizer) { if (!attendee.isOrganizer) {
// example: mailto:joe@domain.com // example: mailto:joe@domain.com
var meString = idPrefix + me; var meString = transport.scheme + ":" + aItipItem.identity
if (attendee.id.toLowerCase() != meString.toLowerCase()) { if (attendee.id.toLowerCase() != meString.toLowerCase()) {
newItem.removeAttendee(attendee); newItem.removeAttendee(attendee);
} }
@ -363,7 +355,7 @@ calItipProcessor.prototype = {
if (!aExistingItem) if (!aExistingItem)
throw new Error("_processCalendarAction: Item to update not found"); throw new Error("_processCalendarAction: Item to update not found");
// TODO: Handle generation properly - Bug 418345 // TODO: Handle generation properly - Bug 418345
aCalItem.generation = aExistingItem.generation; aCalItem.generation = aExistingItem.generation;
// We also have to ensure that the calendar is set properly on // We also have to ensure that the calendar is set properly on
// the new item, or items with alarms will throw during the // the new item, or items with alarms will throw during the
@ -389,20 +381,10 @@ calItipProcessor.prototype = {
* item for the specified attendee * item for the specified attendee
*/ */
_getReplyStatus: function cipGRS(aCalItem, aAttendeeId) { _getReplyStatus: function cipGRS(aCalItem, aAttendeeId) {
var idPrefix = "mailto:"; var idString = this._getTransport(aCalItem.calendar).scheme +
":" + aAttendeeId;
// example: mailto:joe@domain.com
var idString = idPrefix + aAttendeeId;
var attendee = aCalItem.getAttendeeById(idString); var attendee = aCalItem.getAttendeeById(idString);
if (!attendee) { return attendee && attendee.participationStatus;
// Bug 420516 -- we don't support delegation yet TODO: Localize this?
throw new Error("_getReplyStatus: " +
"You are not on the list of invited attendees, delegation " +
"is not supported yet. See bug 420516 for details.");
}
return attendee.participationStatus;
}, },
// A placeholder to make sure we don't try to add multiple items from the // A placeholder to make sure we don't try to add multiple items from the
@ -414,9 +396,8 @@ calItipProcessor.prototype = {
* or not. It then calls _continueProcessingItem setting calAction and * or not. It then calls _continueProcessingItem setting calAction and
* existingItem appropirately * existingItem appropirately
*/ */
_isExistingItem: function cipIEI(aCalItem, aRecvMethod, aRespMethod, _isExistingItem: function cipIEI(aCalItem, aItipItem, aRecvMethod, aRespMethod,
aTargetCal, aListener) { aTargetCal, aListener) {
var foundItemListener = { var foundItemListener = {
itipProcessor: this, itipProcessor: this,
onOperationComplete: onOperationComplete:
@ -428,6 +409,7 @@ calItipProcessor.prototype = {
this.itipProcessor._handledID = aCalItem.id; this.itipProcessor._handledID = aCalItem.id;
this.itipProcessor._continueProcessingItem(aCalItem, this.itipProcessor._continueProcessingItem(aCalItem,
null, null,
aItipItem,
aRecvMethod, aRecvMethod,
aRespMethod, aRespMethod,
CAL_ITIP_PROC_ADD_OP, CAL_ITIP_PROC_ADD_OP,
@ -441,6 +423,7 @@ calItipProcessor.prototype = {
if (aCount && aItems[0]) { if (aCount && aItems[0]) {
this.itipProcessor._continueProcessingItem(aCalItem, this.itipProcessor._continueProcessingItem(aCalItem,
aItems[0], aItems[0],
aItipItem,
aRecvMethod, aRecvMethod,
aRespMethod, aRespMethod,
CAL_ITIP_PROC_UPDATE_OP, CAL_ITIP_PROC_UPDATE_OP,
@ -455,23 +438,24 @@ calItipProcessor.prototype = {
// Then we do not have a target calendar to search, // Then we do not have a target calendar to search,
// this is probably a DECLINE reply or some other such response, // this is probably a DECLINE reply or some other such response,
// allow it to pass through // allow it to pass through
this._continueProcessingItem(aCalItem, null, aRecvMethod, aRespMethod, this._continueProcessingItem(aCalItem, null, aItipItem, aRecvMethod,
null, aTargetCal, aListener); aRespMethod, null, aTargetCal, aListener);
} }
}, },
/** /**
* Centralized location for obtaining the proper transport. This way it * Centralized location for obtaining the proper transport. If a calendar is
* will be easy to support multiple transports in the future * specified, the transport type is taken from the provider. If the provider
* without changing the existing code too much. * does not specify a transport, or no calendar is specified, the default
* email transport is returned.
*/ */
_getTransport: function cipGT() { _getTransport: function cipGT(aCalendar) {
// XXX Support for transports other than email go here. var transportType = (aCalendar && aCalendar.getProperty("itip.transportType")) || "email";
// For now we just assume it's email.
var transport = Components.classes["@mozilla.org/calendar/itip-transport;1?type=email"]. var transport = Components.classes["@mozilla.org/calendar/itip-transport;1?type=" + transportType]
createInstance(Components.interfaces.calIItipTransport); .getService(Components.interfaces.calIItipTransport);
if (!transport) { if (!transport) {
throw new Error("iTipProcessor cannot instantiate transport"); throw new Error("iTipProcessor cannot instantiate transport" + (aCalendar ? "for " + aCalendar.type : ""));
} }
return transport; return transport;
} }

Просмотреть файл

@ -2180,10 +2180,10 @@ function sendItipInvitation(aItem) {
// is worked into the event dialog (which has been done in the prototype // is worked into the event dialog (which has been done in the prototype
// dialog to a degree) then we are going to simply hack in some attendee // dialog to a degree) then we are going to simply hack in some attendee
// support so that we can round-trip iTIP invitations. // support so that we can round-trip iTIP invitations.
// Since there is no way to determine the type of transport an var transportType = aItem.calendar.getProperty("itip.transportType") || "email";
// attendee requires, we default to email
var emlSvc = Components.classes["@mozilla.org/calendar/itip-transport;1?type=email"] var transport = Components.classes["@mozilla.org/calendar/itip-transport;1?type=" + transportType]
.createInstance(Components.interfaces.calIItipTransport); .getService(Components.interfaces.calIItipTransport);
var itipItem = Components.classes["@mozilla.org/calendar/itip-item;1"] var itipItem = Components.classes["@mozilla.org/calendar/itip-item;1"]
.createInstance(Components.interfaces.calIItipItem); .createInstance(Components.interfaces.calIItipItem);
@ -2219,7 +2219,7 @@ function sendItipInvitation(aItem) {
// For this support, we'll need a real invitation manager component. // For this support, we'll need a real invitation manager component.
var organizer = Components.classes["@mozilla.org/calendar/attendee;1"] var organizer = Components.classes["@mozilla.org/calendar/attendee;1"]
.createInstance(Components.interfaces.calIAttendee); .createInstance(Components.interfaces.calIAttendee);
organizer.id = "mailto:" + emlSvc.defaultIdentity; organizer.id = tranport.scheme + ":" + transport.defaultIdentity;
organizer.role = "REQ-PARTICIPANT"; organizer.role = "REQ-PARTICIPANT";
organizer.participationStatus = "ACCEPTED"; organizer.participationStatus = "ACCEPTED";
organizer.isOrganizer = true; organizer.isOrganizer = true;
@ -2251,9 +2251,9 @@ function sendItipInvitation(aItem) {
var subject = sb.formatStringFromName("itipRequestSubject", var subject = sb.formatStringFromName("itipRequestSubject",
[summary], 1); [summary], 1);
var body = sb.formatStringFromName("itipRequestBody", var body = sb.formatStringFromName("itipRequestBody",
[emlSvc.defaultIdentity, summary], [transport.defaultIdentity, summary],
2); 2);
// Send it! // Send it!
emlSvc.sendItems(recipients.length, recipients, subject, body, itipItem); transport.sendItems(recipients.length, recipients, subject, body, itipItem);
} }

Просмотреть файл

@ -21,6 +21,7 @@
* Contributor(s): * Contributor(s):
* Clint Talbert <ctalbert.moz@gmail.com> * Clint Talbert <ctalbert.moz@gmail.com>
* Matthew Willis <lilmatt@mozilla.com> * Matthew Willis <lilmatt@mozilla.com>
* Philipp Kewisch <mozilla@kewis.ch>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -66,6 +67,10 @@ calItipEmailTransport.prototype = {
return this.mDefaultIdentity.email; return this.mDefaultIdentity.email;
}, },
get scheme() {
return "mailto";
},
mSenderAddress: null, mSenderAddress: null,
get senderAddress() { get senderAddress() {
return this.mSenderAddress; return this.mSenderAddress;

Просмотреть файл

@ -23,6 +23,7 @@
* Clint Talbert <ctalbert.moz@gmail.com> * Clint Talbert <ctalbert.moz@gmail.com>
* Matthew Willis <lilmatt@mozilla.com> * Matthew Willis <lilmatt@mozilla.com>
* Mauro Cicognini <mcicogni@libero.it> * Mauro Cicognini <mcicogni@libero.it>
* Philipp Kewisch <mozilla@kewis.ch>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -187,14 +188,7 @@ ltnMimeConverter.prototype = {
var observer = Components.classes["@mozilla.org/observer-service;1"]. var observer = Components.classes["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService); getService(Components.interfaces.nsIObserverService);
observer.notifyObservers(null, "onItipItemCreation", 0); observer.notifyObservers(null, "onItipItemCreation", 0);
} else {
// Thunderbird 1.5.x case: We have no choice but to try
// sending the iTIP item directly with the notification
var observer = Components.classes["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService);
observer.notifyObservers(itipItem, "onItipItemCreation", 0);
} }
} catch (e) { } catch (e) {
Components.utils.reportError("convertToHTML: " + Components.utils.reportError("convertToHTML: " +
"Cannot create itipItem: " + e); "Cannot create itipItem: " + e);

Просмотреть файл

@ -21,6 +21,7 @@
* Contributor(s): * Contributor(s):
* Clint Talbert <ctalbert.moz@gmail.com> * Clint Talbert <ctalbert.moz@gmail.com>
* Matthew Willis <lilmatt@mozilla.com> * Matthew Willis <lilmatt@mozilla.com>
* Philipp Kewisch <mozilla@kewis.ch>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -61,10 +62,6 @@ function checkForItipItem(subject)
// This property was set by LightningTextCalendarConverter.js // This property was set by LightningTextCalendarConverter.js
itipItem = sinkProps.getPropertyAsInterface("itipItem", itipItem = sinkProps.getPropertyAsInterface("itipItem",
Components.interfaces.calIItipItem); Components.interfaces.calIItipItem);
} else {
// With Thunderbird 1.5.x we have to use the subject to pass the
// iTIP item because we don't have sinkProps available.
itipItem = subject.QueryInterface(Components.interfaces.calIItipItem);
} }
} catch (e) { } catch (e) {
// This will throw on every message viewed that doesn't have the // This will throw on every message viewed that doesn't have the
@ -74,6 +71,9 @@ function checkForItipItem(subject)
return; return;
} }
// Get the recipient identity and save it with the itip item.
itipItem.identity = getMsgRecipient();
// We are only called upon receipt of an invite, so ensure that isSend // We are only called upon receipt of an invite, so ensure that isSend
// is false. // is false.
itipItem.isSend = false; itipItem.isSend = false;
@ -232,9 +232,23 @@ function getMsgRecipient()
if (identities.Count() == 0) { if (identities.Count() == 0) {
// If we were not able to retrieve identities above, then we have no // If we were not able to retrieve identities above, then we have no
// choice but to revert to the default identity // choice but to revert to the default identity
var emailSvc = Components.classes["@mozilla.org/calendar/itip-transport;1?type=email"] var acctMgr = Components.classes["@mozilla.org/messenger/account-manager;1"]
.getService(Components.interfaces.calIItipTransport); .getService(Components.interfaces.nsIMsgAccountManager);
emailMap[emailSvc.defaultIdentity.toLowerCase()] = true; var identity = acctMgr.defaultAccount.defaultIdentity;
if (!identity) {
// If there isn't a default identity (i.e Local Folders is your
// default identity), then go ahead and use the first available
// identity.
var allIdentities = acctMgr.allIdentities;
if (allIdentities.Count() > 0) {
identity = allIdentities.GetElementAt(0)
.QueryInterface(Components.interfaces.nsIMsgIdentity);
} else {
// If there are no identities at all, we cannot get a recipient.
return null;
}
}
emailMap[identity.toLowerCase()] = true;
} else { } else {
// Build a map of usable email addresses // Build a map of usable email addresses
for (var i = 0; i < identities.Count(); i++) { for (var i = 0; i < identities.Count(); i++) {
@ -304,7 +318,7 @@ function getTargetCalendar()
*/ */
function setAttendeeResponse(type, eventStatus) function setAttendeeResponse(type, eventStatus)
{ {
var myAddress = getMsgRecipient(); var myAddress = gItipItem.identity
if (!myAddress) { if (!myAddress) {
// Bug 420516 -- we don't support delegation yet TODO: Localize this? // Bug 420516 -- we don't support delegation yet TODO: Localize this?
throw new Error("setAttendeeResponse: " + throw new Error("setAttendeeResponse: " +
@ -312,26 +326,31 @@ function setAttendeeResponse(type, eventStatus)
"is not supported yet. See bug 420516 for details."); "is not supported yet. See bug 420516 for details.");
} }
if (type && gItipItem) { if (type && gItipItem) {
// We set the attendee status appropriately // Some methods need a target calendar. Prompt for it first.
switch (type) { switch (type) {
case "ACCEPTED": case "ACCEPTED":
case "TENTATIVE": case "TENTATIVE":
gItipItem.setAttendeeStatus(myAddress, type);
// fall through
case "REPLY": case "REPLY":
case "PUBLISH": case "PUBLISH":
var targetCalendar = getTargetCalendar(); gItipItem.targetCalendar = getTargetCalendar();
gItipItem.targetCalendar = targetCalendar; if (!gItipItem.targetCalendar) {
doResponse(eventStatus); // The dialog was canceled, we are done.
break; return;
}
}
// Now set the attendee status and perform the iTIP action. If the
// method is not mentioned here, no further action will be taken.
switch (type) {
case "ACCEPTED":
case "TENTATIVE":
case "DECLINED": case "DECLINED":
gItipItem.setAttendeeStatus(myAddress, type); gItipItem.setAttendeeStatus(myAddress, type);
// Fall through
case "REPLY":
case "PUBLISH":
doResponse(eventStatus); doResponse(eventStatus);
break; break;
default:
// no-op. The attendee wishes to disregard the mail, so no
// further action is required.
break;
} }
} }
} }
@ -367,7 +386,7 @@ function doResponse(aLocalStatus)
} }
var itipProc = Components.classes["@mozilla.org/calendar/itip-processor;1"] var itipProc = Components.classes["@mozilla.org/calendar/itip-processor;1"]
.createInstance(Components.interfaces.calIItipProcessor); .getService(Components.interfaces.calIItipProcessor);
itipProc.processItipItem(gItipItem, operationListener); itipProc.processItipItem(gItipItem, operationListener);
} }