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:
makemyday@gmx-topmail.de 2018-03-11 13:59:42 +01:00
Родитель 03cd32f4cf
Коммит f65c0a39f9
8 изменённых файлов: 216 добавлений и 169 удалений

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

@ -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.