diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b9c2a5736f..9d5f63da3e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -223,7 +223,9 @@ + + diff --git a/androidTest/java/org/thoughtcrime/securesms/util/Rfc5724UriTest.java b/androidTest/java/org/thoughtcrime/securesms/util/Rfc5724UriTest.java new file mode 100644 index 0000000000..73452b4e92 --- /dev/null +++ b/androidTest/java/org/thoughtcrime/securesms/util/Rfc5724UriTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.thoughtcrime.securesms.util; + +import android.util.Log; + +import org.thoughtcrime.securesms.TextSecureTestCase; + +import java.net.URISyntaxException; + +public class Rfc5724UriTest extends TextSecureTestCase { + + private static final String TAG = Rfc5724UriTest.class.getSimpleName(); + + public void testInvalidPath() throws Exception { + final String[] invalidSchemaUris = { + "", + ":", + "sms:", + ":sms", + "sms:?goto=fail", + "sms:?goto=fail&fail=goto" + }; + + for (String uri : invalidSchemaUris) { + try { + new Rfc5724Uri(uri); + Log.e(TAG, "uri " + uri + " should have failed path check"); + assertTrue(false); + } catch (URISyntaxException e) { } + } + } + + public void testGetSchema() throws Exception { + final String[][] uriTestPairs = { + {"sms:+15555555555", "sms"}, + {"sMs:+15555555555", "sMs"}, + {"smsto:+15555555555?", "smsto"}, + {"mms:+15555555555?a=b", "mms"}, + {"mmsto:+15555555555?a=b&c=d", "mmsto"} + }; + + for (String[] uriTestPair : uriTestPairs) { + final Rfc5724Uri testUri = new Rfc5724Uri(uriTestPair[0]); + Log.d(TAG, testUri.getSchema() + " ?= " + uriTestPair[1]); + assertTrue(testUri.getSchema().equals(uriTestPair[1])); + } + } + + public void testGetPath() throws Exception { + final String[][] uriTestPairs = { + {"sms:+15555555555", "+15555555555"}, + {"smsto:+15555555555?", "+15555555555"}, + {"mms:+15555555555?a=b", "+15555555555"}, + {"mmsto:+15555555555?a=b&c=d", "+15555555555"}, + {"sms:+15555555555,+14444444444", "+15555555555,+14444444444"}, + {"sms:+15555555555,+14444444444?", "+15555555555,+14444444444"}, + {"sms:+15555555555,+14444444444?a=b", "+15555555555,+14444444444"}, + {"sms:+15555555555,+14444444444?a=b&c=d", "+15555555555,+14444444444"} + }; + + for (String[] uriTestPair : uriTestPairs) { + final Rfc5724Uri testUri = new Rfc5724Uri(uriTestPair[0]); + Log.d(TAG, testUri.getPath() + " ?= " + uriTestPair[1]); + assertTrue(testUri.getPath().equals(uriTestPair[1])); + } + } + + public void testGetQueryParams() throws Exception { + final String[][] uriTestPairs = { + {"sms:+15555555555", "a", null}, + {"mms:+15555555555?b=", "a", null}, + {"mmsto:+15555555555?a=", "a", ""}, + {"sms:+15555555555?a=b", "a", "b"}, + {"sms:+15555555555?a=b&c=d", "a", "b"}, + {"sms:+15555555555?a=b&c=d", "b", null}, + {"sms:+15555555555?a=b&c=d", "c", "d"}, + {"sms:+15555555555?a=b&c=d", "d", null} + }; + + for (String[] uriTestPair : uriTestPairs) { + final Rfc5724Uri testUri = new Rfc5724Uri(uriTestPair[0]); + final String paramResult = testUri.getQueryParams().get(uriTestPair[1]); + + Log.d(TAG, paramResult + " ?= " + uriTestPair[2]); + if (paramResult == null) assertTrue(uriTestPair[2] == null); + else assertTrue(paramResult.equals(uriTestPair[2])); + } + } + +} diff --git a/src/org/thoughtcrime/securesms/SmsSendtoActivity.java b/src/org/thoughtcrime/securesms/SmsSendtoActivity.java index 0040e4098f..798748e132 100644 --- a/src/org/thoughtcrime/securesms/SmsSendtoActivity.java +++ b/src/org/thoughtcrime/securesms/SmsSendtoActivity.java @@ -3,13 +3,20 @@ package org.thoughtcrime.securesms; import android.app.Activity; import android.content.Intent; import android.os.Bundle; +import android.util.Log; import android.widget.Toast; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.util.Rfc5724Uri; + +import java.net.URISyntaxException; public class SmsSendtoActivity extends Activity { + + private static final String TAG = SmsSendtoActivity.class.getSimpleName(); + @Override protected void onCreate(Bundle savedInstanceState) { startActivity(getNextIntent(getIntent())); @@ -18,8 +25,22 @@ public class SmsSendtoActivity extends Activity { } private Intent getNextIntent(Intent original) { - String body = original.getStringExtra("sms_body"); - String data = original.getData().getSchemeSpecificPart(); + String body = ""; + String data = ""; + + if (original.getAction().equals(Intent.ACTION_SENDTO)) { + body = original.getStringExtra("sms_body"); + data = original.getData().getSchemeSpecificPart(); + } else { + try { + Rfc5724Uri smsUri = new Rfc5724Uri(original.getData().toString()); + body = smsUri.getQueryParams().get("body"); + data = smsUri.getPath(); + } catch (URISyntaxException e) { + Log.w(TAG, "unable to parse RFC5724 URI from intent", e); + } + } + Recipients recipients = RecipientFactory.getRecipientsFromString(this, data, false); long threadId = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipients); diff --git a/src/org/thoughtcrime/securesms/util/Rfc5724Uri.java b/src/org/thoughtcrime/securesms/util/Rfc5724Uri.java new file mode 100644 index 0000000000..deba6b6516 --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/Rfc5724Uri.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.thoughtcrime.securesms.util; + +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Map; + +public class Rfc5724Uri { + + private final String uri; + private final String schema; + private final String path; + private final Map queryParams; + + public Rfc5724Uri(String uri) throws URISyntaxException { + this.uri = uri; + this.schema = parseSchema(); + this.path = parsePath(); + this.queryParams = parseQueryParams(); + } + + private String parseSchema() throws URISyntaxException { + String[] parts = uri.split(":"); + + if (parts.length < 1 || parts[0].isEmpty()) throw new URISyntaxException(uri, "invalid schema"); + else return parts[0]; + } + + private String parsePath() throws URISyntaxException { + String[] parts = uri.split("\\?")[0].split(":", 2); + + if (parts.length < 2 || parts[1].isEmpty()) throw new URISyntaxException(uri, "invalid path"); + else return parts[1]; + } + + private Map parseQueryParams() throws URISyntaxException { + Map queryParams = new HashMap<>(); + if (uri.split("\\?").length < 2) { + return queryParams; + } + + for (String keyValue : uri.split("\\?")[1].split("&")) { + String[] parts = keyValue.split("="); + + if (parts.length == 1) queryParams.put(parts[0], ""); + else queryParams.put(parts[0], URLDecoder.decode(parts[1])); + } + + return queryParams; + } + + public String getSchema() { + return schema; + } + + public String getPath() { + return path; + } + + public Map getQueryParams() { + return queryParams; + } +}