Fix cancellation messages for deleted attendee

* We weren't sending a proper ics file for the deleted attendee, and
  this caused Exchange to send a message to the wrong people (the
  referenced bug)
* Split out code that adds attendees to outgoing mail
* Changed the optional last argument to createMessageForX to be a specified
  attendee, i.e. the only addressee to be used for the message

Bug: 2548465
Change-Id: I629fcfaffe621408ea460d42c9c7c283929f7e79
diff --git a/src/com/android/exchange/adapter/CalendarSyncAdapter.java b/src/com/android/exchange/adapter/CalendarSyncAdapter.java
index f87ca4e..f418309 100644
--- a/src/com/android/exchange/adapter/CalendarSyncAdapter.java
+++ b/src/com/android/exchange/adapter/CalendarSyncAdapter.java
@@ -1699,10 +1699,9 @@
                             // Send a cancellation message to each of them
                             msg = CalendarUtilities.createMessageForEventId(mContext, eventId,
                                     Message.FLAG_OUTGOING_MEETING_CANCEL, clientId, mAccount,
-                                    false);
+                                    removedAttendee);
                             if (msg != null) {
                                 // Just send it to the removed attendee
-                                msg.mTo = removedAttendee;
                                 userLog("Queueing cancellation to removed attendee " + msg.mTo);
                                 mOutgoingMailList.add(msg);
                             }
diff --git a/src/com/android/exchange/utility/CalendarUtilities.java b/src/com/android/exchange/utility/CalendarUtilities.java
index 266ab69..049ca30 100644
--- a/src/com/android/exchange/utility/CalendarUtilities.java
+++ b/src/com/android/exchange/utility/CalendarUtilities.java
@@ -1213,6 +1213,51 @@
     }
 
     /**
+     * Add an attendee to the ics attachment and the to list of the Message being composed
+     * @param ics the ics attachment writer
+     * @param toList the list of addressees for this email
+     * @param attendeeName the name of the attendee
+     * @param attendeeEmail the email address of the attendee
+     * @param messageFlag the flag indicating the action to be indicated by the message
+     * @param account the sending account of the email
+     */
+    static private void addAttendeeToMessage(SimpleIcsWriter ics, ArrayList<Address> toList,
+            String attendeeName, String attendeeEmail, int messageFlag, Account account) {
+        if ((messageFlag & Message.FLAG_OUTGOING_MEETING_REQUEST_MASK) != 0) {
+            String icalTag = ICALENDAR_ATTENDEE_INVITE;
+            if ((messageFlag & Message.FLAG_OUTGOING_MEETING_CANCEL) != 0) {
+                icalTag = ICALENDAR_ATTENDEE_CANCEL;
+            }
+            if (attendeeName != null) {
+                icalTag += ";CN=" + SimpleIcsWriter.quoteParamValue(attendeeName);
+            }
+            ics.writeTag(icalTag, "MAILTO:" + attendeeEmail);
+            toList.add(attendeeName == null ? new Address(attendeeEmail) :
+                new Address(attendeeEmail, attendeeName));
+        } else if (attendeeEmail.equalsIgnoreCase(account.mEmailAddress)) {
+            String icalTag = null;
+            switch (messageFlag) {
+                case Message.FLAG_OUTGOING_MEETING_ACCEPT:
+                    icalTag = ICALENDAR_ATTENDEE_ACCEPT;
+                    break;
+                case Message.FLAG_OUTGOING_MEETING_DECLINE:
+                    icalTag = ICALENDAR_ATTENDEE_DECLINE;
+                    break;
+                case Message.FLAG_OUTGOING_MEETING_TENTATIVE:
+                    icalTag = ICALENDAR_ATTENDEE_TENTATIVE;
+                    break;
+            }
+            if (icalTag != null) {
+                if (attendeeName != null) {
+                    icalTag += ";CN="
+                            + SimpleIcsWriter.quoteParamValue(attendeeName);
+                }
+                ics.writeTag(icalTag, "MAILTO:" + attendeeEmail);
+            }
+        }
+    }
+
+    /**
      * Create a Message for an (Event) Entity
      * @param entity the Entity for the Event (as might be retrieved by CalendarProvider)
      * @param messageFlag the Message.FLAG_XXX constant indicating the type of email to be sent
@@ -1223,11 +1268,11 @@
     static public EmailContent.Message createMessageForEntity(Context context, Entity entity,
             int messageFlag, String uid, Account account) {
         return createMessageForEntity(context, entity, messageFlag, uid, account,
-                true /*requireAddressees*/);
+                null /*specifiedAttendee*/);
     }
 
     static public EmailContent.Message createMessageForEntity(Context context, Entity entity,
-            int messageFlag, String uid, Account account, boolean requireAddressees) {
+            int messageFlag, String uid, Account account, String specifiedAttendee) {
         ContentValues entityValues = entity.getEntityValues();
         ArrayList<NamedContentValues> subValues = entity.getSubValues();
         boolean isException = entityValues.containsKey(Events.ORIGINAL_EVENT);
@@ -1437,45 +1482,26 @@
                         }
                         String attendeeEmail = ncvValues.getAsString(Attendees.ATTENDEE_EMAIL);
                         String attendeeName = ncvValues.getAsString(Attendees.ATTENDEE_NAME);
