Map: Fix map multi recipient email issue

Use case:
1. Push an email from carkit to different email addresses
   in to and cc fields.
2. Check sent folder in email app

Observed result:
Two separate emails are sent for to and cc email addresses.

Fix:
Parse CC and BCC emails from message body, later create list of
recipients based on parsed list  and send single email with
all recipients info.

CRs-Fixed: 2388785
Change-Id: Ia57a10ac7f4b6b9234e9696b15e0c3b5ff0ccdf3
diff --git a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java
index a4873e0..0e3e56f 100644
--- a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java
+++ b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapContentObserverEmail.java
@@ -847,13 +847,17 @@
         if (D) Log.d(TAG, "pushMessage emailBaseUri: "+emailBaseUri);
         ArrayList<BluetoothMapbMessage.VCard> recipientList = msg.getRecipients();
         ArrayList<BluetoothMapbMessage.VCard> originatorList = msg.getOriginators();
+        ArrayList<String> emailsTo = msg.getmRecipientTo();
+        ArrayList<String> emailsCc = msg.getmRecipientCc();
+        ArrayList<String> emailsBcc = msg.getmRecipientBCc();
+        int max_env_level = 3; // The maximum level of encapsulation shall be three
         int transparent = (ap.getTransparent() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) ?
                 0 : ap.getTransparent();
         int retry = ap.getRetry();
         int charset = ap.getCharset();
         long handle = -1;
         long folderId = -1;
-        if (recipientList == null) {
+        if (recipientList == null || recipientList.size() == 0) {
             if (D) Log.d(TAG, "empty recipient list");
             return -1;
         }
@@ -877,92 +881,127 @@
                     Log.v(TAG, "part " + i + ":" + messages[i]);
                 }
             }
