Bug 463402 - Remove E-Mail notification dialogs - Part 1: processing;r=philipp
- adding support for processing in different response modes - removing compatibility mode for OL 2002 and earlier --HG-- extra : rebase_source : 20b8933d72ed6220a03d881a93c2dfdb8061a7fc
This commit is contained in:
Родитель
03cd32f4cf
Коммит
f65c0a39f9
|
@ -227,14 +227,14 @@ function setDefaultItemValues(aItem, aCalendar=null, aStartDate=null, aEndDate=n
|
|||
* allday event.
|
||||
*/
|
||||
function createEventWithDialog(calendar, startDate, endDate, summary, event, aForceAllday) {
|
||||
let onNewEvent = function(item, opcalendar, originalItem, listener) {
|
||||
let onNewEvent = function(item, opcalendar, originalItem, listener, extresponse=null) {
|
||||
if (item.id) {
|
||||
// If the item already has an id, then this is the result of
|
||||
// saving the item without closing, and then saving again.
|
||||
doTransaction("modify", item, opcalendar, originalItem, listener);
|
||||
doTransaction("modify", item, opcalendar, originalItem, listener, extresponse);
|
||||
} else {
|
||||
// Otherwise, this is an addition
|
||||
doTransaction("add", item, opcalendar, null, listener);
|
||||
doTransaction("add", item, opcalendar, null, listener, extresponse);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -282,14 +282,14 @@ function createEventWithDialog(calendar, startDate, endDate, summary, event, aFo
|
|||
* @param initialDate (optional) The initial date for new task datepickers
|
||||
*/
|
||||
function createTodoWithDialog(calendar, dueDate, summary, todo, initialDate) {
|
||||
let onNewItem = function(item, opcalendar, originalItem, listener) {
|
||||
let onNewItem = function(item, opcalendar, originalItem, listener, extresponse=null) {
|
||||
if (item.id) {
|
||||
// If the item already has an id, then this is the result of
|
||||
// saving the item without closing, and then saving again.
|
||||
doTransaction("modify", item, opcalendar, originalItem, listener);
|
||||
doTransaction("modify", item, opcalendar, originalItem, listener, extresponse);
|
||||
} else {
|
||||
// Otherwise, this is an addition
|
||||
doTransaction("add", item, opcalendar, null, listener);
|
||||
doTransaction("add", item, opcalendar, null, listener, extresponse);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -348,8 +348,8 @@ function modifyEventWithDialog(aItem, job=null, aPromptOccurrence, initialDate=n
|
|||
return;
|
||||
}
|
||||
|
||||
let onModifyItem = function(item, calendar, originalItem, listener) {
|
||||
doTransaction("modify", item, calendar, originalItem, listener);
|
||||
let onModifyItem = function(item, calendar, originalItem, listener, extresponse=null) {
|
||||
doTransaction("modify", item, calendar, originalItem, listener, extresponse);
|
||||
};
|
||||
|
||||
let item = aItem;
|
||||
|
@ -629,8 +629,10 @@ function getTransactionMgr() {
|
|||
* @param aCalendar The calendar to do the transaction on
|
||||
* @param aOldItem (optional) some actions require an old item
|
||||
* @param aListener (optional) the listener to call when complete.
|
||||
* @param aExtResponse (optional) JS object with additional parameters for sending itip messages
|
||||
* (see also description of checkAndSend in calItipUtils.jsm)
|
||||
*/
|
||||
function doTransaction(aAction, aItem, aCalendar, aOldItem, aListener) {
|
||||
function doTransaction(aAction, aItem, aCalendar, aOldItem, aListener, aExtResponse=null) {
|
||||
// This is usually a user-initiated transaction, so make sure the calendar
|
||||
// this transaction is happening on is visible.
|
||||
ensureCalendarVisible(aCalendar);
|
||||
|
@ -640,7 +642,8 @@ function doTransaction(aAction, aItem, aCalendar, aOldItem, aListener) {
|
|||
aItem,
|
||||
aCalendar,
|
||||
aOldItem,
|
||||
aListener ? aListener : null);
|
||||
aListener ? aListener : null,
|
||||
aExtResponse);
|
||||
updateUndoRedoMenu();
|
||||
}
|
||||
|
||||
|
@ -705,15 +708,27 @@ function updateUndoRedoMenu() {
|
|||
goUpdateCommand("cmd_redo");
|
||||
}
|
||||
|
||||
function setContextPartstat(value, scope, items) {
|
||||
/**
|
||||
* Updates the partstat of the calendar owner for specified items triggered by a
|
||||
* ontext menu operation
|
||||
*
|
||||
* @param {String} aPartStat a valid partstat string as per RfC 5545
|
||||
* @param {String} aScope indicates the scope of anrecurring event - must
|
||||
* be 'this-occurrence' || 'all-occurences'
|
||||
* @param {Array} aItems an array of calEvent or calIToDo items
|
||||
* @param {Object} aExtResponse [optional] an object to provide additional
|
||||
* parameters for sending itip messages as response
|
||||
* response
|
||||
*/
|
||||
function setContextPartstat(aPartStat, aScope, aItems, aExtResponse=null) {
|
||||
startBatchTransaction();
|
||||
try {
|
||||
for (let oldItem of items) {
|
||||
for (let oldItem of aItems) {
|
||||
// Skip this item if its calendar is read only.
|
||||
if (oldItem.calendar.readOnly) {
|
||||
continue;
|
||||
}
|
||||
if (scope == "all-occurrences") {
|
||||
if (aScope == "all-occurrences") {
|
||||
oldItem = oldItem.parentItem;
|
||||
}
|
||||
let attendee = null;
|
||||
|
@ -732,7 +747,7 @@ function setContextPartstat(value, scope, items) {
|
|||
let newItem = oldItem.clone();
|
||||
let newAttendee = attendee.clone();
|
||||
|
||||
newAttendee.participationStatus = value;
|
||||
newAttendee.participationStatus = aPartStat;
|
||||
if (newAttendee.isOrganizer) {
|
||||
newItem.organizer = newAttendee;
|
||||
} else {
|
||||
|
@ -740,7 +755,7 @@ function setContextPartstat(value, scope, items) {
|
|||
newItem.addAttendee(newAttendee);
|
||||
}
|
||||
|
||||
doTransaction("modify", newItem, newItem.calendar, oldItem, null);
|
||||
doTransaction("modify", newItem, newItem.calendar, oldItem, null, aExtResponse);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -634,8 +634,19 @@ cal.itip = {
|
|||
*
|
||||
* Checks to see if e.g. attendees were added/removed or an item has been
|
||||
* deleted and sends out appropriate iTIP messages.
|
||||
* @param {Number} aOpType Type of operation - (e.g. ADD, MODIFY or DELETE)
|
||||
* @param {calIEvent|calITodo} aItem The updated item
|
||||
* @param {calIEvent|calITodo} aOriginalItem The original item
|
||||
* @param {Object} aExtResponse [optional] An object to provide additional
|
||||
* parameters for sending itip messages as response
|
||||
* mode, comments or a subset of recipients. Currently
|
||||
* implemented attributes are:
|
||||
* * responseMode Response mode (long) as defined for autoResponse
|
||||
* of calIItipItem. The default mode is USER (which
|
||||
* will trigger displaying the previously known popup
|
||||
* to ask the user whether to send)
|
||||
*/
|
||||
checkAndSend: function(aOpType, aItem, aOriginalItem) {
|
||||
checkAndSend: function(aOpType, aItem, aOriginalItem, aExtResponse=null) {
|
||||
// balance out parts of the modification vs delete confusion, deletion of occurrences
|
||||
// are notified as parent modifications and modifications of occurrences are notified
|
||||
// as mixed new-occurrence, old-parent (IIRC).
|
||||
|
@ -679,8 +690,30 @@ cal.itip = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
let autoResponse = { value: false }; // controls confirm to send email only once
|
||||
// for backward compatibility, we assume USER mode if not set otherwise
|
||||
let autoResponse = { mode: Ci.calIItipItem.USER };
|
||||
if (aExtResponse && aExtResponse.hasOwnProperty("responseMode")) {
|
||||
switch (aExtResponse.responseMode) {
|
||||
case Ci.calIItipItem.AUTO:
|
||||
case Ci.calIItipItem.NONE:
|
||||
case Ci.calIItipItem.USER:
|
||||
autoResponse.mode = aExtResponse.responseMode;
|
||||
break;
|
||||
default:
|
||||
cal.ERROR("cal.itip.checkAndSend(): Invalid value " + aExtResponse.responseMode +
|
||||
" provided for responseMode attribute in argument aExtResponse." +
|
||||
" Falling back to USER mode.\r\n" + cal.STACK(20));
|
||||
}
|
||||
} else {
|
||||
// let's log something useful to notify addon developers or find any missing pieces in
|
||||
// the conversions
|
||||
cal.LOG("cal.itip.checkAndSend: no response mode provided, " +
|
||||
"falling back to USER mode.\r\n" + cal.STACK(20));
|
||||
}
|
||||
if (autoResponse.mode == Ci.calIItipItem.NONE) {
|
||||
// we stop here and don't send anything if the user opted out before
|
||||
return;
|
||||
}
|
||||
|
||||
let invitedAttendee = cal.isInvitation(aItem) && cal.getInvitedAttendee(aItem);
|
||||
if (invitedAttendee) { // actually is an invitation copy, fix attendee list to send REPLY
|
||||
|
@ -954,10 +987,10 @@ cal.itip = {
|
|||
/**
|
||||
* A shortcut to send DECLINECOUNTER messages - for everything else use cal.itip.checkAndSend
|
||||
*
|
||||
* @param aItem iTIP item to be sent
|
||||
* @param aMethod iTIP method
|
||||
* @param aRecipientsList an array of calIAttendee objects the message should be sent to
|
||||
* @param aAutoResponse an inout object whether the transport should ask before sending
|
||||
* @param {calIItipItem} aItem item to be sent
|
||||
* @param {String} aMethod iTIP method
|
||||
* @param {Array} aRecipientsList array of calIAttendee objects the message should be sent to
|
||||
* @param {Object} aAutoResponse JS object whether the transport should ask before sending
|
||||
*/
|
||||
sendDeclineCounterMessage: function(aItem, aMethod, aRecipientsList, aAutoResponse) {
|
||||
if (aMethod == "DECLINECOUNTER") {
|
||||
|
@ -1142,17 +1175,15 @@ function sendMessage(aItem, aMethod, aRecipientsList, autoResponse) {
|
|||
transport = transport.QueryInterface(Components.interfaces.calIItipTransport);
|
||||
|
||||
let _sendItem = function(aSendToList, aSendItem) {
|
||||
let cIII = Components.interfaces.calIItipItem;
|
||||
let itipItem = Components.classes["@mozilla.org/calendar/itip-item;1"]
|
||||
.createInstance(cIII);
|
||||
.createInstance(Ci.calIItipItem);
|
||||
itipItem.init(cal.item.serialize(aSendItem));
|
||||
itipItem.responseMethod = aMethod;
|
||||
itipItem.targetCalendar = aSendItem.calendar;
|
||||
itipItem.autoResponse = autoResponse && autoResponse.value ? cIII.AUTO : cIII.USER;
|
||||
if (autoResponse) {
|
||||
autoResponse.value = true; // auto every following
|
||||
}
|
||||
// XXX I don't know whether the below are used at all, since we don't use the itip processor
|
||||
itipItem.autoResponse = autoResponse.mode;
|
||||
// we switch to AUTO for each subsequent call of _sendItem()
|
||||
autoResponse.mode = Ci.calIItipItem.AUTO;
|
||||
// XXX I don't know whether the below is used at all, since we don't use the itip processor
|
||||
itipItem.isSend = true;
|
||||
|
||||
return transport.sendItems(aSendToList.length, aSendToList, itipItem);
|
||||
|
@ -1189,16 +1220,22 @@ function sendMessage(aItem, aMethod, aRecipientsList, autoResponse) {
|
|||
* @param opListener operation listener to forward
|
||||
* @param oldItem the previous item before modification (if any)
|
||||
*/
|
||||
function ItipOpListener(opListener, oldItem) {
|
||||
this.mOpListener = opListener;
|
||||
this.mOldItem = oldItem;
|
||||
function ItipOpListener(aOpListener, aOldItem, aExtResponse=null) {
|
||||
this.mOpListener = aOpListener;
|
||||
this.mOldItem = aOldItem;
|
||||
this.mExtResponse = aExtResponse;
|
||||
}
|
||||
ItipOpListener.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.calIOperationListener]),
|
||||
|
||||
mOpListener: null,
|
||||
mOldItem: null,
|
||||
mExtResponse: null,
|
||||
|
||||
onOperationComplete: function(aCalendar, aStatus, aOperationType, aId, aDetail) {
|
||||
cal.ASSERT(Components.isSuccessCode(aStatus), "error on iTIP processing");
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
cal.itip.checkAndSend(aOperationType, aDetail, this.mOldItem);
|
||||
cal.itip.checkAndSend(aOperationType, aDetail, this.mOldItem, this.mExtResponse);
|
||||
}
|
||||
if (this.mOpListener) {
|
||||
this.mOpListener.onOperationComplete(aCalendar,
|
||||
|
@ -1407,7 +1444,7 @@ ItipItemFinder.prototype = {
|
|||
cal.ASSERT(attendees.length == 1,
|
||||
"invalid number of attendees in REFRESH!");
|
||||
if (attendees.length > 0) {
|
||||
let action = function(opListener) {
|
||||
let action = function(opListener, partStat, extResponse) {
|
||||
if (!item.organizer) {
|
||||
let org = createOrganizer(item.calendar);
|
||||
if (org) {
|
||||
|
@ -1415,7 +1452,12 @@ ItipItemFinder.prototype = {
|
|||
item.organizer = org;
|
||||
}
|
||||
}
|
||||
sendMessage(item, "REQUEST", attendees, true /* don't ask */);
|
||||
sendMessage(
|
||||
item,
|
||||
"REQUEST",
|
||||
attendees,
|
||||
{ responseMode: Ci.calIItipItem.AUTO } /* don't ask */
|
||||
);
|
||||
};
|
||||
operations.push(action);
|
||||
}
|
||||
|
@ -1427,7 +1469,7 @@ ItipItemFinder.prototype = {
|
|||
if (item.calendar.getProperty("itip.disableRevisionChecks") ||
|
||||
cal.itip.compare(itipItemItem, item) > 0) {
|
||||
let newItem = updateItem(item, itipItemItem);
|
||||
let action = function(opListener) {
|
||||
let action = function(opListener, partStat, extResponse) {
|
||||
return newItem.calendar.modifyItem(newItem, item, opListener);
|
||||
};
|
||||
actionMethod = method + ":UPDATE";
|
||||
|
@ -1457,7 +1499,7 @@ ItipItemFinder.prototype = {
|
|||
(item.calendar.getProperty("itip.disableRevisionChecks") ||
|
||||
cal.itip.compare(itipItemItem, item) == 0)) {
|
||||
actionMethod = "REQUEST:NEEDS-ACTION";
|
||||
operations.push((opListener, partStat) => {
|
||||
operations.push((opListener, partStat, extResponse) => {
|
||||
let changedItem = firstFoundItem.clone();
|
||||
changedItem.removeAttendee(foundAttendee);
|
||||
foundAttendee = foundAttendee.clone();
|
||||
|
@ -1467,7 +1509,7 @@ ItipItemFinder.prototype = {
|
|||
changedItem.addAttendee(foundAttendee);
|
||||
|
||||
return changedItem.calendar.modifyItem(
|
||||
changedItem, firstFoundItem, new ItipOpListener(opListener, firstFoundItem));
|
||||
changedItem, firstFoundItem, new ItipOpListener(opListener, firstFoundItem, extResponse));
|
||||
});
|
||||
} else if (item.calendar.getProperty("itip.disableRevisionChecks") ||
|
||||
cal.itip.compare(itipItemItem, item) > 0) {
|
||||
|
@ -1477,7 +1519,7 @@ ItipItemFinder.prototype = {
|
|||
cal.itip.getSequence(item);
|
||||
actionMethod = (isMinorUpdate ? method + ":UPDATE-MINOR"
|
||||
: method + ":UPDATE");
|
||||
operations.push((opListener, partStat) => {
|
||||
operations.push((opListener, partStat, extResponse) => {
|
||||
if (!partStat) { // keep PARTSTAT
|
||||
let att_ = cal.getInvitedAttendee(item);
|
||||
partStat = att_ ? att_.participationStatus : "NEEDS-ACTION";
|
||||
|
@ -1487,7 +1529,7 @@ ItipItemFinder.prototype = {
|
|||
att.participationStatus = partStat;
|
||||
newItem.addAttendee(att);
|
||||
return newItem.calendar.modifyItem(
|
||||
newItem, item, new ItipOpListener(opListener, item));
|
||||
newItem, item, new ItipOpListener(opListener, item, extResponse));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1546,7 +1588,7 @@ ItipItemFinder.prototype = {
|
|||
// Make sure the provider-specified properties are copied over
|
||||
copyProviderProperties(this.mItipItem, itipItemItem, newItem);
|
||||
|
||||
let action = function(opListener) {
|
||||
let action = function(opListener, partStat, extResponse) {
|
||||
// n.b.: this will only be processed in case of reply or
|
||||
// declining the counter request - of sending the
|
||||
// appropriate reply will be taken care within the
|
||||
|
@ -1555,7 +1597,7 @@ ItipItemFinder.prototype = {
|
|||
return newItem.calendar.modifyItem(
|
||||
newItem, item,
|
||||
newItem.calendar.getProperty("itip.notify-replies")
|
||||
? new ItipOpListener(opListener, item)
|
||||
? new ItipOpListener(opListener, item, extResponse)
|
||||
: opListener);
|
||||
};
|
||||
operations.push(action);
|
||||
|
@ -1582,15 +1624,21 @@ ItipItemFinder.prototype = {
|
|||
// Make sure the provider-specified properties are copied over
|
||||
copyProviderProperties(this.mItipItem, itipItemItem, newItem);
|
||||
|
||||
operations.push(opListener => newItem.calendar.modifyItem(newItem, item, opListener));
|
||||
operations.push((opListener, partStat, extResponse) =>
|
||||
newItem.calendar.modifyItem(newItem, item, opListener)
|
||||
);
|
||||
}
|
||||
newItem.recurrenceInfo.removeOccurrenceAt(rid);
|
||||
} else if (item.recurrenceId && (item.recurrenceId.compare(rid) == 0)) {
|
||||
// parentless occurrence to be deleted (future)
|
||||
operations.push(opListener => item.calendar.deleteItem(item, opListener));
|
||||
operations.push((opListener, partStat, extResponse) =>
|
||||
item.calendar.deleteItem(item, opListener)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
operations.push(opListener => item.calendar.deleteItem(item, opListener));
|
||||
operations.push((opListener, partStat, extResponse) =>
|
||||
item.calendar.deleteItem(item, opListener)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1612,7 +1660,7 @@ ItipItemFinder.prototype = {
|
|||
switch (method) {
|
||||
case "REQUEST":
|
||||
case "PUBLISH": {
|
||||
let action = (opListener, partStat) => {
|
||||
let action = (opListener, partStat, extResponse) => {
|
||||
let newItem = itipItemItem.clone();
|
||||
setReceivedInfo(newItem, itipItemItem);
|
||||
newItem.parentItem.calendar = this.mItipItem.targetCalendar;
|
||||
|
@ -1641,7 +1689,7 @@ ItipItemFinder.prototype = {
|
|||
}
|
||||
return newItem.calendar.addItem(newItem,
|
||||
method == "REQUEST"
|
||||
? new ItipOpListener(opListener, null)
|
||||
? new ItipOpListener(opListener, null, extResponse)
|
||||
: opListener);
|
||||
};
|
||||
operations.push(action);
|
||||
|
@ -1661,10 +1709,10 @@ ItipItemFinder.prototype = {
|
|||
cal.LOG("iTIP operations: " + operations.length);
|
||||
let actionFunc = null;
|
||||
if (operations.length > 0) {
|
||||
actionFunc = function(opListener, partStat) {
|
||||
actionFunc = function(opListener, partStat=null, extResponse=null) {
|
||||
for (let operation of operations) {
|
||||
try {
|
||||
operation(opListener, partStat);
|
||||
operation(opListener, partStat, extResponse);
|
||||
} catch (exc) {
|
||||
cal.ERROR(exc);
|
||||
}
|
||||
|
|
|
@ -14,15 +14,15 @@ interface calIOperationListener;
|
|||
* regarding the calendar. It is here as a service so that we can keep the
|
||||
* transactions around without holding onto the whole global js scope+window.
|
||||
*/
|
||||
[scriptable, uuid(40a1ccf4-5f54-4815-b842-abf06f84dbfd)]
|
||||
[scriptable, uuid(1d529847-d292-4222-b066-b8b17a794d62)]
|
||||
interface calITransactionManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* @param aAction The Action to execute. This can be one of:
|
||||
* add Adds an item
|
||||
* modify Modfifies an item
|
||||
* delete Deletes an item
|
||||
* move Move an item from one calendar to the
|
||||
* * add Adds an item
|
||||
* * modify Modfifies an item
|
||||
* * delete Deletes an item
|
||||
* * move Move an item from one calendar to the
|
||||
* next. With this operation, aCalendar is
|
||||
* the calendar that the event should be
|
||||
* moved to.
|
||||
|
@ -33,12 +33,16 @@ interface calITransactionManager : nsISupports
|
|||
* modify.
|
||||
* @param aListener The listener to call when the transaction has
|
||||
* completed. This parameter can be null.
|
||||
* @param aExtResponse JS object to provide additional parameters to prepare an itip message.
|
||||
Valid attributes are:
|
||||
* * responseMode A value as defined for calIItipItem.autoResponse
|
||||
*/
|
||||
void createAndCommitTxn(in AUTF8String aAction,
|
||||
in calIItemBase aItem,
|
||||
in calICalendar aCalendar,
|
||||
in calIItemBase aOldItem,
|
||||
in calIOperationListener aListener);
|
||||
in calIOperationListener aListener,
|
||||
in jsval aExtResponse);
|
||||
|
||||
/**
|
||||
* Signals the transaction manager that a series of transactions are going
|
||||
|
|
|
@ -65,8 +65,8 @@ category profile-after-change calendar-startup-service @mozilla.org/calendar/sta
|
|||
component {fcb54c82-2fb9-42cb-bf44-1e197a55e520} calItemModule.js
|
||||
contract @mozilla.org/calendar/transaction;1 {fcb54c82-2fb9-42cb-bf44-1e197a55e520}
|
||||
|
||||
component {40a1ccf4-5f54-4815-b842-abf06f84dbfd} calItemModule.js
|
||||
contract @mozilla.org/calendar/transactionmanager;1 {40a1ccf4-5f54-4815-b842-abf06f84dbfd}
|
||||
component {1d529847-d292-4222-b066-b8b17a794d62} calItemModule.js
|
||||
contract @mozilla.org/calendar/transactionmanager;1 {1d529847-d292-4222-b066-b8b17a794d62}
|
||||
|
||||
component {7af51168-6abe-4a31-984d-6f8a3989212d} calItemModule.js
|
||||
contract @mozilla.org/calendar/todo;1 {7af51168-6abe-4a31-984d-6f8a3989212d}
|
||||
|
|
|
@ -15,7 +15,7 @@ function calTransactionManager() {
|
|||
}
|
||||
}
|
||||
|
||||
var calTransactionManagerClassID = Components.ID("{40a1ccf4-5f54-4815-b842-abf06f84dbfd}");
|
||||
var calTransactionManagerClassID = Components.ID("{1d529847-d292-4222-b066-b8b17a794d62}");
|
||||
var calTransactionManagerInterfaces = [Components.interfaces.calITransactionManager];
|
||||
calTransactionManager.prototype = {
|
||||
|
||||
|
@ -30,12 +30,13 @@ calTransactionManager.prototype = {
|
|||
}),
|
||||
|
||||
transactionManager: null,
|
||||
createAndCommitTxn: function(aAction, aItem, aCalendar, aOldItem, aListener) {
|
||||
createAndCommitTxn: function(aAction, aItem, aCalendar, aOldItem, aListener, aExtResponse) {
|
||||
let txn = new calTransaction(aAction,
|
||||
aItem,
|
||||
aCalendar,
|
||||
aOldItem,
|
||||
aListener);
|
||||
aListener,
|
||||
aExtResponse);
|
||||
this.transactionManager.doTransaction(txn);
|
||||
},
|
||||
|
||||
|
@ -77,13 +78,14 @@ calTransactionManager.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
function calTransaction(aAction, aItem, aCalendar, aOldItem, aListener) {
|
||||
function calTransaction(aAction, aItem, aCalendar, aOldItem, aListener, aExtResponse) {
|
||||
this.wrappedJSObject = this;
|
||||
this.mAction = aAction;
|
||||
this.mItem = aItem;
|
||||
this.mCalendar = aCalendar;
|
||||
this.mOldItem = aOldItem;
|
||||
this.mListener = aListener;
|
||||
this.mExtResponse = aExtResponse;
|
||||
}
|
||||
|
||||
var calTransactionClassID = Components.ID("{fcb54c82-2fb9-42cb-bf44-1e197a55e520}");
|
||||
|
@ -108,12 +110,14 @@ calTransaction.prototype = {
|
|||
mOldCalendar: null,
|
||||
mListener: null,
|
||||
mIsDoTransaction: false,
|
||||
mExtResponse: null,
|
||||
|
||||
onOperationComplete: function(aCalendar, aStatus, aOperationType, aId, aDetail) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
cal.itip.checkAndSend(aOperationType,
|
||||
aDetail,
|
||||
this.mIsDoTransaction ? this.mOldItem : this.mItem);
|
||||
this.mIsDoTransaction ? this.mOldItem : this.mItem,
|
||||
this.mExtResponse);
|
||||
|
||||
if (aOperationType == Components.interfaces.calIOperationListener.ADD ||
|
||||
aOperationType == Components.interfaces.calIOperationListener.MODIFY) {
|
||||
|
|
|
@ -17,7 +17,7 @@ function calItipEmailTransport() {
|
|||
this._initEmailTransport();
|
||||
}
|
||||
var calItipEmailTransportClassID = Components.ID("{d4d7b59e-c9e0-4a7a-b5e8-5958f85515f0}");
|
||||
var calItipEmailTransportInterfaces = [Components.interfaces.calIItipTransport];
|
||||
var calItipEmailTransportInterfaces = [Ci.calIItipTransport];
|
||||
calItipEmailTransport.prototype = {
|
||||
classID: calItipEmailTransportClassID,
|
||||
QueryInterface: XPCOMUtils.generateQI(calItipEmailTransportInterfaces),
|
||||
|
@ -55,7 +55,7 @@ calItipEmailTransport.prototype = {
|
|||
return this._sendXpcomMail(aRecipients, items.subject, items.body, aItipItem);
|
||||
} else {
|
||||
// sending xpcom mail is not available if no identity has been set
|
||||
throw Components.results.NS_ERROR_NOT_AVAILABLE;
|
||||
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -198,7 +198,7 @@ calItipEmailTransport.prototype = {
|
|||
// identity.
|
||||
let allIdentities = MailServices.accounts.allIdentities;
|
||||
if (allIdentities.length > 0) {
|
||||
this.mDefaultIdentity = allIdentities.queryElementAt(0, Components.interfaces.nsIMsgIdentity);
|
||||
this.mDefaultIdentity = allIdentities.queryElementAt(0, Ci.nsIMsgIdentity);
|
||||
} else {
|
||||
// If there are no identities, then we are in the same
|
||||
// situation as if we didn't have Xpcom Mail.
|
||||
|
@ -212,17 +212,19 @@ calItipEmailTransport.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
_sendXpcomMail: function(aToList, aSubject, aBody, aItem) {
|
||||
_sendXpcomMail: function(aToList, aSubject, aBody, aItipItem) {
|
||||
let identity = null;
|
||||
let account;
|
||||
if (aItem.targetCalendar) {
|
||||
identity = aItem.targetCalendar.getProperty("imip.identity");
|
||||
if (aItipItem.targetCalendar) {
|
||||
identity = aItipItem.targetCalendar.getProperty("imip.identity");
|
||||
if (identity) {
|
||||
identity = identity.QueryInterface(Components.interfaces.nsIMsgIdentity);
|
||||
account = aItem.targetCalendar.getProperty("imip.account")
|
||||
.QueryInterface(Components.interfaces.nsIMsgAccount);
|
||||
identity = identity.QueryInterface(Ci.nsIMsgIdentity);
|
||||
account = aItipItem.targetCalendar
|
||||
.getProperty("imip.account")
|
||||
.QueryInterface(Ci.nsIMsgAccount);
|
||||
} else {
|
||||
cal.WARN("No email identity configured for calendar " + aItem.targetCalendar.name);
|
||||
cal.WARN("No email identity configured for calendar " +
|
||||
aItipItem.targetCalendar.name);
|
||||
}
|
||||
}
|
||||
if (!identity) { // use some default identity/account:
|
||||
|
@ -230,41 +232,34 @@ calItipEmailTransport.prototype = {
|
|||
account = this.mDefaultAccount;
|
||||
}
|
||||
|
||||
let compatMode = 0;
|
||||
switch (aItem.autoResponse) {
|
||||
case Components.interfaces.calIItipItem.USER: {
|
||||
cal.LOG("sendXpcomMail: Found USER autoResponse type.\n" +
|
||||
"This type is currently unsupported, the compose API will always enter a text/plain\n" +
|
||||
"or text/html part as first part of the message.\n" +
|
||||
"This will disable OL (up to 2003) to consume the mail as an iTIP invitation showing\n" +
|
||||
"the usual calendar buttons.");
|
||||
// To somehow have a last resort before sending spam, the user can choose to send the mail.
|
||||
let prefCompatMode = Preferences.get("calendar.itip.compatSendMode", 0);
|
||||
let inoutCheck = { value: prefCompatMode == 1 };
|
||||
switch (aItipItem.autoResponse) {
|
||||
case Ci.calIItipItem.USER: {
|
||||
cal.LOG("sendXpcomMail: Found USER autoResponse type.");
|
||||
// We still need this as a last resort if a user just deletes or
|
||||
// drags an invitation related event
|
||||
let parent = Services.wm.getMostRecentWindow(null);
|
||||
if (parent.closed) {
|
||||
parent = cal.window.getCalendarWindow();
|
||||
}
|
||||
if (Services.prompt.confirmEx(parent,
|
||||
cal.calGetString("lightning", "imipSendMail.title", null, "lightning"),
|
||||
cal.calGetString("lightning", "imipSendMail.text", null, "lightning"),
|
||||
Services.prompt.STD_YES_NO_BUTTONS,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
cal.calGetString("lightning", "imipSendMail.Outlook2000CompatMode.text", null, "lightning"),
|
||||
inoutCheck)) {
|
||||
let confirmed = Services.prompt.confirmEx(
|
||||
parent,
|
||||
cal.calGetString("lightning", "imipSendMail.title", null, "lightning"),
|
||||
cal.calGetString("lightning", "imipSendMail.text", null, "lightning"),
|
||||
Services.prompt.STD_YES_NO_BUTTONS,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{}
|
||||
);
|
||||
if (!confirmed) {
|
||||
break;
|
||||
} // else go on with auto sending for now
|
||||
compatMode = (inoutCheck.value ? 1 : 0);
|
||||
if (compatMode != prefCompatMode) {
|
||||
Preferences.set("calendar.itip.compatSendMode", compatMode);
|
||||
}
|
||||
}
|
||||
// falls through, based on prompting above
|
||||
case Components.interfaces.calIItipItem.AUTO: {
|
||||
// falls through intended
|
||||
case Ci.calIItipItem.AUTO: {
|
||||
// don't show log message in case of falling through
|
||||
if (aItem.autoResponse == Components.interfaces.calIItipItem.AUTO) {
|
||||
if (aItipItem.autoResponse == Ci.calIItipItem.AUTO) {
|
||||
cal.LOG("sendXpcomMail: Found AUTO autoResponse type.");
|
||||
}
|
||||
let cbEmail = function(aVal, aInd, aArr) {
|
||||
|
@ -280,14 +275,14 @@ calItipEmailTransport.prototype = {
|
|||
return false;
|
||||
}
|
||||
let toList = toMap.join(", ");
|
||||
let composeUtils = Components.classes["@mozilla.org/messengercompose/computils;1"]
|
||||
.createInstance(Components.interfaces.nsIMsgCompUtils);
|
||||
let composeUtils = Cc["@mozilla.org/messengercompose/computils;1"]
|
||||
.createInstance(Ci.nsIMsgCompUtils);
|
||||
let messageId = composeUtils.msgGenerateMessageId(identity);
|
||||
let mailFile = this._createTempImipFile(compatMode, toList, aSubject, aBody, aItem, identity, messageId);
|
||||
let mailFile = this._createTempImipFile(toList, aSubject, aBody, aItipItem, identity, messageId);
|
||||
if (mailFile) {
|
||||
// compose fields for message: from/to etc need to be specified both here and in the file
|
||||
let composeFields = Components.classes["@mozilla.org/messengercompose/composefields;1"]
|
||||
.createInstance(Components.interfaces.nsIMsgCompFields);
|
||||
let composeFields = Cc["@mozilla.org/messengercompose/composefields;1"]
|
||||
.createInstance(Ci.nsIMsgCompFields);
|
||||
composeFields.characterSet = "UTF-8";
|
||||
composeFields.to = toList;
|
||||
let mailfrom = (identity.fullName.length ? identity.fullName + " <" + identity.email + ">" : identity.email);
|
||||
|
@ -314,16 +309,16 @@ calItipEmailTransport.prototype = {
|
|||
// "@mozilla.org/messengercompose/composesendlistener;1"
|
||||
// and/or "chrome://messenger/content/messengercompose/sendProgress.xul"
|
||||
// i.e. bug 432662
|
||||
let msgSend = Components.classes["@mozilla.org/messengercompose/send;1"]
|
||||
.createInstance(Components.interfaces.nsIMsgSend);
|
||||
let msgSend = Cc["@mozilla.org/messengercompose/send;1"]
|
||||
.createInstance(Ci.nsIMsgSend);
|
||||
msgSend.sendMessageFile(identity,
|
||||
account.key,
|
||||
composeFields,
|
||||
mailFile,
|
||||
true, // deleteSendFileOnCompletion
|
||||
false, // digest_p
|
||||
(Services.io.offline ? Components.interfaces.nsIMsgSend.nsMsgQueueForLater
|
||||
: Components.interfaces.nsIMsgSend.nsMsgDeliverNow),
|
||||
(Services.io.offline ? Ci.nsIMsgSend.nsMsgQueueForLater
|
||||
: Ci.nsIMsgSend.nsMsgDeliverNow),
|
||||
null, // nsIMsgDBHdr msgToReplace
|
||||
null, // nsIMsgSendListener aListener
|
||||
null, // nsIMsgStatusFeedback aStatusFeedback
|
||||
|
@ -332,30 +327,30 @@ calItipEmailTransport.prototype = {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case Components.interfaces.calIItipItem.NONE: {
|
||||
case Ci.calIItipItem.NONE: {
|
||||
// we shouldn't get here, as we stoppped processing in this case
|
||||
// earlier in checkAndSend in calItipUtils.jsm
|
||||
cal.LOG("sendXpcomMail: Found NONE autoResponse type.");
|
||||
|
||||
// No response
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Unknown autoResponse type
|
||||
// Also of this case should have been taken care at the same place
|
||||
throw new Error("sendXpcomMail: " +
|
||||
"Unknown autoResponse type: " +
|
||||
aItem.autoResponse);
|
||||
aItipItem.autoResponse);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_createTempImipFile: function(compatMode, aToList, aSubject, aBody, aItem, aIdentity, aMessageId) {
|
||||
_createTempImipFile: function(aToList, aSubject, aBody, aItipItem, aIdentity, aMessageId) {
|
||||
try {
|
||||
let itemList = aItem.getItemList({});
|
||||
let serializer = Components.classes["@mozilla.org/calendar/ics-serializer;1"]
|
||||
.createInstance(Components.interfaces.calIIcsSerializer);
|
||||
let itemList = aItipItem.getItemList({});
|
||||
let serializer = Cc["@mozilla.org/calendar/ics-serializer;1"]
|
||||
.createInstance(Ci.calIIcsSerializer);
|
||||
serializer.addItems(itemList, itemList.length);
|
||||
let methodProp = cal.getIcsService().createIcalProperty("METHOD");
|
||||
methodProp.value = aItem.responseMethod;
|
||||
methodProp.value = aItipItem.responseMethod;
|
||||
serializer.addProperty(methodProp);
|
||||
let calText = serializer.serializeToString();
|
||||
let utf8CalText = ltn.invitation.encodeUTF8(calText);
|
||||
|
@ -364,55 +359,43 @@ calItipEmailTransport.prototype = {
|
|||
// it can cope with nested attachments,
|
||||
// like multipart/alternative with enclosed text/calendar and text/plain.
|
||||
let mailText = ltn.invitation.getHeaderSection(aMessageId, aIdentity, aToList, aSubject);
|
||||
switch (compatMode) {
|
||||
case 1:
|
||||
mailText += "Content-class: urn:content-classes:calendarmessage\r\n" +
|
||||
"Content-type: text/calendar; method=" + aItem.responseMethod + "; charset=UTF-8\r\n" +
|
||||
"Content-transfer-encoding: 8BIT\r\n" +
|
||||
"\r\n" +
|
||||
utf8CalText +
|
||||
"\r\n";
|
||||
break;
|
||||
default:
|
||||
mailText += "Content-type: multipart/mixed; boundary=\"Boundary_(ID_qyG4ZdjoAsiZ+Jo19dCbWQ)\"\r\n" +
|
||||
"\r\n\r\n" +
|
||||
"--Boundary_(ID_qyG4ZdjoAsiZ+Jo19dCbWQ)\r\n" +
|
||||
"Content-type: multipart/alternative;\r\n" +
|
||||
" boundary=\"Boundary_(ID_ryU4ZdJoASiZ+Jo21dCbwA)\"\r\n" +
|
||||
"\r\n\r\n" +
|
||||
"--Boundary_(ID_ryU4ZdJoASiZ+Jo21dCbwA)\r\n" +
|
||||
"Content-type: text/plain; charset=UTF-8\r\n" +
|
||||
"Content-transfer-encoding: 8BIT\r\n" +
|
||||
"\r\n" +
|
||||
ltn.invitation.encodeUTF8(aBody) +
|
||||
"\r\n\r\n\r\n" +
|
||||
"--Boundary_(ID_ryU4ZdJoASiZ+Jo21dCbwA)\r\n" +
|
||||
"Content-type: text/calendar; method=" + aItem.responseMethod + "; charset=UTF-8\r\n" +
|
||||
"Content-transfer-encoding: 8BIT\r\n" +
|
||||
"\r\n" +
|
||||
utf8CalText +
|
||||
"\r\n\r\n" +
|
||||
"--Boundary_(ID_ryU4ZdJoASiZ+Jo21dCbwA)--\r\n" +
|
||||
"\r\n" +
|
||||
"--Boundary_(ID_qyG4ZdjoAsiZ+Jo19dCbWQ)\r\n" +
|
||||
"Content-type: application/ics; name=invite.ics\r\n" +
|
||||
"Content-transfer-encoding: 8BIT\r\n" +
|
||||
"Content-disposition: attachment; filename=invite.ics\r\n" +
|
||||
"\r\n" +
|
||||
utf8CalText +
|
||||
"\r\n\r\n" +
|
||||
"--Boundary_(ID_qyG4ZdjoAsiZ+Jo19dCbWQ)--\r\n";
|
||||
break;
|
||||
}
|
||||
mailText += "Content-type: multipart/mixed; boundary=\"Boundary_(ID_qyG4ZdjoAsiZ+Jo19dCbWQ)\"\r\n" +
|
||||
"\r\n\r\n" +
|
||||
"--Boundary_(ID_qyG4ZdjoAsiZ+Jo19dCbWQ)\r\n" +
|
||||
"Content-type: multipart/alternative;\r\n" +
|
||||
" boundary=\"Boundary_(ID_ryU4ZdJoASiZ+Jo21dCbwA)\"\r\n" +
|
||||
"\r\n\r\n" +
|
||||
"--Boundary_(ID_ryU4ZdJoASiZ+Jo21dCbwA)\r\n" +
|
||||
"Content-type: text/plain; charset=UTF-8\r\n" +
|
||||
"Content-transfer-encoding: 8BIT\r\n" +
|
||||
"\r\n" +
|
||||
ltn.invitation.encodeUTF8(aBody) +
|
||||
"\r\n\r\n\r\n" +
|
||||
"--Boundary_(ID_ryU4ZdJoASiZ+Jo21dCbwA)\r\n" +
|
||||
"Content-type: text/calendar; method=" + aItipItem.responseMethod + "; charset=UTF-8\r\n" +
|
||||
"Content-transfer-encoding: 8BIT\r\n" +
|
||||
"\r\n" +
|
||||
utf8CalText +
|
||||
"\r\n\r\n" +
|
||||
"--Boundary_(ID_ryU4ZdJoASiZ+Jo21dCbwA)--\r\n" +
|
||||
"\r\n" +
|
||||
"--Boundary_(ID_qyG4ZdjoAsiZ+Jo19dCbWQ)\r\n" +
|
||||
"Content-type: application/ics; name=invite.ics\r\n" +
|
||||
"Content-transfer-encoding: 8BIT\r\n" +
|
||||
"Content-disposition: attachment; filename=invite.ics\r\n" +
|
||||
"\r\n" +
|
||||
utf8CalText +
|
||||
"\r\n\r\n" +
|
||||
"--Boundary_(ID_qyG4ZdjoAsiZ+Jo19dCbWQ)--\r\n";
|
||||
cal.LOG("mail text:\n" + mailText);
|
||||
|
||||
let tempFile = Services.dirsvc.get("TmpD", Components.interfaces.nsIFile);
|
||||
let tempFile = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
tempFile.append("itipTemp");
|
||||
tempFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE,
|
||||
tempFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE,
|
||||
parseInt("0600", 8));
|
||||
|
||||
let outputStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
let outputStream = Cc["@mozilla.org/network/file-output-stream;1"]
|
||||
.createInstance(Ci.nsIFileOutputStream);
|
||||
// Let's write the file - constants from file-utils.js
|
||||
const MODE_WRONLY = 0x02;
|
||||
const MODE_CREATE = 0x08;
|
||||
|
|
|
@ -57,12 +57,6 @@ pref("calendar.alarms.todoalarmunit", "minutes");
|
|||
pref("calendar.invitations.autorefresh.enabled", true);
|
||||
pref("calendar.invitations.autorefresh.timeout", 3);
|
||||
|
||||
// iTIP compatibility send mode
|
||||
// 0 -- Outlook 2003 and following with text/plain and application/ics (default)
|
||||
// 1 -- all Outlook, but no text/plain nor application/ics
|
||||
// We may extend the compat mode if necessary.
|
||||
pref("calendar.itip.compatSendMode", 0);
|
||||
|
||||
// whether "notify" is checked by default when creating new events/todos with attendees
|
||||
pref("calendar.itip.notify", true);
|
||||
|
||||
|
|
|
@ -141,7 +141,6 @@ imipBarProcessingFailed=Processing message failed. Status: %1$S.
|
|||
imipBarNotWritable=No writable calendars are configured for invitations, please check the calendar properties.
|
||||
imipSendMail.title=E-Mail Notification
|
||||
imipSendMail.text=Would you like to send out notification E-Mail now?
|
||||
imipSendMail.Outlook2000CompatMode.text=Support Outlook 2000 and Outlook 2002/XP
|
||||
imipNoIdentity=None
|
||||
imipNoCalendarAvailable=There are no writable calendars available.
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче