bug 334685 - Add iTIP/iMIP support. r=dbo
git-svn-id: svn://10.0.0.236/trunk@221456 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
ceb2af1a6f
commit
c09b85cd46
@ -1,4 +1,3 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
@ -21,6 +20,7 @@
|
||||
# Contributor(s):
|
||||
# Dan Mosedale <dan.mosedale@oracle.com>
|
||||
# Mike Shaver <shaver@off.net>
|
||||
# Matthew Willis <lilmatt@mozilla.com>
|
||||
#
|
||||
# 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
|
||||
@ -65,6 +65,8 @@ XPIDLSRCS = calIAlarmService.idl \
|
||||
calIICSService.idl \
|
||||
calIItemBase.idl \
|
||||
calIItipItem.idl \
|
||||
calIItipProcessor.idl \
|
||||
calIItipTransport.idl \
|
||||
calIRecurrenceInfo.idl \
|
||||
calIRecurrenceDate.idl \
|
||||
calIRecurrenceDateSet.idl \
|
||||
|
||||
@ -97,11 +97,6 @@
|
||||
#define CAL_RECURRENCEINFO_CONTRACTID \
|
||||
"@mozilla.org/calendar/recurrence-info;1"
|
||||
|
||||
#define CAL_ITIPITEM_CID \
|
||||
{ 0xb84de879, 0x4b85, 0x4d68, { 0x85, 0x50, 0xe0, 0xc5, 0x27, 0xe4, 0x6f, 0x98 } }
|
||||
#define CAL_ITIPITEM_CONTRACTID \
|
||||
"@mozilla.org/calendar/itip-item;1"
|
||||
|
||||
#define NS_ERROR_CALENDAR_WRONG_COMPONENT_TYPE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CALENDAR, 1)
|
||||
// Until extensible xpconnect error mapping works
|
||||
// #define NS_ERROR_CALENDAR_IMMUTABLE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CALENDAR, 2)
|
||||
|
||||
@ -241,6 +241,12 @@ interface calIItemBase : nsISupports
|
||||
// removeAttendee/addAttendee that follow the call to getAttendees.
|
||||
void getAttendees(out PRUint32 count,
|
||||
[array,size_is(count),retval] out calIAttendee attendees);
|
||||
|
||||
/**
|
||||
* getAttendeeById's matching is done in a case-insensitive manner to handle
|
||||
* places where "MAILTO:" or similar properties are capitalized arbitrarily
|
||||
* by different calendar clients.
|
||||
*/
|
||||
calIAttendee getAttendeeById(in AUTF8String id);
|
||||
void removeAttendee(in calIAttendee attendee);
|
||||
void addAttendee(in calIAttendee attendee);
|
||||
|
||||
@ -19,7 +19,8 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Clint Talbert <cmtalbert@myfastmail.com>
|
||||
* Clint Talbert <ctalbert.moz@gmail.com>
|
||||
* Matthew Willis <lilmatt@mozilla.com>
|
||||
*
|
||||
* 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
|
||||
@ -46,14 +47,20 @@ interface nsISimpleEnumerator;
|
||||
* parser, the imip-bar UI, and the iTIP processor. It encapsulates a list of
|
||||
* calIItemBase objects and provides specialized iTIP methods for those items.
|
||||
*/
|
||||
[scriptable, uuid(B84DE879-4B85-4d68-8550-E0C527E46F98)]
|
||||
[scriptable, uuid(f41392ab-dcad-4bad-818f-b3d1631c4d93)]
|
||||
interface calIItipItem : nsISupports
|
||||
{
|
||||
/**
|
||||
/**
|
||||
* Initializes the item with an ics string
|
||||
* @arg - in parameter - AString of ical Data
|
||||
* @param - in parameter - AString of ical Data
|
||||
*/
|
||||
void init(in AString icalData);
|
||||
void init(in AUTF8String icalData);
|
||||
|
||||
/**
|
||||
* Creates a new calItipItem with the same attributes as the one that
|
||||
* clone() is called upon.
|
||||
*/
|
||||
calIItipItem clone();
|
||||
|
||||
/**
|
||||
* Attribute: isSend - set to TRUE when sending this item to initiate an
|
||||
@ -68,14 +75,14 @@ interface calIItipItem : nsISupports
|
||||
/**
|
||||
* Attribute: receivedMethod - method the iTIP item had upon reciept
|
||||
*/
|
||||
attribute AString receivedMethod;
|
||||
attribute AUTF8String receivedMethod;
|
||||
|
||||
/**
|
||||
* Attribute: responseMethod - method that the protocol handler (or the
|
||||
* user) decides to use to respond to the iTIP item (could be COUNTER,
|
||||
* REPLY, DECLINECOUNTER, etc)
|
||||
*/
|
||||
attribute AString responseMethod;
|
||||
attribute AUTF8String responseMethod;
|
||||
|
||||
/**
|
||||
* Attribute: autoResponse Set to one of the three constants below
|
||||
@ -104,33 +111,47 @@ interface calIItipItem : nsISupports
|
||||
*/
|
||||
attribute calICalendar targetCalendar;
|
||||
|
||||
/**
|
||||
* localStatus: The response that the user has made to the invitation in
|
||||
* this ItipItem.
|
||||
*/
|
||||
attribute AUTF8String localStatus;
|
||||
|
||||
/**
|
||||
* Get the list of items that are encapsulated in this calIItipItem
|
||||
* @returns An array of calIItemBase items that are inside this
|
||||
* calIItipItem
|
||||
*/
|
||||
void getItemList(out unsigned long itemCount,
|
||||
[retval, array, size_is(itemCount)] out calIItemBase items);
|
||||
|
||||
/**
|
||||
* Get the first item from the iTIP message
|
||||
* Bug XXX 351761: Need to find a way to make this use an nsISimpleEnumerator
|
||||
* @return calIItemBase
|
||||
*/
|
||||
|
||||
calIItemBase getFirstItem();
|
||||
|
||||
*/
|
||||
/**
|
||||
* Get next item from the iTIP message. If there is no next item then it
|
||||
* returns NULL
|
||||
* @return calIItemBase
|
||||
*/
|
||||
|
||||
calIItemBase getNextItem();
|
||||
|
||||
*/
|
||||
/**
|
||||
* Modifies a calIItemBase that is in the component list. Internally, the
|
||||
* interface will update the proper component. It does this via the
|
||||
* UID of the component by calling hasSameIds().
|
||||
* @arg in parameter - item to modify
|
||||
* @param in parameter - item to modify
|
||||
* @return returns the new calIItemBase object for convienence
|
||||
*/
|
||||
calIItemBase modifyItem(in calIItemBase item);
|
||||
|
||||
/**
|
||||
* Modifies the state of the given attendee in the item's ics
|
||||
* @arg in parameter - AString containing attendee address
|
||||
* @arg in parameter - AString contianing the new attendee status
|
||||
* @param in parameter - AString containing attendee address
|
||||
* @param in parameter - AString contianing the new attendee status
|
||||
*/
|
||||
void setAttendeeStatus(in AString attendeeId, in AString status);
|
||||
};
|
||||
|
||||
@ -83,10 +83,11 @@ EXTRA_SCRIPTS = \
|
||||
calCalendarManager.js \
|
||||
calDateTimeFormatter.js \
|
||||
calEvent.js \
|
||||
calItemBase.js \
|
||||
calItipItem.js \
|
||||
calIcsParser.js \
|
||||
calIcsSerializer.js \
|
||||
calItemBase.js \
|
||||
calItipItem.js \
|
||||
calItipProcessor.js \
|
||||
calProtocolHandler.js \
|
||||
calRecurrenceInfo.js \
|
||||
calTodo.js \
|
||||
|
||||
@ -162,6 +162,9 @@ calEvent.prototype = {
|
||||
var calcomp = icssvc.createIcalComponent("VCALENDAR");
|
||||
calcomp.prodid = "-//Mozilla Calendar//NONSGML Sunbird//EN";
|
||||
calcomp.version = "2.0";
|
||||
if (this.hasProperty("METHOD")) {
|
||||
calcomp.method = this.getProperty("METHOD");
|
||||
}
|
||||
calcomp.addSubcomponent(this.icalComponent);
|
||||
return calcomp.serializeToICS();
|
||||
},
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
* Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
|
||||
* Mike Shaver <shaver@off.net>
|
||||
* Joey Minta <jminta@gmail.com>
|
||||
* Matthew Willis <lilmatt@mozilla.com>
|
||||
*
|
||||
* 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
|
||||
@ -408,9 +409,14 @@ calItemBase.prototype = {
|
||||
|
||||
getAttendeeById: function (id) {
|
||||
var attendees = this.getAttendees({});
|
||||
for (var i = 0; i < attendees.length; i++)
|
||||
if (attendees[i].id == id)
|
||||
return attendees[i];
|
||||
var lowerCaseId = id.toLowerCase();
|
||||
for each (var attendee in attendees) {
|
||||
// This match must be case insensitive to deal with differing
|
||||
// cases of things like MAILTO:
|
||||
if (attendee.id.toLowerCase() == lowerCaseId) {
|
||||
return attendee;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
@ -418,8 +424,10 @@ calItemBase.prototype = {
|
||||
this.modify();
|
||||
var found = false, newAttendees = [];
|
||||
var attendees = this.getAttendees({});
|
||||
var attIdLowerCase =attendee.id.toLowerCase();
|
||||
|
||||
for (var i = 0; i < attendees.length; i++) {
|
||||
if (attendees[i].id != attendee.id)
|
||||
if (attendees[i].id.toLowerCase() != attIdLowerCase)
|
||||
newAttendees.push(attendees[i]);
|
||||
else
|
||||
found = true;
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
|
||||
* Mike Shaver <shaver@off.net>
|
||||
* Matthew Willis <lilmatt@mozilla.com>
|
||||
*
|
||||
* 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
|
||||
@ -139,11 +140,16 @@ const componentData =
|
||||
script: "calWeekTitleService.js",
|
||||
constructor: "calWeekTitleService"},
|
||||
|
||||
{cid: Components.ID("{b84de879-4b85-4d68-8550-e0C527e46f98}"),
|
||||
{cid: Components.ID("{f41392ab-dcad-4bad-818f-b3d1631c4d93}"),
|
||||
contractid: "@mozilla.org/calendar/itip-item;1",
|
||||
script: "calItipItem.js",
|
||||
constructor: "calItipItem"},
|
||||
|
||||
{cid: Components.ID("{9787876b-0780-4464-8282-b7f86fb221e8}"),
|
||||
contractid: "@mozilla.org/calendar/itip-processor;1",
|
||||
script: "calItipProcessor.js",
|
||||
constructor: "calItipProcessor"},
|
||||
|
||||
{cid: Components.ID("{1e2fc0e2-bf5f-4d60-9f1e-5e92cf517c0b}"),
|
||||
contractid: "@mozilla.org/network/protocol;1?name=webcal",
|
||||
script: "calProtocolHandler.js",
|
||||
|
||||
@ -19,7 +19,8 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Clint Talbert <cmtalbert@myfastmail.com>
|
||||
* Clint Talbert <ctalbert.moz@gmail.com>
|
||||
* Matthew Willis <lilmatt@mozilla.com>
|
||||
*
|
||||
* 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
|
||||
@ -44,37 +45,29 @@ function calItipItem() {
|
||||
this.mCurrentItemIndex = 0;
|
||||
}
|
||||
|
||||
var calItipItemClassInfo = {
|
||||
getInterfaces: function (count) {
|
||||
calItipItem.prototype = {
|
||||
getInterfaces: function ciiGI(count) {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calIItipItem,
|
||||
Components.interfaces.nsIClassInfo
|
||||
Ci.nsIClassInfo,
|
||||
Ci.nsISupports,
|
||||
Ci.calIItipItem
|
||||
];
|
||||
count.value = ifaces.length;
|
||||
return ifaces;
|
||||
},
|
||||
|
||||
getHelperForLanguage: function (language) {
|
||||
getHelperForLanguage: function ciiGHFL(aLanguage) {
|
||||
return null;
|
||||
},
|
||||
|
||||
contractID: "@mozilla.org/calendar/itip-item;1",
|
||||
classDescription: "Calendar iTIP item",
|
||||
classID: Components.ID("{b84de879-4b85-4d68-8550-e0C527e46f98}"),
|
||||
classID: Components.ID("{f41392ab-dcad-4bad-818f-b3d1631c4d93}"),
|
||||
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
|
||||
flags: 0
|
||||
};
|
||||
flags: 0,
|
||||
|
||||
calItipItem.prototype = {
|
||||
QueryInterface: function (aIID) {
|
||||
if (aIID.equals(Ci.nsIClassInfo)) {
|
||||
return calItipItemClassInfo;
|
||||
}
|
||||
|
||||
if (aIID.equals(Ci.nsISupports) || aIID.equals(Ci.calIItipItem)) {
|
||||
return this;
|
||||
} else {
|
||||
QueryInterface: function ciiQI(aIid) {
|
||||
if (!aIid.equals(Ci.nsISupports) && !aIid.equals(Ci.calIItipItem)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
@ -82,108 +75,156 @@ calItipItem.prototype = {
|
||||
},
|
||||
|
||||
mIsSend: false,
|
||||
|
||||
get isSend() {
|
||||
return this.mIsSend;
|
||||
},
|
||||
set isSend(value) {
|
||||
this.mIsSend = value;
|
||||
set isSend(aValue) {
|
||||
return (this.mIsSend = aValue);
|
||||
},
|
||||
|
||||
mReceivedMethod: null,
|
||||
|
||||
get receivedMethod() {
|
||||
return this.mReceivedMethod;
|
||||
},
|
||||
set receivedMethod(value) {
|
||||
this.mReceivedMethod = value;
|
||||
set receivedMethod(aMethod) {
|
||||
return (this.mReceivedMethod = aMethod.toUpperCase());
|
||||
},
|
||||
|
||||
mResponseMethod: null,
|
||||
|
||||
get responseMethod() {
|
||||
return this.mResponseMethod;
|
||||
if (this.mIsInitialized) {
|
||||
var method = null;
|
||||
for each (var prop in this.mPropertiesList) {
|
||||
if (prop.propertyName == "METHOD") {
|
||||
method = prop.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return method;
|
||||
} else {
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
},
|
||||
set responseMethod(value) {
|
||||
this.mResponseMethod = value;
|
||||
set responseMethod(aMethod) {
|
||||
this.mResponseMethod = aMethod.toUpperCase();
|
||||
// Setting this also sets the global method attribute inside the
|
||||
// encapsulated VCALENDAR.
|
||||
if (this.mIsInitialized) {
|
||||
var methodExists = false;
|
||||
for each (var prop in this.mPropertiesList) {
|
||||
if (prop.propertyName == "METHOD") {
|
||||
methodExists = true;
|
||||
prop.value = this.mResponseMethod;
|
||||
}
|
||||
}
|
||||
|
||||
if (!methodExists) {
|
||||
var newProp = { propertyName: "METHOD",
|
||||
value: this.mResponseMethod };
|
||||
this.mPropertiesList.push(newProp);
|
||||
}
|
||||
} else {
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
return this.mResponseMethod;
|
||||
},
|
||||
|
||||
mAutoResponse: null,
|
||||
|
||||
get autoResponse() {
|
||||
return this.mAutoResponse;
|
||||
},
|
||||
set autoResponse(value) {
|
||||
this.mAutoResponse = value;
|
||||
set autoResponse(aValue) {
|
||||
return (this.mAutoResponse = aValue);
|
||||
},
|
||||
|
||||
mTargetCalendar: null,
|
||||
|
||||
get targetCalendar() {
|
||||
return this.mTargetCalendar;
|
||||
},
|
||||
set targetCalendar(value) {
|
||||
this.mTargetCalendar = value;
|
||||
set targetCalendar(aValue) {
|
||||
return (this.mTargetCalendar = aValue);
|
||||
},
|
||||
|
||||
modifyItem: function(item) {
|
||||
// Bug 348666: This will be used when we support delegation and COUNTER
|
||||
mLocalStatus: null,
|
||||
get localStatus() {
|
||||
return this.mLocalStatus;
|
||||
},
|
||||
set localStatus(aValue) {
|
||||
return (this.mLocalStatus = aValue);
|
||||
},
|
||||
|
||||
modifyItem: function ciiMI(item) {
|
||||
// Bug 348666: This will be used when we support delegation and COUNTER.
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
mItemList: null,
|
||||
mPropertiesList: null,
|
||||
|
||||
init: function(icalData) {
|
||||
this.mItemList = new Array();
|
||||
var icsService = Cc["@mozilla.org/calendar/ics-service;1"]
|
||||
.getService(Components.interfaces.calIICSService);
|
||||
var rootComp = icsService.parseICS(icalData);
|
||||
var calComp;
|
||||
// libical returns the vcalendar component if there is just
|
||||
// one vcalendar. If there are multiple vcalendars, it returns
|
||||
// an xroot component, with those vcalendar children. We need to
|
||||
// handle both cases.
|
||||
if (rootComp.componentType == 'VCALENDAR') {
|
||||
calComp = rootComp;
|
||||
} else {
|
||||
calComp = rootComp.getFirstSubcomponent('VCALENDAR');
|
||||
init: function ciiI(aIcalString) {
|
||||
var parser = Cc["@mozilla.org/calendar/ics-parser;1"].
|
||||
createInstance(Ci.calIIcsParser);
|
||||
parser.parseString(aIcalString);
|
||||
this.mItemList = parser.getItems({});
|
||||
this.mPropertiesList = parser.getProperties({});
|
||||
|
||||
// We set both methods now for safety's sake. It's the ItipProcessor's
|
||||
// responsibility to properly ascertain what the correct response
|
||||
// method is (using user feedback, prefs, etc.) for the given
|
||||
// receivedMethod. The RFC tells us to treat items without a METHOD
|
||||
// as if they were METHOD:REQUEST.
|
||||
var method;
|
||||
for each (var prop in this.mPropertiesList) {
|
||||
if (prop.propertyName == "METHOD") {
|
||||
method = prop.value;
|
||||
}
|
||||
}
|
||||
// Get the method property out of the calendar to set our methods
|
||||
var method = calComp.method;
|
||||
// We set both methods now for safety's sake. It is the iTIP
|
||||
// processor's responsibility to properly ascertain what the correct
|
||||
// response method is (using user feedback, pref's etc) for this given
|
||||
// ReceivedMethod
|
||||
this.mReceivedMethod = method;
|
||||
this.mResponseMethod = method;
|
||||
|
||||
while (calComp) {
|
||||
var subComp = calComp.getFirstSubcomponent("ANY");
|
||||
while (subComp) {
|
||||
switch (subComp.componentType) {
|
||||
case "VEVENT":
|
||||
var event = Cc["@mozilla.org/calendar/event;1"]
|
||||
.createInstance(Ci.calIEvent);
|
||||
event.icalComponent = subComp;
|
||||
this.mItemList.push(event);
|
||||
break;
|
||||
case "VTODO":
|
||||
var todo = Cc["@mozilla.org/calendar/todo;1"]
|
||||
.createInstance(Ci.calITodo);
|
||||
todo.icalComponent = subComp;
|
||||
this.mItemList.push(todo);
|
||||
break;
|
||||
default:
|
||||
// Nothing -- Bug 185537: Implement VFREEBUSY, VJOURNAL
|
||||
}
|
||||
subComp = calComp.getNextSubcomponent("ANY");
|
||||
}
|
||||
calComp = rootComp.getNextSubcomponent('VCALENDAR');
|
||||
}
|
||||
this.mIsInitialized = true;
|
||||
},
|
||||
|
||||
getFirstItem: function() {
|
||||
clone: function ciiC() {
|
||||
// Iterate through all the calItems in the original calItipItem to
|
||||
// concatenate all the calItems' icalStrings.
|
||||
var icalString = "";
|
||||
|
||||
var itemList = this.getItemList({ });
|
||||
for (var i = 0; i < itemList.length; i++) {
|
||||
icalString += itemList[i].icalString;
|
||||
}
|
||||
|
||||
// Create a new calItipItem and initialize it using the icalString
|
||||
// from above.
|
||||
var newItem = Cc["@mozilla.org/calendar/itip-item;1"].
|
||||
createInstance(Ci.calIItipItem);
|
||||
newItem.init(icalString);
|
||||
|
||||
// Copy over the exposed attributes.
|
||||
newItem.receivedMethod = this.receivedMethod;
|
||||
newItem.responseMethod = this.responseMethod;
|
||||
newItem.autoResponse = this.autoResponse;
|
||||
newItem.targetCalendar = this.targetCalendar;
|
||||
newItem.localStatus = this.localStatus;
|
||||
newItem.isSend = this.isSend;
|
||||
|
||||
return newItem;
|
||||
},
|
||||
|
||||
/**
|
||||
* This returns both the array and the number of items. An easy way to
|
||||
* call it is: var itemArray = itipItem.getItemList({ });
|
||||
*/
|
||||
getItemList: function ciiGIL(itemCountRef) {
|
||||
if (!this.mIsInitialized || (this.mItemList.length == 0)) {
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
itemCountRef.value = this.mItemList.length;
|
||||
return this.mItemList;
|
||||
},
|
||||
|
||||
/*getFirstItem: function ciiGFI() {
|
||||
if (!this.mIsInitialized || (this.mItemList.length == 0)) {
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
@ -191,7 +232,7 @@ calItipItem.prototype = {
|
||||
return this.mItemList[0];
|
||||
},
|
||||
|
||||
getNextItem: function() {
|
||||
getNextItem: function ciiGNI() {
|
||||
if (!this.mIsInitialized || (this.mItemList.length == 0)) {
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
@ -201,22 +242,44 @@ calItipItem.prototype = {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},*/
|
||||
|
||||
setAttendeeStatus: function (attendeeID, status) {
|
||||
// Note that this code forces the user to respond to all items
|
||||
// in the same way, which is a current limitation of the spec
|
||||
if (attendeeID.match(/mailto:/i)) {
|
||||
attendeeID = "mailto:" + attendeeID; // prepend mailto
|
||||
/**
|
||||
* Note that this code forces the user to respond to all items in the same
|
||||
* way, which is a current limitation of the spec.
|
||||
*/
|
||||
setAttendeeStatus: function ciiSAS(aAttendeeId, aStatus) {
|
||||
// Append "mailto:" to the attendee if it is missing it.
|
||||
var attId = aAttendeeId.toLowerCase();
|
||||
if (!attId.match(/mailto:/i)) {
|
||||
attId = "mailto:" + attId;
|
||||
}
|
||||
for (var i=0; i < this.mItemList.length; ++i) {
|
||||
var item = this.mItemList[i];
|
||||
var attendee = item.getAttendeeById(attendeeID);
|
||||
|
||||
for each (var item in this.mItemList) {
|
||||
var attendee = item.getAttendeeById(attId);
|
||||
if (attendee) {
|
||||
// XXX BUG 351589: workaround for updating an attendee
|
||||
item.removeAttendee(attendee);
|
||||
attendee.participationStatus = status;
|
||||
item.addAttendee(attendee);
|
||||
|
||||
// Replies should not have the RSVP property.
|
||||
// Since attendee.deleteProperty("RSVP") doesn't work, we must
|
||||
// create a new attendee from scratch WITHOUT the RSVP
|
||||
// property and copy in the other relevant data.
|
||||
// XXX use deleteProperty after bug 358498 is fixed.
|
||||
newAttendee = Cc["@mozilla.org/calendar/attendee;1"].
|
||||
createInstance(Ci.calIAttendee);
|
||||
if (attendee.commonName) {
|
||||
newAttendee.commonName = attendee.commonName;
|
||||
}
|
||||
if (attendee.role) {
|
||||
newAttendee.role = attendee.role;
|
||||
}
|
||||
if (attendee.userType) {
|
||||
newAttendee.userType = attendee.userType;
|
||||
}
|
||||
newAttendee.id = attendee.id;
|
||||
newAttendee.participationStatus = aStatus;
|
||||
item.addAttendee(newAttendee);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,7 +222,9 @@ bin\js\calIcsImportExport.js
|
||||
bin\js\calIcsParser.js
|
||||
bin\js\calIcsSerializer.js
|
||||
bin\js\calItemBase.js
|
||||
bin\js\calItipEmailTransport.js
|
||||
bin\js\calItipItem.js
|
||||
bin\js\calItipProcessor.js
|
||||
bin\js\calListFormatter.js
|
||||
bin\js\calMonthGridPrinter.js
|
||||
bin\js\calOutlookCSVImportExport.js
|
||||
|
||||
@ -54,6 +54,7 @@ DIRS = ../../db/sqlite3/src ../../storage \
|
||||
../libical ../base ../providers \
|
||||
../import-export \
|
||||
components \
|
||||
../itip \
|
||||
$(NULL)
|
||||
|
||||
# Select a theme from which to pull our skin goodness
|
||||
|
||||
@ -20,7 +20,8 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Mike Shaver <shaver@mozilla.org>
|
||||
* Clint Talbert <cmtalbert@myfastmail.com>
|
||||
* Clint Talbert <ctalbert.moz@gmail.com>
|
||||
* Matthew Willis <lilmatt@mozilla.com>
|
||||
*
|
||||
* 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
|
||||
@ -45,8 +46,8 @@ function makeTableRow(val) {
|
||||
|
||||
function getLightningStringBundle()
|
||||
{
|
||||
var svc = Cc["@mozilla.org/intl/stringbundle;1"]
|
||||
.getService(Ci.nsIStringBundleService);
|
||||
var svc = Cc["@mozilla.org/intl/stringbundle;1"].
|
||||
getService(Ci.nsIStringBundleService);
|
||||
return svc.createBundle("chrome://lightning/locale/lightning.properties");
|
||||
}
|
||||
|
||||
@ -107,18 +108,23 @@ function createHtml(event)
|
||||
html.body.table.appendChild(createHtmlTableSection(labelText,
|
||||
event.startDate.jsDate.toLocaleString()));
|
||||
|
||||
if (event.organizer &&
|
||||
(event.organizer.commonName || event.organizer.id)) {
|
||||
if (event.organizer &&
|
||||
(event.organizer.commonName || event.organizer.id))
|
||||
{
|
||||
labelText = stringBundle.GetStringFromName("imipHtml.organizer");
|
||||
var orgname = event.organizer.commonName || event.organizer.id;
|
||||
// Trim any instances of "mailto:" for better readibility.
|
||||
var orgname = event.organizer.commonName ||
|
||||
event.organizer.id.replace(/mailto:/ig, "");
|
||||
html.body.table.appendChild(createHtmlTableSection(labelText, orgname));
|
||||
}
|
||||
|
||||
var eventDescription = event.getProperty("DESCRIPTION");
|
||||
if (eventDescription) {
|
||||
// Remove the useless "Outlookism" squiggle.
|
||||
var desc = eventDescription.replace("*~*~*~*~*~*~*~*~*~*", "");
|
||||
|
||||
labelText = stringBundle.GetStringFromName("imipHtml.description");
|
||||
html.body.table.appendChild(createHtmlTableSection(labelText,
|
||||
eventDescription));
|
||||
html.body.table.appendChild(createHtmlTableSection(labelText,desc));
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,32 +134,48 @@ function createHtml(event)
|
||||
function ltnMimeConverter() { }
|
||||
|
||||
ltnMimeConverter.prototype = {
|
||||
QueryInterface: function (aIID) {
|
||||
QueryInterface: function QI(aIID) {
|
||||
if (!aIID.equals(Ci.nsISupports) &&
|
||||
!aIID.equals(Ci.nsISimpleMimeConverter))
|
||||
throw Ci.NS_ERROR_NO_INTERFACE;
|
||||
{
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
convertToHTML: function(contentType, data) {
|
||||
var event = Cc["@mozilla.org/calendar/event;1"]
|
||||
.createInstance(Ci.calIEvent);
|
||||
mUri: null,
|
||||
get uri() {
|
||||
return this.mUri;
|
||||
},
|
||||
set uri(aUri) {
|
||||
return (this.mUri = aUri);
|
||||
},
|
||||
|
||||
convertToHTML: function lmcCTH(contentType, data) {
|
||||
var event = Cc["@mozilla.org/calendar/event;1"].
|
||||
createInstance(Ci.calIEvent);
|
||||
event.icalString = data;
|
||||
var html = createHtml(event);
|
||||
|
||||
try {
|
||||
// Bug 351610: This mechanism is a little flawed
|
||||
var itipItem = Cc["@mozilla.org/calendar/itip-item;1"]
|
||||
.createInstance(Ci.calIItipItem);
|
||||
var itipItem = Cc["@mozilla.org/calendar/itip-item;1"].
|
||||
createInstance(Ci.calIItipItem);
|
||||
itipItem.init(data);
|
||||
var observer = Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(Ci.nsIObserverService);
|
||||
if (observer) {
|
||||
observer.notifyObservers(itipItem, "onItipItemCreation", 0);
|
||||
}
|
||||
|
||||
// this.mUri is the message URL that we are processing.
|
||||
// We use it to get the nsMsgHeaderSink to store the calItipItem.
|
||||
var msgUrl = this.mUri.QueryInterface(Ci.nsIMsgMailNewsUrl);
|
||||
var sinkProps = msgUrl.msgWindow.msgHeaderSink.properties;
|
||||
sinkProps.setPropertyAsInterface("itipItem", itipItem);
|
||||
|
||||
// Notify the observer that the itipItem is available
|
||||
var observer = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
observer.notifyObservers(null, "onItipItemCreation", 0);
|
||||
} catch (e) {
|
||||
Components.utils.reportError("Cannot Create iTIP Item: " + e);
|
||||
Components.utils.reportError("convertToHTML: " +
|
||||
"Cannot create itipItem: " + e);
|
||||
}
|
||||
|
||||
return html;
|
||||
@ -161,30 +183,30 @@ ltnMimeConverter.prototype = {
|
||||
};
|
||||
|
||||
var myModule = {
|
||||
registerSelf: function (compMgr, fileSpec, location, type) {
|
||||
registerSelf: function RS(aCompMgr, aFileSpec, aLocation, aType) {
|
||||
debug("*** Registering Lightning text/calendar handler\n");
|
||||
compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
var compMgr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
compMgr.registerFactoryLocation(this.myCID,
|
||||
"Lightning text/calendar handler",
|
||||
this.myContractID,
|
||||
fileSpec,
|
||||
location,
|
||||
type);
|
||||
aFileSpec,
|
||||
aLocation,
|
||||
aType);
|
||||
|
||||
var catman = Components.classes["@mozilla.org/categorymanager;1"]
|
||||
.getService(Ci.nsICategoryManager);
|
||||
.getService(Ci.nsICategoryManager);
|
||||
|
||||
catman.addCategoryEntry("simple-mime-converters", "text/calendar",
|
||||
this.myContractID, true, true);
|
||||
},
|
||||
|
||||
getClassObject: function (compMgr, cid, iid) {
|
||||
if (!cid.equals(this.myCID))
|
||||
getClassObject: function GCO(aCompMgr, aCid, aIid) {
|
||||
if (!aCid.equals(this.myCID)) {
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
|
||||
if (!iid.equals(Components.interfaces.nsIFactory))
|
||||
}
|
||||
if (!aIid.equals(Components.interfaces.nsIFactory)) {
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
}
|
||||
return this.myFactory;
|
||||
},
|
||||
|
||||
@ -193,15 +215,15 @@ var myModule = {
|
||||
myContractID: "@mozilla.org/lightning/mime-converter;1",
|
||||
|
||||
myFactory: {
|
||||
createInstance: function (outer, iid) {
|
||||
if (outer != null)
|
||||
createInstance: function mfCI(aOuter, aIid) {
|
||||
if (aOuter != null) {
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
return (new ltnMimeConverter()).QueryInterface(iid);
|
||||
}
|
||||
return (new ltnMimeConverter()).QueryInterface(aIid);
|
||||
}
|
||||
},
|
||||
|
||||
canUnload: function(compMgr) {
|
||||
canUnload: function CU(aCompMgr) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@ -209,4 +231,3 @@ var myModule = {
|
||||
function NSGetModule(compMgr, fileSpec) {
|
||||
return myModule;
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,8 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Clint Talbert <cmtalbert@myfastmail.com>
|
||||
* Clint Talbert <ctalbert.moz@gmail.com>
|
||||
* Matthew Willis <lilmatt@mozilla.com>
|
||||
*
|
||||
* 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
|
||||
@ -34,62 +35,68 @@
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* This bar lives inside the message window, its lifetime is the lifetime of
|
||||
* the main thunderbird message window.
|
||||
* This bar lives inside the message window.
|
||||
* Its lifetime is the lifetime of the main thunderbird message window.
|
||||
*/
|
||||
|
||||
var gItipItem;
|
||||
|
||||
/**
|
||||
* Sets up iTIP creation event listener
|
||||
* When the mime parser discovers a text/calendar attachment to a message,
|
||||
* it creates a calIItipItem and calls an observer. We watch for that
|
||||
* observer. Bug 351610 is open so that we can find a way to make this
|
||||
* communication mechanism more robust.
|
||||
*/
|
||||
const onItipItem = {
|
||||
observe: function observe(subject, topic, state) {
|
||||
if (topic == "onItipItemCreation") {
|
||||
try {
|
||||
var itipItem =
|
||||
subject.QueryInterface(Components.interfaces.calIItipItem);
|
||||
// We are only called upon receipt of an invite, so
|
||||
// ensure that isSend is false.
|
||||
itipItem.isSend = false;
|
||||
|
||||
// Until the iTIPResponder code lands, we do no response
|
||||
// at all.
|
||||
itipItem.autoResponse = Components.interfaces.calIItipItem.NONE;
|
||||
itipItem.targetCalendar = getTargetCalendar();
|
||||
|
||||
var imipMethod = getMsgImipMethod();
|
||||
if (imipMethod.length) {
|
||||
itipItem.receivedMethod = imipMethod;
|
||||
} else {
|
||||
// Thunderbird 1.5 case, we cannot get the iMIPMethod
|
||||
imipMethod = itipItem.receivedMethod;
|
||||
}
|
||||
|
||||
gItipItem = itipItem;
|
||||
|
||||
// XXX Bug 351742: no security yet
|
||||
// handleImipSecurity(imipMethod);
|
||||
|
||||
setupBar(imipMethod);
|
||||
|
||||
} catch (e) {
|
||||
Components.utils.reportError(e);
|
||||
}
|
||||
checkForItipItem();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addEventListener('messagepane-loaded', imipOnLoad, true);
|
||||
addEventListener('messagepane-unloaded', imipOnUnload, true);
|
||||
function checkForItipItem()
|
||||
{
|
||||
var itipItem;
|
||||
try {
|
||||
var msgUri = GetLoadedMessage();
|
||||
var sinkProps = msgWindow.msgHeaderSink.properties;
|
||||
// This property was set by LightningTextCalendarConverter.js
|
||||
itipItem = sinkProps.getPropertyAsInterface("itipItem",
|
||||
Components.interfaces.calIItipItem)
|
||||
} catch (e) {
|
||||
// This will throw on every message viewed that doesn't have the
|
||||
// itipItem property set on it. So we eat the errors and move on.
|
||||
|
||||
// XXX TODO: Only swallow the errors we need to. Throw all others.
|
||||
return;
|
||||
}
|
||||
|
||||
// We are only called upon receipt of an invite, so ensure that isSend
|
||||
// is false.
|
||||
itipItem.isSend = false;
|
||||
|
||||
// XXX Get these from preferences
|
||||
itipItem.autoResponse = Components.interfaces.calIItipItem.USER;
|
||||
itipItem.targetCalendar = getTargetCalendar();
|
||||
|
||||
var imipMethod = getMsgImipMethod();
|
||||
if (imipMethod.length) {
|
||||
itipItem.receivedMethod = imipMethod;
|
||||
} else {
|
||||
// Thunderbird 1.5 case, we cannot get the imipMethod
|
||||
imipMethod = itipItem.receivedMethod;
|
||||
}
|
||||
|
||||
gItipItem = itipItem;
|
||||
|
||||
// XXX Bug 351742: no S/MIME or spoofing protection yet
|
||||
// handleImipSecurity(imipMethod);
|
||||
|
||||
setupBar(imipMethod);
|
||||
}
|
||||
|
||||
addEventListener("messagepane-loaded", imipOnLoad, true);
|
||||
addEventListener("messagepane-unloaded", imipOnUnload, true);
|
||||
|
||||
/**
|
||||
* Attempt to add self to gMessageListeners defined in msgHdrViewOverlay.js
|
||||
* Add self to gMessageListeners defined in msgHdrViewOverlay.js
|
||||
*/
|
||||
function imipOnLoad()
|
||||
{
|
||||
@ -99,18 +106,20 @@ function imipOnLoad()
|
||||
gMessageListeners.push(listener);
|
||||
|
||||
// Set up our observers
|
||||
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
observerService.addObserver(onItipItem, "onItipItemCreation", false);
|
||||
var observerSvc = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
observerSvc.addObserver(onItipItem, "onItipItemCreation", false);
|
||||
}
|
||||
|
||||
function imipOnUnload()
|
||||
{
|
||||
removeEventListener('messagepane-loaded', imipOnLoad, true);
|
||||
removeEventListener('messagepane-unloaded', imipOnUnload, true);
|
||||
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
||||
.getService(Components.interfaces.nsIObserverService);
|
||||
observerService.removeObserver(onItipItem, "onItipItemCreation");
|
||||
removeEventListener("messagepane-loaded", imipOnLoad, true);
|
||||
removeEventListener("messagepane-unloaded", imipOnUnload, true);
|
||||
|
||||
var observerSvc = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
observerSvc.removeObserver(onItipItem, "onItipItemCreation");
|
||||
|
||||
gItipItem = null;
|
||||
}
|
||||
|
||||
@ -119,25 +128,27 @@ function onImipStartHeaders()
|
||||
var imipBar = document.getElementById("imip-bar");
|
||||
imipBar.setAttribute("collapsed", "true");
|
||||
|
||||
// New Message is starting, clear our iMIP/iTIP stuff so that we don't set
|
||||
// it by accident
|
||||
// A new message is starting.
|
||||
// Clear our iMIP/iTIP stuff so it doesn't contain stale information.
|
||||
imipMethod = "";
|
||||
gItipItem = null;
|
||||
}
|
||||
|
||||
// We need an onEndHeader or else MessageListner will throw. However,
|
||||
// we do not need to actually do anything in this function.
|
||||
/**
|
||||
* Required by MessageListener. no-op
|
||||
*/
|
||||
function onImipEndHeaders()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
function setupBar(imipMethod)
|
||||
{
|
||||
// XXX - Bug 348666 - Currently we only do PUBLISH requests
|
||||
// XXX - Bug 348666 - Currently we only do REQUEST requests
|
||||
// In the future this function will set up the proper actions
|
||||
// and attributes for the buttons as based on the iMIP Method
|
||||
var imipBar = document.getElementById("imip-bar");
|
||||
imipBar.setAttribute("collapsed","false");
|
||||
imipBar.setAttribute("collapsed", "false");
|
||||
var description = document.getElementById("imip-description");
|
||||
|
||||
// Bug 348666: here is where we would check if this event was already
|
||||
@ -146,13 +157,22 @@ function setupBar(imipMethod)
|
||||
description.firstChild.data = ltnGetString("lightning","imipBarText");
|
||||
}
|
||||
|
||||
// Since there is only a PUBLISH, this is easy
|
||||
var button1 = document.getElementById("imip-btn1");
|
||||
button1.removeAttribute("hidden");
|
||||
button1.setAttribute("label", ltnGetString("lightning",
|
||||
"imipAddToCalendar.label"));
|
||||
button1.setAttribute("oncommand",
|
||||
"setAttendeeResponse('PUBLISH', 'CONFIRMED');");
|
||||
var button = document.getElementById("imip-button1");
|
||||
button.removeAttribute("hidden");
|
||||
button.setAttribute("label", ltnGetString("lightning",
|
||||
"imipAcceptInvitation.label"));
|
||||
button.setAttribute("oncommand",
|
||||
"setAttendeeResponse('ACCEPTED', 'CONFIRMED');");
|
||||
|
||||
if (imipMethod == "REQUEST") {
|
||||
// Then create a DECLINE button
|
||||
button = document.getElementById("imip-button2");
|
||||
button.removeAttribute("hidden");
|
||||
button.setAttribute("label", ltnGetString("lightning",
|
||||
"imipDeclineInvitation.label"));
|
||||
button.setAttribute("oncommand",
|
||||
"setAttendeeResponse('DECLINED', 'CONFIRMED');");
|
||||
}
|
||||
}
|
||||
|
||||
function getMsgImipMethod()
|
||||
@ -171,10 +191,40 @@ function getMsgRecipient()
|
||||
var msgURI = GetLoadedMessage();
|
||||
var msgHdr = messenger.messageServiceFromURI(msgURI)
|
||||
.messageURIToMsgHdr(msgURI);
|
||||
// msgHdr.recipients is always the one recipient - the one looking at
|
||||
// the email, which is who we are interested in.
|
||||
|
||||
// msgHdr recipients can be a comma separated list of recipients.
|
||||
// We then compare against the defaultIdentity to find ourselves.
|
||||
// XXX This won't always work:
|
||||
// Users with multiple accounts and invites going to the non-default
|
||||
// account, Users with email aliases where the defaultIdentity.email
|
||||
// doesn't match the recipient, etc.
|
||||
if (msgHdr) {
|
||||
imipRecipient = msgHdr.recipients;
|
||||
var recipientList = msgHdr.recipients;
|
||||
// Remove any spaces
|
||||
recipientList = recipientList.split(" ").join("");
|
||||
recipientList = recipientList.split(",");
|
||||
|
||||
var emailSvc = Cc["@mozilla.org/calendar/itip-transport;1?type=email"].
|
||||
getService(Ci.calIItipTransport);
|
||||
var me = emailSvc.defaultIdentity;
|
||||
|
||||
var lt;
|
||||
var gt;
|
||||
for each (var recipient in recipientList) {
|
||||
// Deal with <foo@bar.com> style addresses
|
||||
lt = recipient.indexOf("<");
|
||||
gt = recipient.indexOf(">");
|
||||
|
||||
// I chose 6 since <a@b.c> is the shortest technically valid email
|
||||
// address I could come up with.
|
||||
if ((lt >= 0) && (gt >= 6)) {
|
||||
recipient = recipient.substring(lt+1, gt);
|
||||
}
|
||||
|
||||
if (recipient.toLowerCase() == me.toLowerCase()) {
|
||||
imipRecipient = recipient;
|
||||
}
|
||||
}
|
||||
}
|
||||
return imipRecipient;
|
||||
}
|
||||
@ -184,8 +234,8 @@ function getMsgRecipient()
|
||||
*/
|
||||
function getTargetCalendar()
|
||||
{
|
||||
var calMgr = Components.classes["@mozilla.org/calendar/manager;1"]
|
||||
.getService(Components.interfaces.calICalendarManager);
|
||||
var calMgr = Cc["@mozilla.org/calendar/manager;1"].
|
||||
getService(Ci.calICalendarManager);
|
||||
var cals = calMgr.getCalendars({});
|
||||
return cals[0];
|
||||
}
|
||||
@ -198,69 +248,97 @@ function setAttendeeResponse(type, eventStatus)
|
||||
{
|
||||
var myAddress = getMsgRecipient();
|
||||
if (type && gItipItem) {
|
||||
switch (type) { // We set the attendee status appropriately
|
||||
// We set the attendee status appropriately
|
||||
switch (type) {
|
||||
case "ACCEPTED":
|
||||
case "TENTATIVE":
|
||||
case "DECLINED":
|
||||
gItipItem.setAttendeeStatus(myAddress, type);
|
||||
doResponse();
|
||||
break;
|
||||
// fall through
|
||||
case "REPLY":
|
||||
case "PUBLISH":
|
||||
doResponse(eventStatus);
|
||||
break;
|
||||
default:
|
||||
// Nothing -- if given nothing then the attendee wishes to
|
||||
// disregard the mail, so no further action required
|
||||
// no-op. The attendee wishes to disregard the mail, so no
|
||||
// further action is required.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
finishItipAction(type, eventStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* doResponse performs the iTIP action for the current iTIPItem that we
|
||||
* doResponse performs the iTIP action for the current ItipItem that we
|
||||
* parsed from the email.
|
||||
* Takes an optional parameter to set the event STATUS property
|
||||
* @param aLocalStatus optional parameter to set the event STATUS property.
|
||||
* aLocalStatus can be empty, "TENTATIVE", "CONFIRMED", or "CANCELLED"
|
||||
*/
|
||||
function doResponse(eventStatus)
|
||||
function doResponse(aLocalStatus)
|
||||
{
|
||||
// XXX For now, just add the item to the calendar
|
||||
// calIOperationListener so that we can properly return status to the
|
||||
// imip-bar
|
||||
var operationListener = {
|
||||
onOperationComplete:
|
||||
function ooc(aCalendar, aStatus, aOperationType, aId, aDetail) {
|
||||
// Call finishItipAction to set the status of the operation
|
||||
finishItipAction(aOperationType, aStatus, aDetail);
|
||||
},
|
||||
|
||||
onGetResult:
|
||||
function ogr(aCalendar, aStatus, aItemType, aDetail, aCount, aItems) {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
|
||||
// The spec is unclear if we must add all the items or if the
|
||||
// user should get to pick which item gets added.
|
||||
var cal = getTargetCalendar();
|
||||
|
||||
var item = gItipItem.getFirstItem();
|
||||
while (item != null) {
|
||||
if (eventStatus.length)
|
||||
item.status = eventStatus;
|
||||
cal.addItem(item, null);
|
||||
item = gItipItem.getNextItem();
|
||||
if (aLocalStatus != null) {
|
||||
gItipItem.localStatus = aLocalStatus;
|
||||
}
|
||||
|
||||
var itipProc = Cc["@mozilla.org/calendar/itip-processor;1"].
|
||||
createInstance(Ci.calIItipProcessor);
|
||||
|
||||
itipProc.processItipItem(gItipItem, operationListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bug 348666 (complete iTIP support) - This gives the user an indication
|
||||
* that the Action occurred.
|
||||
* In the future we want to store the status of invites that you have added
|
||||
* to your calendar and provide the ability to request updates from the
|
||||
* organizer. This function will be responsible for setting up and
|
||||
* maintaining the proper lists of events and informing the user as to the
|
||||
* state of the iTIP action
|
||||
* Additionally, this function should ONLY be called once we KNOW what the
|
||||
* status of the event addition was. It must wait for a clear signal from the
|
||||
* iTIP Processor as to whether or not the event added/failed to add or
|
||||
* what have you. It should alert the user to the true status of the operation
|
||||
*
|
||||
* In the future, this will store the status of the invitation in the
|
||||
* invitation manager. This will enable us to provide the ability to request
|
||||
* updates from the organizer and to suggest changes to invitations.
|
||||
*
|
||||
* Currently, this is called from our calIOperationListener that is sent to
|
||||
* the ItipProcessor. This conveys the status of the local iTIP processing
|
||||
* on your calendar. It does not convey the success or failure of sending a
|
||||
* response to the ItipItem.
|
||||
*/
|
||||
function finishItipAction(type, eventStatus)
|
||||
function finishItipAction(aOperationType, aStatus, aDetail)
|
||||
{
|
||||
// For now, we just do something very simple
|
||||
var description = document.getElementById("imip-description");
|
||||
if (description.firstChild.data) {
|
||||
description.firstChild.data = ltnGetString("lightning",
|
||||
"imipAddedItemToCal");
|
||||
// For now, we just state the status for the user something very simple
|
||||
var desc = document.getElementById("imip-description");
|
||||
if (desc.firstChild != null) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
desc.firstChild.data = ltnGetString("lightning",
|
||||
"imipAddedItemToCal");
|
||||
document.getElementById("imip-button1").setAttribute("hidden",
|
||||
true);
|
||||
document.getElementById("imip-button2").setAttribute("hidden",
|
||||
true);
|
||||
} else {
|
||||
// Bug 348666: When we handle more iTIP methods, we need to create
|
||||
// more sophisticated error handling.
|
||||
document.getElementById("imip-bar").setAttribute("collapsed", true);
|
||||
var msg = "Invitation could not be processed. Status: " + aStatus;
|
||||
if (aDetail) {
|
||||
msg += "\nDetails: " + aDetail;
|
||||
}
|
||||
// Defined in import-export
|
||||
showError(msg);
|
||||
}
|
||||
}
|
||||
document.getElementById("imip-btn1").setAttribute("hidden", true);
|
||||
}
|
||||
|
||||
|
||||
@ -226,7 +226,8 @@
|
||||
&lightning.imipbar.description;
|
||||
</description>
|
||||
<spacer flex="1"/>
|
||||
<button id="imip-btn1" align="right"/>
|
||||
<button id="imip-button1" align="center" pack="end"/>
|
||||
<button id="imip-button2" align="center" pack="end" hidden="true"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#
|
||||
# Contributor(s):
|
||||
# Matthew Willis <lilmatt@mozilla.com>
|
||||
# Clint Talbert <ctalbert.moz@gmail.com>
|
||||
#
|
||||
# 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
|
||||
@ -55,3 +56,9 @@ imipHtml.description=Description:
|
||||
imipAddToCalendar.label=Add To Calendar
|
||||
imipAddedItemToCal=Event Added to Calendar
|
||||
imipBarText=This message contains an invitation to an event.
|
||||
imipAcceptInvitation.label=Accept
|
||||
imipDeclineInvitation.label=Decline
|
||||
|
||||
itipReplySubject=Event Invitation Reply: %1$S
|
||||
itipReplyBodyAccept=%1$S has accepted your event invitation.
|
||||
itipReplyBodyDecline=%1$S has declined your event invitation.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user