+
                         // This shouldn't be possible, but allow for it
                         if (attendeeEmail == null) continue;
-
-                        if ((messageFlag & Message.FLAG_OUTGOING_MEETING_REQUEST_MASK) != 0) {
-                            String icalTag = ICALENDAR_ATTENDEE_INVITE;
-                            if ((messageFlag & Message.FLAG_OUTGOING_MEETING_CANCEL) != 0) {
-                                icalTag = ICALENDAR_ATTENDEE_CANCEL;
-                            }
-                            if (attendeeName != null) {
-                                icalTag += ";CN=" + SimpleIcsWriter.quoteParamValue(attendeeName);
-                            }
-                            ics.writeTag(icalTag, "MAILTO:" + attendeeEmail);
-                            toList.add(attendeeName == null ? new Address(attendeeEmail) :
-                                new Address(attendeeEmail, attendeeName));
-                        } else if (attendeeEmail.equalsIgnoreCase(account.mEmailAddress)) {
-                            String icalTag = null;
-                            switch (messageFlag) {
-                                case Message.FLAG_OUTGOING_MEETING_ACCEPT:
-                                    icalTag = ICALENDAR_ATTENDEE_ACCEPT;
-                                    break;
-                                case Message.FLAG_OUTGOING_MEETING_DECLINE:
-                                    icalTag = ICALENDAR_ATTENDEE_DECLINE;
-                                    break;
-                                case Message.FLAG_OUTGOING_MEETING_TENTATIVE:
-                                    icalTag = ICALENDAR_ATTENDEE_TENTATIVE;
-                                    break;
-                            }
-                            if (icalTag != null) {
-                                if (attendeeName != null) {
-                                    icalTag += ";CN="
-                                            + SimpleIcsWriter.quoteParamValue(attendeeName);
-                                }
-                                ics.writeTag(icalTag, "MAILTO:" + attendeeEmail);
-                            }
+                        // If we only want to send to the specifiedAttendee, eliminate others here
+                        if ((specifiedAttendee != null) &&
+                                !attendeeEmail.equalsIgnoreCase(specifiedAttendee)) {
+                            continue;
                         }
+
+                        addAttendeeToMessage(ics, toList, attendeeName, attendeeEmail, messageFlag,
+                                account);
                     }
                 }
             }
 
+            // Manually add the specifiedAttendee if he wasn't added in the Attendees loop
+            if (toList.isEmpty() && (specifiedAttendee != null)) {
+                addAttendeeToMessage(ics, toList, null, specifiedAttendee, messageFlag, account);
+            }
+
             // Create the organizer tag for ical
             if (organizerEmail != null) {
                 String icalTag = "ORGANIZER";
@@ -1491,8 +1517,8 @@
                 }
             }
 
-            // If we have no "to" list and addressees are required (the default), we're done
-            if (toList.isEmpty() && requireAddressees) return null;
+            // If we have no "to" list, we're done
+            if (toList.isEmpty()) return null;
 
             // Write out the "to" list
             Address[] toArray = new Address[toList.size()];
@@ -1547,11 +1573,11 @@
     static public EmailContent.Message createMessageForEventId(Context context, long eventId,
             int messageFlag, String uid, Account account) throws RemoteException {
         return createMessageForEventId(context, eventId, messageFlag, uid, account,
-                true /*requireAddressees*/);
+                null /*specifiedAttendee*/);
     }
 
     static public EmailContent.Message createMessageForEventId(Context context, long eventId,
-            int messageFlag, String uid, Account account, boolean requireAddressees)
+            int messageFlag, String uid, Account account, String specifiedAttendee)
             throws RemoteException {
         ContentResolver cr = context.getContentResolver();
         EntityIterator eventIterator =
@@ -1563,7 +1589,7 @@
             while (eventIterator.hasNext()) {
                 Entity entity = eventIterator.next();
                 return createMessageForEntity(context, entity, messageFlag, uid, account,
-                        requireAddressees);
+                        specifiedAttendee);
             }
         } finally {
             eventIterator.close();