Bug 463402 - Remove E-Mail notification dialogs - Part 1: processing;r=philipp
authormakemyday@gmx-topmail.de
Sun, 11 Mar 2018 13:59:42 +0100
changeset 31275 044240bd35e00b5c202b97d37ba532ef5f23d309
parent 31274 3cc1812a10b418c8aac85feb001e332cb56892c9
child 31276 5ae749bd1ed8dbb33e1995c60fdc13152c066752
push id383
push userclokep@gmail.com
push dateMon, 07 May 2018 21:52:48 +0000
reviewersphilipp
bugs463402
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
calendar/base/content/calendar-item-editing.js
calendar/base/modules/calItipUtils.jsm
calendar/base/public/calITransactionManager.idl
calendar/base/src/calItemModule.manifest
calendar/base/src/calTransactionManager.js
calendar/itip/calItipEmailTransport.js
calendar/lightning/content/lightning.js
calendar/locales/en-US/chrome/lightning/lightning.properties
--- a/calendar/base/content/calendar-item-editing.js
+++ b/calendar/base/content/calendar-item-editing.js
@@ -222,24 +222,24 @@ function setDefaultItemValues(aItem, aCa
  * @param startDate     (optional) The event's start date.
  * @param endDate       (optional) The event's end date.
  * @param summary       (optional) The event's title.
  * @param event         (optional) A template event to show in the dialog
  * @param aForceAllDay  (optional) Make sure the event shown in the dialog is an
  *                                   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);
         }
     };
 
     if (event) {
         if (!event.isMutable) {
             event = event.clone();
         }
         // If the event should be created from a template, then make sure to
@@ -277,24 +277,24 @@ function createEventWithDialog(calendar,
  *
  * @param calendar      (optional) The calendar to create the task in
  * @param dueDate       (optional) The task's due date.
  * @param summary       (optional) The task's title.
  * @param todo          (optional) A template task to show in the dialog.
  * @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);
         }
     };
 
     if (todo) {
         // If the todo should be created from a template, then make sure to
         // remove the id so that the item obtains a new id when doing the
         // transaction
         if (todo.id) {
@@ -343,18 +343,18 @@ function createTodoWithDialog(calendar, 
 function modifyEventWithDialog(aItem, job=null, aPromptOccurrence, initialDate=null, aCounterProposal) {
     let dlg = cal.item.findWindow(aItem);
     if (dlg) {
         dlg.focus();
         disposeJob(job);
         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;
     let response;
     if (aPromptOccurrence !== false) {
         [item, , response] = promptOccurrenceModification(aItem, true, "edit");
     }
 
@@ -624,28 +624,31 @@ function getTransactionMgr() {
  * manager. Also updates the undo/redo menu.
  *
  * @see                 calITransactionManager
  * @param aAction       The action to do.
  * @param aItem         The new item to add/modify/delete
  * @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);
 
     // Now use the transaction manager to execute the action
     getTransactionMgr().createAndCommitTxn(aAction,
                                            aItem,
                                            aCalendar,
                                            aOldItem,
-                                           aListener ? aListener : null);
+                                           aListener ? aListener : null,
+                                           aExtResponse);
     updateUndoRedoMenu();
 }
 
 /**
  * Undo the last operation done through the transaction manager.
  */
 function undo() {
     if (canUndo()) {
@@ -700,25 +703,37 @@ function canRedo() {
 /**
  * Update the undo and redo commands.
  */
 function updateUndoRedoMenu() {
     goUpdateCommand("cmd_undo");
     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;
             if (cal.isInvitation(oldItem)) {
                 // Check for the invited attendee first, this is more important
                 attendee = cal.getInvitedAttendee(oldItem);
             } else if (oldItem.organizer && oldItem.getAttendees({}).length) {
                 // Now check the organizer. This should be done last.
@@ -727,25 +742,25 @@ function setContextPartstat(value, scope
                     attendee = oldItem.organizer;
                 }
             }
 
             if (attendee) {
                 let newItem = oldItem.clone();
                 let newAttendee = attendee.clone();
 
-                newAttendee.participationStatus = value;
+                newAttendee.participationStatus = aPartStat;
                 if (newAttendee.isOrganizer) {
                     newItem.organizer = newAttendee;
                 } else {
                     newItem.removeAttendee(attendee);
                     newItem.addAttendee(newAttendee);
                 }
 
-                doTransaction("modify", newItem, newItem.calendar, oldItem, null);
+                doTransaction("modify", newItem, newItem.calendar, oldItem, null, aExtResponse);
             }
         }
     } catch (e) {
         cal.ERROR("Error setting partstat: " + e);
     } finally {
         endBatchTransaction();
     }
 }
--- a/calendar/base/modules/calItipUtils.jsm
+++ b/calendar/base/modules/calItipUtils.jsm
@@ -629,18 +629,29 @@ cal.itip = {
         }
     },
 
     /**
      * Scope: iTIP message sender
      *
      * 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).
         if (aOriginalItem && aItem.recurrenceInfo) {
             if (aOriginalItem.recurrenceId && !aItem.recurrenceId) {
                 // sanity check: assure aItem doesn't refer to the master
                 aItem = aItem.recurrenceInfo.getOccurrenceFor(aOriginalItem.recurrenceId);
                 cal.ASSERT(aItem, "unexpected!");
@@ -674,18 +685,40 @@ cal.itip = {
                         // xxx todo: support multiple
                         aItem = aOriginalItem.recurrenceInfo.getOccurrenceFor(exdates[0].date);
                         aOriginalItem = null;
                         aOpType = Components.interfaces.calIOperationListener.DELETE;
                     }
                 }
             }
         }
-
-        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
             /* We check if the attendee id matches one of of the
              * userAddresses. If they aren't equal, it means that
              * someone is accepting invitations on behalf of an other user. */
             if (aItem.calendar.aclEntry) {
                 let userAddresses = aItem.calendar.aclEntry.getUserAddresses({});
@@ -949,20 +982,20 @@ cal.itip = {
         itipItem.targetCalendar = ("targetCalendar" in aProps) ? aProps.targetCalendar : aItipItem.targetCalendar;
 
         return itipItem;
     },
 
     /**
      * 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") {
             return sendMessage(aItem, aMethod, aRecipientsList, aAutoResponse);
         }
         return false;
     }
 };
@@ -1137,27 +1170,25 @@ function sendMessage(aItem, aMethod, aRe
 
     let transport = aItem.calendar.getProperty("itip.transport");
     if (!transport) { // can only send if there's a transport for the calendar
         return false;
     }
     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);
     };
 
     // split up transport, if attendee undisclosure is requested
     // and this is a message send by the organizer
     if (aItem.getProperty("X-MOZ-SEND-INVITATIONS-UNDISCLOSED") == "TRUE" &&
@@ -1184,26 +1215,32 @@ function sendMessage(aItem, aMethod, aRe
 
 /** local to this module file
  * An operation listener that is used on calendar operations which checks and sends further iTIP
  * messages based on the calendar action.
  *
  * @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,
                                                  aStatus,
                                                  aOperationType,
                                                  aId,
                                                  aDetail);
         }
@@ -1402,37 +1439,42 @@ ItipItemFinder.prototype = {
                             }
 
                             switch (method) {
                                 case "REFRESH": { // xxx todo test
                                     let attendees = itipItemItem.getAttendees({});
                                     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) {
                                                     item = item.clone();
                                                     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);
                                     }
                                     break;
                                 }
                                 case "PUBLISH":
                                     cal.ASSERT(itipItemItem.getAttendees({}).length == 0,
                                                "invalid number of attendees in PUBLISH!");
                                     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";
                                         operations.push(action);
                                     }
                                     break;
                                 case "REQUEST": {
                                     let newItem = updateItem(item, itipItemItem);
@@ -1452,47 +1494,47 @@ ItipItemFinder.prototype = {
                                         // are viewing the current representation of the item, show the
                                         // accept/decline buttons. This means newer events will show the
                                         // "Update" button and older events will show the "already
                                         // processed" text.
                                         if (foundAttendee.participationStatus == "NEEDS-ACTION" &&
                                             (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();
                                                 if (partStat) {
                                                     foundAttendee.participationStatus = partStat;
                                                 }
                                                 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) {
                                             addScheduleAgentClient(newItem, item.calendar);
 
                                             let isMinorUpdate = cal.itip.getSequence(newItem) ==
                                                                 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";
                                                 }
                                                 newItem.removeAttendee(att);
                                                 att = att.clone();
                                                 att.participationStatus = partStat;
                                                 newItem.addAttendee(att);
                                                 return newItem.calendar.modifyItem(
-                                                    newItem, item, new ItipOpListener(opListener, item));
+                                                    newItem, item, new ItipOpListener(opListener, item, extResponse));
                                             });
                                         }
                                     }
                                     break;
                                 }
                                 case "DECLINECOUNTER":
                                     // nothing to do right now, but once countering is implemented,
                                     // we probably need some action here to remove the proposal from
@@ -1541,26 +1583,26 @@ ItipItemFinder.prototype = {
                                         let newPS = itipItemItem.getAttendeeById(replyer.id)
                                                                 .participationStatus;
                                         replyer.participationStatus = newPS;
                                         newItem.addAttendee(replyer);
 
                                         // 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
                                             // opListener (defined in imip-bar.js)
                                             // TODO: move that from imip-bar.js to here
                                             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);
                                     }
                                     break;
                                 }
                             }
                         }
@@ -1577,25 +1619,31 @@ ItipItemFinder.prototype = {
                                     let newItem = modifiedItems[item.id];
                                     if (!newItem) {
                                         newItem = item.clone();
                                         modifiedItems[item.id] = newItem;
 
                                         // 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)
+                                );
                             }
                         }
                     }
                     break;
                 }
                 default:
                     rc = Components.results.NS_ERROR_NOT_IMPLEMENTED;
                     break;
@@ -1607,17 +1655,17 @@ ItipItemFinder.prototype = {
             // It will likely be the composite calendar, so we should update
             // if an item was added or removed
             this._observeChanges(this.mItipItem.targetCalendar);
 
             for (let itipItemItem of this.mItipItem.getItemList({})) {
                 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;
                             addScheduleAgentClient(newItem, this.mItipItem.targetCalendar);
                             if (partStat) {
                                 if (partStat != "DECLINED") {
                                     cal.alarms.setDefaultValues(newItem);
                                 }
@@ -1636,17 +1684,17 @@ ItipItemFinder.prototype = {
                                     return null;
                                 }
                             } else {
                                 cal.ASSERT(itipItemItem.getAttendees({}).length == 0,
                                            "invalid number of attendees in PUBLISH!");
                             }
                             return newItem.calendar.addItem(newItem,
                                                             method == "REQUEST"
-                                                            ? new ItipOpListener(opListener, null)
+                                                            ? new ItipOpListener(opListener, null, extResponse)
                                                             : opListener);
                         };
                         operations.push(action);
                         break;
                     }
                     case "CANCEL": // has already been processed
                     case "REPLY": // item has been previously removed from the calendar
                     case "COUNTER": // the item has been previously removed form the calendar
@@ -1656,20 +1704,20 @@ ItipItemFinder.prototype = {
                         break;
                 }
             }
         }
 
         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);
                     }
                 }
             };
             actionFunc.method = actionMethod;
         }
 
--- a/calendar/base/public/calITransactionManager.idl
+++ b/calendar/base/public/calITransactionManager.idl
@@ -9,41 +9,45 @@ interface calICalendar;
 interface calIItemBase;
 interface calIOperationListener;
 
 /**
  * calITransactionManager is a service designed to handle nsITransactions
  * 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.
      * @param aCalendar     The Calendar to execute the transaction on
      * @param aItem         The changed item for this transaction. This item 
      *                      should be immutable
      * @param aOldItem      The Item in its original form. Only needed for 
      *                      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
      * to be performed, but that, for the purposes of undo and redo, they should
      * all be regarded as a single transaction. See also
      * nsITransactionManager::beginBatch
      */
     void beginBatch();
--- a/calendar/base/src/calItemModule.manifest
+++ b/calendar/base/src/calItemModule.manifest
@@ -60,16 +60,16 @@ contract @mozilla.org/calendar/relation;
 
 component {2547331f-34c0-4a4b-b93c-b503538ba6d6} calItemModule.js
 contract @mozilla.org/calendar/startup-service;1 {2547331f-34c0-4a4b-b93c-b503538ba6d6}
 category profile-after-change calendar-startup-service @mozilla.org/calendar/startup-service;1
 
 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}
 
 component {6877bbdd-f336-46f5-98ce-fe86d0285cc1} calItemModule.js
 contract @mozilla.org/calendar/weekinfo-service;1 {6877bbdd-f336-46f5-98ce-fe86d0285cc1}
--- a/calendar/base/src/calTransactionManager.js
+++ b/calendar/base/src/calTransactionManager.js
@@ -10,37 +10,38 @@ function calTransactionManager() {
     this.wrappedJSObject = this;
     if (!this.transactionManager) {
         this.transactionManager =
             Components.classes["@mozilla.org/transactionmanager;1"]
                       .createInstance(Components.interfaces.nsITransactionManager);
     }
 }
 
-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 = {
 
     classID: calTransactionManagerClassID,
     QueryInterface: XPCOMUtils.generateQI(calTransactionManagerInterfaces),
     classInfo: XPCOMUtils.generateCI({
         classID: calTransactionManagerClassID,
         classDescription: "Calendar Transaction Manager",
         contractID: "mozilla.org/calendar/transactionmanager;1",
         interfaces: calTransactionManagerInterfaces,
         flags: Components.interfaces.nsIClassInfo.SINGLETON
     }),
 
     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);
     },
 
     beginBatch: function() {
         this.transactionManager.beginBatch(null);
     },
 
     endBatch: function() {
@@ -72,23 +73,24 @@ calTransactionManager.prototype = {
     },
 
     canRedo: function() {
         return this.transactionManager.numberOfRedoItems > 0 &&
                this.checkWritable(this.transactionManager.peekRedoStack());
     }
 };
 
-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}");
 var calTransactionInterfaces = [
     Components.interfaces.nsITransaction,
     Components.interfaces.calIOperationListener
 ];
 calTransaction.prototype = {
@@ -103,22 +105,24 @@ calTransaction.prototype = {
 
     mAction: null,
     mCalendar: null,
     mItem: null,
     mOldItem: null,
     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) {
                 if (this.mIsDoTransaction) {
                     this.mItem = aDetail;
                 } else {
                     this.mOldItem = aDetail;
                 }
--- a/calendar/itip/calItipEmailTransport.js
+++ b/calendar/itip/calItipEmailTransport.js
@@ -12,17 +12,17 @@ ChromeUtils.import("resource://calendar/
 /**
  * Constructor of calItipEmailTransport object
  */
 function calItipEmailTransport() {
     this.wrappedJSObject = this;
     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),
     classInfo: XPCOMUtils.generateCI({
         classID: calItipEmailTransportClassID,
         contractID: "@mozilla.org/calendar/itip-transport;1?type=email",
         classDescription: "Calendar iTIP Email Transport",
         interfaces: calItipEmailTransportInterfaces,
@@ -50,17 +50,17 @@ calItipEmailTransport.prototype = {
             let items = this._prepareItems(aItipItem);
             if (items === false) {
                 return false;
             }
 
             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;
         }
     },
 
     _prepareItems: function(aItipItem) {
         let item = aItipItem.getItemList({})[0];
 
         // Get ourselves some default text - when we handle organizer properly
         // We'll need a way to configure the Common Name attribute and we should
@@ -193,106 +193,101 @@ calItipEmailTransport.prototype = {
             this.mDefaultIdentity = this.mDefaultAccount.defaultIdentity;
 
             if (!this.mDefaultIdentity) {
                 // If there isn't a default identity (i.e Local Folders is your
                 // default identity, then go ahead and use the first available
                 // 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.
                     this.mHasXpcomMail = false;
                     cal.LOG("initEmailService: No XPCOM Mail available: " + e);
                 }
             }
         } catch (ex) {
             // Then we must resort to operating system specific means
             this.mHasXpcomMail = false;
         }
     },
 
-    _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:
             identity = this.mDefaultIdentity;
             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) {
                     let email = cal.getAttendeeEmail(aVal, true);
                     if (!email.length) {
                         cal.LOG("Invalid recipient for email transport: " + aVal.toString());
                     }
                     return email;
                 };
                 let toMap = aToList.map(cbEmail).filter(value => value.length);
                 if (toMap.length < aToList.length) {
                     // at least one invalid recipient, so we skip sending for this message
                     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);
                     composeFields.from = (cal.validateRecipientList(mailfrom) == mailfrom ? mailfrom : identity.email);
                     composeFields.replyTo = identity.replyTo;
                     composeFields.organization = identity.organization;
                     composeFields.messageId = messageId;
                     let validRecipients;
@@ -309,115 +304,103 @@ calItipEmailTransport.prototype = {
                             composeFields.bcc = validRecipients;
                         }
                     }
 
                     // xxx todo: add send/progress UI, maybe recycle
                     //           "@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
                                             "");   // password
                     return true;
                 }
                 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);
 
             // Home-grown mail composition; I'd love to use nsIMimeEmitter, but it's not clear to me whether
             // 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;
             const MODE_TRUNCATE = 0x20;
             outputStream.init(tempFile,
                               MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE,
                               parseInt("0600", 8),
                               0);
--- a/calendar/lightning/content/lightning.js
+++ b/calendar/lightning/content/lightning.js
@@ -52,22 +52,16 @@ pref("calendar.alarms.eventalarmunit", "
 pref("calendar.alarms.onfortodos", 0);
 pref("calendar.alarms.todoalarmlen", 15);
 pref("calendar.alarms.todoalarmunit", "minutes");
 
 // open invitations autorefresh settings
 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);
 
 // whether the organizer propagates replies of attendees to all attendees
 pref("calendar.itip.notify-replies", false);
 
 // whether email invitation updates are send out to all attendees if (only) adding a new attendee
 pref("calendar.itip.updateInvitationForNewAttendeesOnly", false);
--- a/calendar/locales/en-US/chrome/lightning/lightning.properties
+++ b/calendar/locales/en-US/chrome/lightning/lightning.properties
@@ -136,17 +136,16 @@ imipBarReplyToNotExistingItem=This messa
 # LOCALIZATION_NOTE(imipBarReplyToRecentlyRemovedItem):
 # %1$S - datetime of deletion
 imipBarReplyToRecentlyRemovedItem=This message contains a reply referring to an event that was removed from your calendar at %1$S.
 imipBarUnsupportedText=This message contains an event that this version of Lightning cannot process.
 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.
 
 itipReplySubject=Event Invitation Reply: %1$S
 itipReplyBodyAccept=%1$S has accepted your event invitation.
 itipReplyBodyDecline=%1$S has declined your event invitation.
 itipReplySubjectAccept=Event Invitation Reply (Accepted): %1$S
 itipReplySubjectDecline=Event Invitation Reply (Declined): %1$S