Loading src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java +44 −22 Original line number Diff line number Diff line Loading @@ -15,19 +15,18 @@ */ package com.android.internal.telephony; import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.provider.VoicemailContract; import android.telephony.SmsMessage; import android.telephony.TelephonyManager; import android.telephony.VisualVoicemailSmsFilterSettings; import android.util.Log; import android.telephony.SmsMessage; import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData; import java.nio.charset.StandardCharsets; public class VisualVoicemailSmsFilter { private static final String TAG = "VvmSmsFilter"; Loading Loading @@ -61,13 +60,34 @@ public class VisualVoicemailSmsFilter { // TODO: filter base on originating number and destination port. String messageBody = getFullMessage(pdus, format); if(messageBody == null){ return false; // Verizon WAP push SMS is not recognized by android, which has a ascii PDU. // Attempt to parse it. Log.i(TAG, "Unparsable SMS received"); String asciiMessage = parseAsciiPduMessage(pdus); WrappedMessageData messageData = VisualVoicemailSmsParser .parseAlternativeFormat(asciiMessage); if (messageData != null) { sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData); } // Confidence for what the message actually is is low. Don't remove the message and let // system decide. Usually because it is not parsable it will be dropped. return false; } else { String clientPrefix = settings.clientPrefix; WrappedMessageData messageData = VisualVoicemailSmsParser.parse(clientPrefix, messageBody); WrappedMessageData messageData = VisualVoicemailSmsParser .parse(clientPrefix, messageBody); if (messageData != null) { sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData); return true; } } return false; } private static void sendVvmSmsBroadcast(Context context, String vvmClientPackage, int subId, WrappedMessageData messageData) { Log.i(TAG, "VVM SMS received"); Intent intent = new Intent(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED); intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_PREFIX, messageData.prefix); Loading @@ -75,10 +95,6 @@ public class VisualVoicemailSmsFilter { intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID, subId); intent.setPackage(vvmClientPackage); context.sendBroadcast(intent); return true; } return false; } private static String getFullMessage(byte[][] pdus, String format) { Loading @@ -86,10 +102,8 @@ public class VisualVoicemailSmsFilter { for (byte pdu[] : pdus) { SmsMessage message =SmsMessage.createFromPdu(pdu, format); if(message == null || message.mWrappedSmsMessage == null) { // b/29123941 Certain PDU will cause createFromPdu() to return a SmsMessage with // null mWrappedSmsMessage, throwing NPE on any method called. In this case, just // ignore the message. if (message == null) { // The PDU is not recognized by android return null; } String body = message.getMessageBody(); Loading @@ -99,4 +113,12 @@ public class VisualVoicemailSmsFilter { } return builder.toString(); } private static String parseAsciiPduMessage(byte[][] pdus) { StringBuilder builder = new StringBuilder(); for (byte pdu[] : pdus) { builder.append(new String(pdu, StandardCharsets.US_ASCII)); } return builder.toString(); } } src/java/com/android/internal/telephony/VisualVoicemailSmsParser.java +43 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,10 @@ import android.os.Bundle; public class VisualVoicemailSmsParser { private static final String[] ALLOWED_ALTERNATIVE_FORMAT_EVENT = new String[] { "MBOXUPDATE", "UNRECOGNIZED" }; /** * Class wrapping the raw OMTP message data, internally represented as as map of all key-value * pairs found in the SMS body. <p> All the methods return null if either the field was not Loading Loading @@ -80,6 +84,7 @@ public class VisualVoicemailSmsParser { * @param message The sms string with the prefix removed. * @return A WrappedMessageData object containing the map. */ @Nullable private static Bundle parseSmsBody(String message) { // TODO: ensure fail if format does not match Bundle keyValues = new Bundle(); Loading Loading @@ -107,4 +112,42 @@ public class VisualVoicemailSmsParser { return keyValues; } /** * The alternative format is [Event]?([key]=[value])*, for example * * <p>"MBOXUPDATE?m=1;server=example.com;port=143;name=foo@example.com;pw=foo". * * <p>This format is not protected with a client prefix and should be handled with care. For * safety, the event type must be one of {@link #ALLOWED_ALTERNATIVE_FORMAT_EVENT} */ @Nullable public static WrappedMessageData parseAlternativeFormat(String smsBody) { try { int eventTypeEnd = smsBody.indexOf("?"); if (eventTypeEnd == -1) { return null; } String eventType = smsBody.substring(0, eventTypeEnd); if (!isAllowedAlternativeFormatEvent(eventType)) { return null; } Bundle fields = parseSmsBody(smsBody.substring(eventTypeEnd + 1)); if (fields == null) { return null; } return new WrappedMessageData(eventType, fields); } catch (IndexOutOfBoundsException e) { return null; } } private static boolean isAllowedAlternativeFormatEvent(String eventType) { for (String event : ALLOWED_ALTERNATIVE_FORMAT_EVENT) { if (event.equals(eventType)) { return true; } } return false; } } tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsParserTest.java +38 −2 Original line number Diff line number Diff line Loading @@ -16,9 +16,7 @@ package com.android.internal.telephony; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData; import junit.framework.TestCase; public class VisualVoicemailSmsParserTest extends TestCase { Loading Loading @@ -147,4 +145,42 @@ public class VisualVoicemailSmsParserTest extends TestCase { assertEquals("STATUS", result.prefix); assertEquals("", result.fields.getString("key")); } @SmallTest public void testAlternativeParsing_Mboxupdate() { WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat( "MBOXUPDATE?m=1;server=example.com;port=143;name=foo@example.com;pw=bar"); assertEquals("MBOXUPDATE", result.prefix); assertEquals("1", result.fields.getString("m")); assertEquals("example.com", result.fields.getString("server")); assertEquals("143", result.fields.getString("port")); assertEquals("foo@example.com", result.fields.getString("name")); assertEquals("bar", result.fields.getString("pw")); } @SmallTest public void testAlternativeParsing_Unrecognized() { WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat( "UNRECOGNIZED?cmd=STATUS"); assertEquals("UNRECOGNIZED", result.prefix); assertEquals("STATUS", result.fields.getString("cmd")); } @SmallTest public void testAlternativeParsingFail_MissingSeparator() { WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat( "I send SMS in weird formats"); assertNull(result); } @SmallTest public void testAlternativeParsingFail_NotWhitelistedEvent() { WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat( "AreYouStillThere?"); assertNull(result); } } Loading
src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java +44 −22 Original line number Diff line number Diff line Loading @@ -15,19 +15,18 @@ */ package com.android.internal.telephony; import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.provider.VoicemailContract; import android.telephony.SmsMessage; import android.telephony.TelephonyManager; import android.telephony.VisualVoicemailSmsFilterSettings; import android.util.Log; import android.telephony.SmsMessage; import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData; import java.nio.charset.StandardCharsets; public class VisualVoicemailSmsFilter { private static final String TAG = "VvmSmsFilter"; Loading Loading @@ -61,13 +60,34 @@ public class VisualVoicemailSmsFilter { // TODO: filter base on originating number and destination port. String messageBody = getFullMessage(pdus, format); if(messageBody == null){ return false; // Verizon WAP push SMS is not recognized by android, which has a ascii PDU. // Attempt to parse it. Log.i(TAG, "Unparsable SMS received"); String asciiMessage = parseAsciiPduMessage(pdus); WrappedMessageData messageData = VisualVoicemailSmsParser .parseAlternativeFormat(asciiMessage); if (messageData != null) { sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData); } // Confidence for what the message actually is is low. Don't remove the message and let // system decide. Usually because it is not parsable it will be dropped. return false; } else { String clientPrefix = settings.clientPrefix; WrappedMessageData messageData = VisualVoicemailSmsParser.parse(clientPrefix, messageBody); WrappedMessageData messageData = VisualVoicemailSmsParser .parse(clientPrefix, messageBody); if (messageData != null) { sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData); return true; } } return false; } private static void sendVvmSmsBroadcast(Context context, String vvmClientPackage, int subId, WrappedMessageData messageData) { Log.i(TAG, "VVM SMS received"); Intent intent = new Intent(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED); intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_PREFIX, messageData.prefix); Loading @@ -75,10 +95,6 @@ public class VisualVoicemailSmsFilter { intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID, subId); intent.setPackage(vvmClientPackage); context.sendBroadcast(intent); return true; } return false; } private static String getFullMessage(byte[][] pdus, String format) { Loading @@ -86,10 +102,8 @@ public class VisualVoicemailSmsFilter { for (byte pdu[] : pdus) { SmsMessage message =SmsMessage.createFromPdu(pdu, format); if(message == null || message.mWrappedSmsMessage == null) { // b/29123941 Certain PDU will cause createFromPdu() to return a SmsMessage with // null mWrappedSmsMessage, throwing NPE on any method called. In this case, just // ignore the message. if (message == null) { // The PDU is not recognized by android return null; } String body = message.getMessageBody(); Loading @@ -99,4 +113,12 @@ public class VisualVoicemailSmsFilter { } return builder.toString(); } private static String parseAsciiPduMessage(byte[][] pdus) { StringBuilder builder = new StringBuilder(); for (byte pdu[] : pdus) { builder.append(new String(pdu, StandardCharsets.US_ASCII)); } return builder.toString(); } }
src/java/com/android/internal/telephony/VisualVoicemailSmsParser.java +43 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,10 @@ import android.os.Bundle; public class VisualVoicemailSmsParser { private static final String[] ALLOWED_ALTERNATIVE_FORMAT_EVENT = new String[] { "MBOXUPDATE", "UNRECOGNIZED" }; /** * Class wrapping the raw OMTP message data, internally represented as as map of all key-value * pairs found in the SMS body. <p> All the methods return null if either the field was not Loading Loading @@ -80,6 +84,7 @@ public class VisualVoicemailSmsParser { * @param message The sms string with the prefix removed. * @return A WrappedMessageData object containing the map. */ @Nullable private static Bundle parseSmsBody(String message) { // TODO: ensure fail if format does not match Bundle keyValues = new Bundle(); Loading Loading @@ -107,4 +112,42 @@ public class VisualVoicemailSmsParser { return keyValues; } /** * The alternative format is [Event]?([key]=[value])*, for example * * <p>"MBOXUPDATE?m=1;server=example.com;port=143;name=foo@example.com;pw=foo". * * <p>This format is not protected with a client prefix and should be handled with care. For * safety, the event type must be one of {@link #ALLOWED_ALTERNATIVE_FORMAT_EVENT} */ @Nullable public static WrappedMessageData parseAlternativeFormat(String smsBody) { try { int eventTypeEnd = smsBody.indexOf("?"); if (eventTypeEnd == -1) { return null; } String eventType = smsBody.substring(0, eventTypeEnd); if (!isAllowedAlternativeFormatEvent(eventType)) { return null; } Bundle fields = parseSmsBody(smsBody.substring(eventTypeEnd + 1)); if (fields == null) { return null; } return new WrappedMessageData(eventType, fields); } catch (IndexOutOfBoundsException e) { return null; } } private static boolean isAllowedAlternativeFormatEvent(String eventType) { for (String event : ALLOWED_ALTERNATIVE_FORMAT_EVENT) { if (event.equals(eventType)) { return true; } } return false; } }
tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsParserTest.java +38 −2 Original line number Diff line number Diff line Loading @@ -16,9 +16,7 @@ package com.android.internal.telephony; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData; import junit.framework.TestCase; public class VisualVoicemailSmsParserTest extends TestCase { Loading Loading @@ -147,4 +145,42 @@ public class VisualVoicemailSmsParserTest extends TestCase { assertEquals("STATUS", result.prefix); assertEquals("", result.fields.getString("key")); } @SmallTest public void testAlternativeParsing_Mboxupdate() { WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat( "MBOXUPDATE?m=1;server=example.com;port=143;name=foo@example.com;pw=bar"); assertEquals("MBOXUPDATE", result.prefix); assertEquals("1", result.fields.getString("m")); assertEquals("example.com", result.fields.getString("server")); assertEquals("143", result.fields.getString("port")); assertEquals("foo@example.com", result.fields.getString("name")); assertEquals("bar", result.fields.getString("pw")); } @SmallTest public void testAlternativeParsing_Unrecognized() { WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat( "UNRECOGNIZED?cmd=STATUS"); assertEquals("UNRECOGNIZED", result.prefix); assertEquals("STATUS", result.fields.getString("cmd")); } @SmallTest public void testAlternativeParsingFail_MissingSeparator() { WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat( "I send SMS in weird formats"); assertNull(result); } @SmallTest public void testAlternativeParsingFail_NotWhitelistedEvent() { WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat( "AreYouStillThere?"); assertNull(result); } }