MAP: make MMS parsing more robust
Some devices are not following the specs correctly and send plan-text as MMS without the right headers.
This patch makes the MMS parser more robust against faulty MMS messages.
Bug: 11161383
Change-Id: If5e59f9daaab4537cfe5d06e6203ae783e311fd3
diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java b/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
index 11ff0ff..58528f6 100644
--- a/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
+++ b/android/app/src/com/android/bluetooth/map/BluetoothMapContentObserver.java
@@ -662,9 +662,7 @@
/* Send message if folder is outbox */
/* to do, support MMS in the future */
/*
- if (folder.equals("outbox")) {
handle = sendMmsMessage(folder, phone, (BluetoothMapbMessageMmsEmail)msg);
- }
*/
break;
}
@@ -720,22 +718,16 @@
*else if folder !outbox:
*1) push message to folder
* */
- if (folder != null && (folder.equalsIgnoreCase("outbox")|| folder.equalsIgnoreCase("drafts"))) {
- long handle = pushMmsToFolder(Mms.MESSAGE_BOX_DRAFTS, to_address, msg);
- /* if invalid handle (-1) then just return the handle - else continue sending (if folder is outbox) */
- if (BluetoothMapAppParams.INVALID_VALUE_PARAMETER != handle && folder.equalsIgnoreCase("outbox")) {
- moveDraftToOutbox(handle);
+ long handle = pushMmsToFolder(Mms.MESSAGE_BOX_DRAFTS, to_address, msg);
+ /* if invalid handle (-1) then just return the handle - else continue sending (if folder is outbox) */
+ if (BluetoothMapAppParams.INVALID_VALUE_PARAMETER != handle && folder.equalsIgnoreCase("outbox")) {
+ moveDraftToOutbox(handle);
- Intent sendIntent = new Intent("android.intent.action.MMS_SEND_OUTBOX_MSG");
- Log.d(TAG, "broadcasting intent: "+sendIntent.toString());
- mContext.sendBroadcast(sendIntent);
- }
- return handle;
- } else {
- /* not allowed to push mms to anything but outbox/drafts */
- throw new IllegalArgumentException("Cannot push message to other folders than outbox/drafts");
+ Intent sendIntent = new Intent("android.intent.action.MMS_SEND_OUTBOX_MSG");
+ Log.d(TAG, "broadcasting intent: "+sendIntent.toString());
+ mContext.sendBroadcast(sendIntent);
}
-
+ return handle;
}
diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapObexServer.java b/android/app/src/com/android/bluetooth/map/BluetoothMapObexServer.java
index a876740..932645c 100644
--- a/android/app/src/com/android/bluetooth/map/BluetoothMapObexServer.java
+++ b/android/app/src/com/android/bluetooth/map/BluetoothMapObexServer.java
@@ -239,10 +239,11 @@
if(folderName == null || folderName.equals("")) {
folderName = mCurrentFolder.getName();
}
- if(!folderName.equals("outbox") && !folderName.equals("draft")) {
+ if(!folderName.equalsIgnoreCase("outbox") && !folderName.equalsIgnoreCase("draft")) {
if(D) Log.d(TAG, "Push message only allowed to outbox and draft. folderName: " + folderName);
return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE;
}
+ folderName = folderName.toLowerCase();
/* - Read out the message
* - Decode into a bMessage
* - send it.
diff --git a/android/app/src/com/android/bluetooth/map/BluetoothMapbMessageMmsEmail.java b/android/app/src/com/android/bluetooth/map/BluetoothMapbMessageMmsEmail.java
index 0f1feac..0fcba3b 100644
--- a/android/app/src/com/android/bluetooth/map/BluetoothMapbMessageMmsEmail.java
+++ b/android/app/src/com/android/bluetooth/map/BluetoothMapbMessageMmsEmail.java
@@ -481,6 +481,7 @@
{
if(contentTypeParts[j].contains("boundary")) {
boundary = contentTypeParts[j].split("boundary[\\s]*=", 2)[1].trim();
+ boundary = boundary.replaceAll("\"", ""); // " is allowed around a boundary, but is not allowed as part of the boundary
}
}
}
@@ -497,49 +498,53 @@
private void parseMmsMimePart(String partStr) {
String[] parts = partStr.split("\r\n\r\n", 2); // Split the header from the body
String body;
+ MimePart newPart = addMimePart();
+ String partEncoding = encoding; /* Use the overall encoding as default */
if(parts.length != 2) {
body = partStr;
} else {
body = parts[1];
- }
- String[] headers = parts[0].split("\r\n");
- MimePart newPart = addMimePart();
- String partEncoding = encoding; /* Use the overall encoding as default */
+ String[] headers = parts[0].split("\r\n");
- for(String header : headers) {
- if(header.length() == 0)
- continue;
+ for(String header : headers) {
+ if(header.length() == 0)
+ continue;
- if(header.trim() == "" || header.trim().equals("--")) // Skip empty lines(the \r\n after the boundary tag) and endBoundary tags
- continue;
- String[] headerParts = header.split(":",2);
- if(headerParts.length != 2)
- throw new IllegalArgumentException("part-Header not formatted correctly: " + header);
- String headerType = headerParts[0].toUpperCase();
- String headerValue = headerParts[1].trim();
- if(headerType.contains("CONTENT-TYPE")) {
- // TODO: extract charset? Only UTF-8 is allowed for TEXT typed parts
- newPart.contentType = headerValue;
- Log.d(TAG, "*** CONTENT-TYPE: " + newPart.contentType);
- }
- else if(headerType.contains("CONTENT-LOCATION")) {
- // This is used if the smil refers to a file name in its src=
- newPart.contentLocation = headerValue;
- newPart.partName = headerValue;
- }
- else if(headerType.contains("CONTENT-TRANSFER-ENCODING")) {
- partEncoding = headerValue;
- }
- else if(headerType.contains("CONTENT-ID")) {
- // This is used if the smil refers to a cid:<xxx> in it's src=
- newPart.contentId = headerValue;
- }
- else if(headerType.contains("CONTENT-DISPOSITION")) {
- // This is used if the smil refers to a cid:<xxx> in it's src=
- newPart.contentDisposition = headerValue;
- }
- else {
- if(D) Log.w(TAG,"Skipping unknown part-header: " + headerType + " (" + header + ")");
+ if(header.trim() == "" || header.trim().equals("--")) // Skip empty lines(the \r\n after the boundary tag) and endBoundary tags
+ continue;
+ String[] headerParts = header.split(":",2);
+ if(headerParts.length != 2) {
+ //throw new IllegalArgumentException("part-Header not formatted correctly: " + header);
+ // If we find a part without headers, treat the entire content as body
+ body = partStr;
+ break;
+ }
+ String headerType = headerParts[0].toUpperCase();
+ String headerValue = headerParts[1].trim();
+ if(headerType.contains("CONTENT-TYPE")) {
+ // TODO: extract charset? Only UTF-8 is allowed for TEXT typed parts
+ newPart.contentType = headerValue;
+ Log.d(TAG, "*** CONTENT-TYPE: " + newPart.contentType);
+ }
+ else if(headerType.contains("CONTENT-LOCATION")) {
+ // This is used if the smil refers to a file name in its src=
+ newPart.contentLocation = headerValue;
+ newPart.partName = headerValue;
+ }
+ else if(headerType.contains("CONTENT-TRANSFER-ENCODING")) {
+ partEncoding = headerValue;
+ }
+ else if(headerType.contains("CONTENT-ID")) {
+ // This is used if the smil refers to a cid:<xxx> in it's src=
+ newPart.contentId = headerValue;
+ }
+ else if(headerType.contains("CONTENT-DISPOSITION")) {
+ // This is used if the smil refers to a cid:<xxx> in it's src=
+ newPart.contentDisposition = headerValue;
+ }
+ else {
+ if(D) Log.w(TAG,"Skipping unknown part-header: " + headerType + " (" + header + ")");
+ }
}
}
// Now for the body
@@ -607,7 +612,7 @@
else
{
mimeParts = messageBody.split("--" + boundary);
- for(int i = 0; i < mimeParts.length - 1; i++) {
+ for(int i = 1; i < mimeParts.length - 1; i++) {
String part = mimeParts[i];
if (part != null && (part.length() > 0))
parseMmsMimePart(part);