Integrate in cl/356241895 into testRcsApp

Add support for incoming MSRP sessions using code in cl/356241895

Fixes: 178469888
Test: manual
Change-Id: I4e39964e7577c566d19f28aa60b8015e4a867d7a
diff --git a/testapps/TestRcsApp/TestApp/AndroidManifest.xml b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
index 6e52949..d57ec94 100644
--- a/testapps/TestRcsApp/TestApp/AndroidManifest.xml
+++ b/testapps/TestRcsApp/TestApp/AndroidManifest.xml
@@ -19,8 +19,8 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.google.android.sample.rcsclient"
-    android:versionCode="3"
-    android:versionName="1.0.2_UP1.0">
+    android:versionCode="4"
+    android:versionName="1.0.3">
 
     <uses-sdk
         android:minSdkVersion="30"
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/javatests/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessageTest.java b/testapps/TestRcsApp/aosp_test_rcsclient/javatests/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessageTest.java
new file mode 100644
index 0000000..2dda33f
--- /dev/null
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/javatests/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessageTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.libraries.rcs.simpleclient.protocol.cpim;
+
+import static com.google.common.truth.Truth.assertThat;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class SimpleCpimMessageTest {
+    private static final String SAMPLE_CPIM =
+            "From: MR SANDERS <im:[email protected]>\r\n"
+                    + "To: Depressed Donkey <im:[email protected]>\r\n"
+                    + "DateTime: 2000-12-13T13:40:00-08:00\r\n"
+                    + "Subject: the weather will be fine today\r\n"
+                    + "Subject:;lang=fr beau temps prevu pour aujourd'hui\r\n"
+                    + "NS: MyFeatures <mid:[email protected]>\r\n"
+                    + "Require: MyFeatures.VitalMessageOption\r\n"
+                    + "MyFeatures.VitalMessageOption: Confirmation-requested\r\n"
+                    + "MyFeatures.WackyMessageOption: Use-silly-font\r\n"
+                    + "\r\n"
+                    + "Content-type: text/plain; charset=utf-8\r\n"
+                    + "Content-ID: <[email protected]>\r\n"
+                    + "\r\n"
+                    + "body";
+
+    @Test
+    public void parse_successful() throws Exception {
+        SimpleCpimMessage cpim = SimpleCpimMessage.parse(SAMPLE_CPIM.getBytes(UTF_8));
+
+        assertThat(cpim.namespaces()).containsEntry("MyFeatures", "mid:[email protected]");
+        assertThat(cpim.headers()).containsEntry("Require", "MyFeatures.VitalMessageOption");
+        assertThat(cpim.contentType()).isEqualTo("text/plain; charset=utf-8");
+        assertThat(cpim.content()).isEqualTo("body");
+    }
+}
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessage.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessage.java
index aeb6b11..ad5f1f5 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessage.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/protocol/cpim/SimpleCpimMessage.java
@@ -16,11 +16,19 @@
 
 package com.android.libraries.rcs.simpleclient.protocol.cpim;
 
+import android.text.TextUtils;
 import com.google.auto.value.AutoValue;
+import com.google.common.base.Ascii;
 import com.google.common.base.Utf8;
 import com.google.common.collect.ImmutableMap;
-
+import com.google.common.io.CharStreams;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * The CPIM implementation as per RFC 3862. This class supports minimal fields that is required to
@@ -30,10 +38,9 @@
 public abstract class SimpleCpimMessage {
     private static final String CRLF = "\r\n";
     private static final String COLSP = ": ";
-
-    public static SimpleCpimMessage.Builder newBuilder() {
-        return new AutoValue_SimpleCpimMessage.Builder();
-    }
+    private static final Pattern NAMESPACE_HEADER_PATTERN =
+            Pattern.compile("NS:\\s+(\\S+)\\s+<(.+)>");
+    private static final Pattern HEADER_PATTERN = Pattern.compile("([^\\s:]+):\\s+(.+)");
 
     public abstract ImmutableMap<String, String> namespaces();
 
@@ -68,6 +75,42 @@
         return builder.toString();
     }
 
+    public static SimpleCpimMessage parse(byte[] content) throws IOException {
+        BufferedReader reader =
+                new BufferedReader(new InputStreamReader(new ByteArrayInputStream(content)));
+        Builder builder = newBuilder();
+
+        String line = reader.readLine();
+        while (!TextUtils.isEmpty(line)) {
+            Matcher namespaceMatcher = NAMESPACE_HEADER_PATTERN.matcher(line);
+            Matcher headerMatcher = HEADER_PATTERN.matcher(line);
+            if (namespaceMatcher.matches()) {
+                builder.addNamespace(namespaceMatcher.group(1), namespaceMatcher.group(2));
+            } else if (headerMatcher.matches()) {
+                builder.addHeader(headerMatcher.group(1), headerMatcher.group(2));
+            }
+
+            line = reader.readLine();
+        }
+
+        line = reader.readLine();
+        while (!TextUtils.isEmpty(line)) {
+            Matcher headerMatcher = HEADER_PATTERN.matcher(line);
+            if (headerMatcher.matches()) {
+                if (Ascii.equalsIgnoreCase("content-type", headerMatcher.group(1))) {
+                    builder.setContentType(headerMatcher.group(2));
+                }
+            }
+
+            line = reader.readLine();
+        }
+
+        String body = CharStreams.toString(reader);
+        builder.setContent(body);
+
+        return builder.build();
+    }
+
     @AutoValue.Builder
     public abstract static class Builder {
         public abstract ImmutableMap.Builder<String, String> namespacesBuilder();
@@ -90,4 +133,8 @@
             return this;
         }
     }
+
+    public static SimpleCpimMessage.Builder newBuilder() {
+        return new AutoValue_SimpleCpimMessage.Builder();
+    }
 }
diff --git a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
index 74472d7..29c5176 100644
--- a/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
+++ b/testapps/TestRcsApp/aosp_test_rcsclient/src/com/android/libraries/rcs/simpleclient/service/chat/SimpleChatSession.java
@@ -31,6 +31,7 @@
 import com.android.libraries.rcs.simpleclient.protocol.cpim.SimpleCpimMessage;
 import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunk;
 import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunk.Continuation;
+import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpChunkHeader;
 import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpConstants;
 import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpManager;
 import com.android.libraries.rcs.simpleclient.protocol.msrp.MsrpSession;
@@ -408,11 +409,29 @@
 
     private void receiveMsrpChunk(MsrpChunk chunk) {
         Log.d(TAG, "Received msrp= " + chunk + " conversation=" + mConversationId);
-        if (mListener != null) {
-            // TODO(b/173186571): Parse CPIM and invoke onMessageReceived()
+
+        MsrpChunkHeader contentTypeHeader = chunk.header("Content-Type");
+        if (chunk.content().length == 0 || contentTypeHeader == null) {
+            Log.i(TAG, "No content or Content-Type header, drop it");
+            return;
+        }
+
+        String contentType = contentTypeHeader.value();
+        if ("message/cpim".equals(contentType)) {
+            try {
+                SimpleCpimMessage cpim = SimpleCpimMessage.parse(chunk.content());
+                if (mListener != null) {
+                    mListener.onMessageReceived(cpim);
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "Error while parsing cpim message.", e);
+            }
+        } else {
+            Log.w(TAG, contentType + " is not supported.");
         }
     }
 
+
     /** Set new listener for this session. */
     public void setListener(@Nullable ChatSessionListener listener) {
         mListener = listener;