-            String toAddress[] = null;
+            StringBuilder addressCc = new StringBuilder();
+            StringBuilder addressBcc = new StringBuilder();
+            StringBuilder addressTo = new StringBuilder();
+            if (D) Log.v(TAG," pushMessage recipientList size:" + recipientList.size());
             for (BluetoothMapbMessage.VCard recipient : recipientList) {
-                if(recipient.getEnvLevel() == 0) // Only send the message to the top level recipient
-                    toAddress = ((BluetoothMapbMessage.VCard)recipient).getEmailAddresses();
-                Uri uriInsert = BluetoothMapEmailContract
-                        .buildEmailMessageUri(BluetoothMapEmailContract.EMAIL_AUTHORITY);
-                if (D) Log.d(TAG, "pushMessage - uriInsert= " + uriInsert.toString() +
-                        ", intoFolder id=" + folderElement.getFolderId());
-                synchronized(getMsgListMsg()) {
-                    // Now insert the empty message into folder
-                    ContentValues values = new ContentValues();
-                    Time timeObj = new Time();
-                    timeObj.setToNow();
-                    folderId = folderElement.getFolderId();
-                    values.put(BluetoothMapEmailContract.ExtEmailMessageColumns.MAILBOX_KEY,
-                            folderId);
-                    if(((BluetoothMapbMessageExtEmail)msg).getSubject() != null) {
-                        values.put(BluetoothMapContract.MessageColumns.SUBJECT,
-                                ((BluetoothMapbMessageExtEmail)msg).getSubject());
-                    } else {
-                        values.put(BluetoothMapContract.MessageColumns.SUBJECT, "");
+                if (recipient.getEnvLevel() < max_env_level) {
+                    String address[] = ((BluetoothMapbMessage.VCard)recipient).getEmailAddresses();
+                    for (String  s : address) {
+                        if (emailsTo.contains(s)) {
+                            addressTo.append(s);
+                            addressTo.append(";");
+                        } else if (emailsCc.contains(s)) {
+                            addressCc.append(s);
+                            addressCc.append(";");
+                        } else if (emailsBcc.contains(s)) {
+                            addressBcc.append(s);
+                            addressBcc.append(";");
+                        } else {
+                            if (D) Log.d(TAG, "Ignoring extra address < " + s + " >");
+                        }
                     }
-                    values.put("syncServerTimeStamp", 0);
-                    values.put("timeStamp", timeObj.toMillis(false));
-                    values.put("flagLoaded", "1");
-                    values.put("flagFavorite", "0");
-                    values.put("flagAttachment", "0");
-                    if(folderElement.getName().equalsIgnoreCase(BluetoothMapContract
-                        .FOLDER_NAME_DRAFT) || folderElement.getName()
-                            .equalsIgnoreCase(BluetoothMapEmailContract.FOLDER_NAME_DRAFTS)) {
-                        values.put("flags", "1179648");
-                    } else
-                        values.put("flags", "0");
-                    String splitStr[] = emailBaseUri.split("/");
-                    for (String str: splitStr)
-                        Log.d(TAG,"seg for mBaseUri: "+ str);
-                    if (mAccount != null) {
-                        values.put("accountKey", mAccount.getAccountId());
-                        values.put("displayName", mAccount.getDisplayName());
-                        values.put("fromList", mAccount.getEmailAddress());
-                    }
-                    values.put("mailboxKey", folderId);
-                    StringBuilder address = new StringBuilder();
-                    for (String  s : toAddress) {
-                        address.append(s);
-                        address.append(";");
-                    }
-                    values.put("toList", address.toString().trim());
-                    values.put("flagRead", 0);
-                    Uri uriNew = mProviderClient.insert(uriInsert, values);
-                    if (D) Log.d(TAG, "pushMessage - uriNew= " + uriNew.toString());
-                    handle =  Long.parseLong(uriNew.getLastPathSegment());
-                    if (V) {
-                        Log.v(TAG, " NEW HANDLE " + handle);
-                    }
-                    if(handle == -1) {
-                       Log.v(TAG, " Inavlid Handle ");
-                       return -1;
-                    }
-                    //Insert msgBody in DB Provider BODY TABLE
-                    ContentValues valuesBody = new ContentValues();
-                    valuesBody.put("messageKey", String.valueOf(handle));
-                    valuesBody.put("textContent", msgBody);
-                    Uri uriMsgBdyInsert = BluetoothMapEmailContract
-                            .buildEmailMessageBodyUri(BluetoothMapEmailContract.EMAIL_AUTHORITY);
-                    Log.d(TAG, "pushMessage - uriMsgBdyInsert = " + uriMsgBdyInsert.toString());
-                    mProviderClient.insert(uriMsgBdyInsert, valuesBody);
-                    // Extract the data for the inserted message, and store in local mirror, to
-                    // avoid sending a NewMessage Event.
-                    //TODO: We need to add the new 1.1 parameter as well:-) e.g. read
-                    Msg newMsg = new Msg(handle, folderId, 1); // TODO: Create define for read-state
-                    newMsg.transparent = (transparent == 1) ? true : false;
-                    newMsg.localInitiatedSend = true;
-                    if ( folderId == folderElement.getFolderByName(
-                        BluetoothMapContract.FOLDER_NAME_OUTBOX).getFolderId() ) {
-                        //Trigger Email App to send the message over network.
-                        Intent emailIn = new Intent();
-                        long accountId = mAccount.getAccountId();
-                        if(V) Log.d(TAG, "sendIntent SEND: " + handle + "accounId: " +accountId);
-                        emailIn.setAction(BluetoothMapEmailContract.ACTION_SEND_PENDING_MAIL);
-                        emailIn.putExtra(BluetoothMapEmailContract.EXTRA_ACCOUNT, accountId);
-                        mContext.sendBroadcast(emailIn);
-                    }
-                    getMsgListMsg().put(handle, newMsg);
                 }
             }
+            // Extra check to format email list, it's should not happen
+            if (addressTo.length() == 0 && addressCc.length() == 0 && addressBcc.length() == 0) {
+                if (D) Log.v(TAG, "Parse from  recipientList");
+                for (BluetoothMapbMessage.VCard recipient : recipientList) {
+                    if (recipient.getEnvLevel() < max_env_level) {
+                        String address[] = ((BluetoothMapbMessage.VCard)recipient)
+                                .getEmailAddresses();
+                        for (String  s : address) {
+                            addressTo.append(s);
+                            addressTo.append(";");
+                        }
+                    }
+                }
+            }
+            Uri uriInsert = BluetoothMapEmailContract
+                    .buildEmailMessageUri(BluetoothMapEmailContract.EMAIL_AUTHORITY);
+            if (D) Log.d(TAG, "pushMessage - uriInsert= " + uriInsert.toString() +
+                     ", intoFolder id=" + folderElement.getFolderId());
+            synchronized(getMsgListMsg()) {
+                // Now insert the empty message into folder
+                ContentValues values = new ContentValues();
+                Time timeObj = new Time();
+                timeObj.setToNow();
+                folderId = folderElement.getFolderId();
+                values.put(BluetoothMapEmailContract.ExtEmailMessageColumns.MAILBOX_KEY,
+                        folderId);
+                if(((BluetoothMapbMessageExtEmail)msg).getSubject() != null) {
+                    values.put(BluetoothMapContract.MessageColumns.SUBJECT,
+                            ((BluetoothMapbMessageExtEmail)msg).getSubject());
+                } else {
+                    values.put(BluetoothMapContract.MessageColumns.SUBJECT, "");
+                }
+                values.put("syncServerTimeStamp", 0);
+                values.put("timeStamp", timeObj.toMillis(false));
+                values.put("flagLoaded", "1");
+                values.put("flagFavorite", "0");
+                values.put("flagAttachment", "0");
+                if(folderElement.getName().equalsIgnoreCase(BluetoothMapContract
+                    .FOLDER_NAME_DRAFT) || folderElement.getName()
+                        .equalsIgnoreCase(BluetoothMapEmailContract.FOLDER_NAME_DRAFTS)) {
+                    values.put("flags", "1179648");
+                } else
+                    values.put("flags", "0");
+                String splitStr[] = emailBaseUri.split("/");
+                for (String str: splitStr)
+                    Log.d(TAG,"seg for mBaseUri: "+ str);
+                if (mAccount != null) {
+                    values.put("accountKey", mAccount.getAccountId());
+                    values.put("displayName", mAccount.getDisplayName());
+                    values.put("fromList", mAccount.getEmailAddress());
+                }
+                values.put("mailboxKey", folderId);
+                if (addressTo.length() != 0) {
+                    values.put("toList", addressTo.toString().trim());
+                } if (addressCc.length() != 0) {
+                    values.put("ccList", addressCc.toString().trim());
+                } if (addressBcc.length() != 0) {
+                    values.put("bccList", addressBcc.toString().trim());
+                }
+                if (D) Log.d(TAG, " toList :" + addressTo + "\n ccList :" + addressCc +
+                    "\n bccList:" + addressBcc);
+                values.put("flagRead", 0);
+                Uri uriNew = mProviderClient.insert(uriInsert, values);
+                if (D) Log.d(TAG, "pushMessage - uriNew= " + uriNew.toString());
+                handle =  Long.parseLong(uriNew.getLastPathSegment());
+                if (V) {
+                    Log.v(TAG, " NEW HANDLE " + handle);
+                }
+                if(handle == -1) {
+                   Log.v(TAG, " Inavlid Handle ");
+                   return -1;
+                }
+                //Insert msgBody in DB Provider BODY TABLE
+                ContentValues valuesBody = new ContentValues();
+                valuesBody.put("messageKey", String.valueOf(handle));
+                valuesBody.put("textContent", msgBody);
+                Uri uriMsgBdyInsert = BluetoothMapEmailContract
+                        .buildEmailMessageBodyUri(BluetoothMapEmailContract.EMAIL_AUTHORITY);
+                Log.d(TAG, "pushMessage - uriMsgBdyInsert = " + uriMsgBdyInsert.toString());
+                mProviderClient.insert(uriMsgBdyInsert, valuesBody);
+                // Extract the data for the inserted message, and store in local mirror, to
+                // avoid sending a NewMessage Event.
+                //TODO: We need to add the new 1.1 parameter as well:-) e.g. read
+                Msg newMsg = new Msg(handle, folderId, 1); // TODO: Create define for read-state
+                newMsg.transparent = (transparent == 1) ? true : false;
+                newMsg.localInitiatedSend = true;
+                if ( folderId == folderElement.getFolderByName(
+                   BluetoothMapContract.FOLDER_NAME_OUTBOX).getFolderId() ) {
+                   //Trigger Email App to send the message over network.
+                   Intent emailIn = new Intent();
+                   long accountId = mAccount.getAccountId();
+                   if(V) Log.d(TAG, "sendIntent SEND: " + handle + "accounId: " +accountId);
+                   emailIn.setAction(BluetoothMapEmailContract.ACTION_SEND_PENDING_MAIL);
+                   emailIn.putExtra(BluetoothMapEmailContract.EXTRA_ACCOUNT, accountId);
+                   mContext.sendBroadcast(emailIn);
+                 }
+                 getMsgListMsg().put(handle, newMsg);
+            }
         }
         // If multiple recipients return handle of last
         return handle;
diff --git a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapbMessageExtEmail.java b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapbMessageExtEmail.java
index dbf10c8..8cbe2e0 100644
--- a/packages_apps_bluetooth_ext/src/map/src/BluetoothMapbMessageExtEmail.java
+++ b/packages_apps_bluetooth_ext/src/map/src/BluetoothMapbMessageExtEmail.java
@@ -25,6 +25,8 @@
 import java.util.Date;
 import java.util.Locale;
 import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import com.android.bluetooth.map.BluetoothMapSmsPdu.SmsPdu;
 
@@ -100,6 +102,9 @@
        int pos1 = 0;
        //PARSE SUBJECT
        setSubject(parseSubjectEmail(body));
+       setmRecipientTo(parseEmails(body, "To:"));
+       setmRecipientCc(parseEmails(body, "Cc:"));
+       setmRecipientBCc(parseEmails(body, "Bcc:"));
        //Parse Boundary
        String boundary = parseBoundaryEmail(body);
        if (boundary != null && !boundary.equalsIgnoreCase("")) {
@@ -289,4 +294,37 @@
        }
        return encodeGeneric(bodyFragments);
    }
+
+    private ArrayList<String> parseEmails(String body , String type){
+        ArrayList<String> emailList =new ArrayList<>();
+        try {
+            int pos = body.indexOf(type);
+            if (pos > 0) {
+                int beginVersionPos = pos + type.length();
+                int endVersionPos = body.indexOf("\n", beginVersionPos);
+                String data= body.substring(beginVersionPos, endVersionPos);
+                if (data == null || data.isEmpty()) {
+                    return emailList;
+                }
+                Matcher m = Pattern.compile("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+")
+                        .matcher(data);
+                while (m.find()) {
+                    String email = m.group();
+                    if (email.startsWith(".")) {
+                        email= email.substring(1);
+                    } if (email.endsWith(".")) {
+                        email= email.substring(0,email.length()-1);
+                    }
+                    if (emailList == null) {
+                        emailList=new ArrayList<>();
+                    } if(!emailList.contains(email)) {
+                        emailList.add(email);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Log.w(TAG," parseEmails " + e.toString());
+        }
+        return emailList;
+    }
 }