mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +00:00
Support for incoming attachments.
1) Refactored MMS layer to use abstracted types. 2) Added support for retrieving attachment IDs.
This commit is contained in:
parent
4bb337a3a0
commit
9287d413ac
@ -33,6 +33,7 @@ import java.io.InputStream;
|
|||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles providing lookups, serializing, and deserializing the RedPhone directory.
|
* Handles providing lookups, serializing, and deserializing the RedPhone directory.
|
||||||
@ -102,7 +103,30 @@ public class NumberFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void update(File bloomFilter, long capacity, int hashCount, String version)
|
public synchronized void update(DirectoryDescriptor descriptor, File compressedData) {
|
||||||
|
try {
|
||||||
|
File uncompressed = File.createTempFile("directory", ".dat", context.getFilesDir());
|
||||||
|
FileInputStream fin = new FileInputStream (compressedData);
|
||||||
|
GZIPInputStream gin = new GZIPInputStream(fin);
|
||||||
|
FileOutputStream out = new FileOutputStream(uncompressed);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int read;
|
||||||
|
|
||||||
|
while ((read = gin.read(buffer)) != -1) {
|
||||||
|
out.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.close();
|
||||||
|
compressedData.delete();
|
||||||
|
|
||||||
|
update(uncompressed, descriptor.getCapacity(), descriptor.getHashCount(), descriptor.getVersion());
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.w("NumberFilter", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void update(File bloomFilter, long capacity, int hashCount, String version)
|
||||||
{
|
{
|
||||||
if (this.bloomFilter != null)
|
if (this.bloomFilter != null)
|
||||||
this.bloomFilter.delete();
|
this.bloomFilter.delete();
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
package org.whispersystems.textsecure.push;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class IncomingGcmMessage {
|
|
||||||
|
|
||||||
private String source;
|
|
||||||
private List<String> destinations;
|
|
||||||
private String messageText;
|
|
||||||
private List<String> attachments;
|
|
||||||
private long timestamp;
|
|
||||||
|
|
||||||
public IncomingGcmMessage(String source, List<String> destinations, String messageText, List<String> attachments, long timestamp) {
|
|
||||||
this.source = source;
|
|
||||||
this.destinations = destinations;
|
|
||||||
this.messageText = messageText;
|
|
||||||
this.attachments = attachments;
|
|
||||||
this.timestamp = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimestampMillis() {
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSource() {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getAttachments() {
|
|
||||||
return attachments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessageText() {
|
|
||||||
return messageText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getDestinations() {
|
|
||||||
return destinations;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,87 @@
|
|||||||
|
package org.whispersystems.textsecure.push;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IncomingPushMessage implements Parcelable {
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<IncomingPushMessage> CREATOR = new Parcelable.Creator<IncomingPushMessage>() {
|
||||||
|
@Override
|
||||||
|
public IncomingPushMessage createFromParcel(Parcel in) {
|
||||||
|
return new IncomingPushMessage(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IncomingPushMessage[] newArray(int size) {
|
||||||
|
return new IncomingPushMessage[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private String source;
|
||||||
|
private List<String> destinations;
|
||||||
|
private String messageText;
|
||||||
|
private List<PushAttachmentPointer> attachments;
|
||||||
|
private long timestamp;
|
||||||
|
|
||||||
|
public IncomingPushMessage(String source, List<String> destinations, String messageText,
|
||||||
|
List<PushAttachmentPointer> attachments, long timestamp)
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
this.destinations = destinations;
|
||||||
|
this.messageText = messageText;
|
||||||
|
this.attachments = attachments;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncomingPushMessage(Parcel in) {
|
||||||
|
this.destinations = new LinkedList<String>();
|
||||||
|
this.attachments = new LinkedList<PushAttachmentPointer>();
|
||||||
|
|
||||||
|
this.source = in.readString();
|
||||||
|
in.readStringList(destinations);
|
||||||
|
this.messageText = in.readString();
|
||||||
|
in.readList(attachments, PushAttachmentPointer.class.getClassLoader());
|
||||||
|
this.timestamp = in.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestampMillis() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PushAttachmentPointer> getAttachments() {
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessageText() {
|
||||||
|
return messageText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getDestinations() {
|
||||||
|
return destinations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAttachments() {
|
||||||
|
return getAttachments() != null && !getAttachments().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(source);
|
||||||
|
dest.writeStringList(destinations);
|
||||||
|
dest.writeString(messageText);
|
||||||
|
dest.writeList(attachments);
|
||||||
|
dest.writeLong(timestamp);
|
||||||
|
}
|
||||||
|
}
|
@ -5,13 +5,13 @@ import java.util.List;
|
|||||||
|
|
||||||
public class OutgoingPushMessage {
|
public class OutgoingPushMessage {
|
||||||
|
|
||||||
private List<String> destinations;
|
private List<String> destinations;
|
||||||
private String messageText;
|
private String messageText;
|
||||||
private List<String> attachments;
|
private List<PushAttachmentPointer> attachments;
|
||||||
|
|
||||||
public OutgoingPushMessage(String destination, String messageText) {
|
public OutgoingPushMessage(String destination, String messageText) {
|
||||||
this.destinations = new LinkedList<String>();
|
this.destinations = new LinkedList<String>();
|
||||||
this.attachments = new LinkedList<String>();
|
this.attachments = new LinkedList<PushAttachmentPointer>();
|
||||||
this.messageText = messageText;
|
this.messageText = messageText;
|
||||||
this.destinations.add(destination);
|
this.destinations.add(destination);
|
||||||
}
|
}
|
||||||
@ -19,11 +19,11 @@ public class OutgoingPushMessage {
|
|||||||
public OutgoingPushMessage(List<String> destinations, String messageText) {
|
public OutgoingPushMessage(List<String> destinations, String messageText) {
|
||||||
this.destinations = destinations;
|
this.destinations = destinations;
|
||||||
this.messageText = messageText;
|
this.messageText = messageText;
|
||||||
this.attachments = new LinkedList<String>();
|
this.attachments = new LinkedList<PushAttachmentPointer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutgoingPushMessage(List<String> destinations, String messageText,
|
public OutgoingPushMessage(List<String> destinations, String messageText,
|
||||||
List<String> attachments)
|
List<PushAttachmentPointer> attachments)
|
||||||
{
|
{
|
||||||
this.destinations = destinations;
|
this.destinations = destinations;
|
||||||
this.messageText = messageText;
|
this.messageText = messageText;
|
||||||
@ -38,7 +38,7 @@ public class OutgoingPushMessage {
|
|||||||
return messageText;
|
return messageText;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getAttachments() {
|
public List<PushAttachmentPointer> getAttachments() {
|
||||||
return attachments;
|
return attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package org.whispersystems.textsecure.push;
|
package org.whispersystems.textsecure.push;
|
||||||
|
|
||||||
public class PushAttachment {
|
public class PushAttachmentData {
|
||||||
|
|
||||||
private final String contentType;
|
private final String contentType;
|
||||||
private final byte[] data;
|
private final byte[] data;
|
||||||
|
|
||||||
public PushAttachment(String contentType, byte[] data) {
|
public PushAttachmentData(String contentType, byte[] data) {
|
||||||
this.contentType = contentType;
|
this.contentType = contentType;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getContentType() {
|
public String getContentType() {
|
@ -0,0 +1,51 @@
|
|||||||
|
package org.whispersystems.textsecure.push;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
public class PushAttachmentPointer implements Parcelable {
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<PushAttachmentPointer> CREATOR = new Parcelable.Creator<PushAttachmentPointer>() {
|
||||||
|
@Override
|
||||||
|
public PushAttachmentPointer createFromParcel(Parcel in) {
|
||||||
|
return new PushAttachmentPointer(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PushAttachmentPointer[] newArray(int size) {
|
||||||
|
return new PushAttachmentPointer[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final String contentType;
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
public PushAttachmentPointer(String contentType, String key) {
|
||||||
|
this.contentType = contentType;
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PushAttachmentPointer(Parcel in) {
|
||||||
|
this.contentType = in.readString();
|
||||||
|
this.key = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(contentType);
|
||||||
|
dest.writeString(key);
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ package org.whispersystems.textsecure.push;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GcmMessageResponse {
|
public class PushMessageResponse {
|
||||||
private List<String> success;
|
private List<String> success;
|
||||||
private List<String> failure;
|
private List<String> failure;
|
||||||
|
|
@ -23,8 +23,6 @@ import java.io.OutputStream;
|
|||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.KeyManagementException;
|
import java.security.KeyManagementException;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
@ -46,11 +44,13 @@ public class PushServiceSocket {
|
|||||||
private static final String MESSAGE_PATH = "/v1/messages/";
|
private static final String MESSAGE_PATH = "/v1/messages/";
|
||||||
private static final String ATTACHMENT_PATH = "/v1/attachments/%s";
|
private static final String ATTACHMENT_PATH = "/v1/attachments/%s";
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
private final String localNumber;
|
private final String localNumber;
|
||||||
private final String password;
|
private final String password;
|
||||||
private final TrustManagerFactory trustManagerFactory;
|
private final TrustManagerFactory trustManagerFactory;
|
||||||
|
|
||||||
public PushServiceSocket(Context context, String localNumber, String password) {
|
public PushServiceSocket(Context context, String localNumber, String password) {
|
||||||
|
this.context = context.getApplicationContext();
|
||||||
this.localNumber = localNumber;
|
this.localNumber = localNumber;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.trustManagerFactory = initializeTrustManagerFactory(context);
|
this.trustManagerFactory = initializeTrustManagerFactory(context);
|
||||||
@ -70,54 +70,55 @@ public class PushServiceSocket {
|
|||||||
makeRequest(REGISTER_GCM_PATH, "PUT", new Gson().toJson(registration));
|
makeRequest(REGISTER_GCM_PATH, "PUT", new Gson().toJson(registration));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregisterGcmId() throws IOException, RateLimitException {
|
public void unregisterGcmId() throws IOException {
|
||||||
makeRequest(REGISTER_GCM_PATH, "DELETE", null);
|
makeRequest(REGISTER_GCM_PATH, "DELETE", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessage(String recipient, String messageText)
|
public void sendMessage(String recipient, String messageText)
|
||||||
throws IOException, RateLimitException
|
throws IOException
|
||||||
{
|
{
|
||||||
OutgoingPushMessage message = new OutgoingPushMessage(recipient, messageText);
|
OutgoingPushMessage message = new OutgoingPushMessage(recipient, messageText);
|
||||||
sendMessage(message);
|
sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessage(List<String> recipients, String messageText)
|
public void sendMessage(List<String> recipients, String messageText)
|
||||||
throws IOException, RateLimitException
|
throws IOException
|
||||||
{
|
{
|
||||||
OutgoingPushMessage message = new OutgoingPushMessage(recipients, messageText);
|
OutgoingPushMessage message = new OutgoingPushMessage(recipients, messageText);
|
||||||
sendMessage(message);
|
sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessage(List<String> recipients, String messageText,
|
public void sendMessage(List<String> recipients, String messageText,
|
||||||
List<PushAttachment> attachments)
|
List<PushAttachmentData> attachments)
|
||||||
throws IOException, RateLimitException
|
throws IOException
|
||||||
{
|
{
|
||||||
List<String> attachmentIds = sendAttachments(attachments);
|
List<PushAttachmentPointer> attachmentIds = sendAttachments(attachments);
|
||||||
OutgoingPushMessage message = new OutgoingPushMessage(recipients, messageText, attachmentIds);
|
OutgoingPushMessage message = new OutgoingPushMessage(recipients, messageText, attachmentIds);
|
||||||
sendMessage(message);
|
sendMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessage(OutgoingPushMessage message) throws IOException, RateLimitException {
|
private void sendMessage(OutgoingPushMessage message) throws IOException {
|
||||||
String responseText = makeRequest(MESSAGE_PATH, "POST", new Gson().toJson(message));
|
String responseText = makeRequest(MESSAGE_PATH, "POST", new Gson().toJson(message));
|
||||||
GcmMessageResponse response = new Gson().fromJson(responseText, GcmMessageResponse.class);
|
PushMessageResponse response = new Gson().fromJson(responseText, PushMessageResponse.class);
|
||||||
|
|
||||||
if (response.getFailure().size() != 0)
|
if (response.getFailure().size() != 0)
|
||||||
throw new IOException("Got send failure: " + response.getFailure().get(0));
|
throw new IOException("Got send failure: " + response.getFailure().get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> sendAttachments(List<PushAttachment> attachments)
|
private List<PushAttachmentPointer> sendAttachments(List<PushAttachmentData> attachments)
|
||||||
throws IOException, RateLimitException
|
throws IOException
|
||||||
{
|
{
|
||||||
List<String> attachmentIds = new LinkedList<String>();
|
List<PushAttachmentPointer> attachmentIds = new LinkedList<PushAttachmentPointer>();
|
||||||
|
|
||||||
for (PushAttachment attachment : attachments) {
|
for (PushAttachmentData attachment : attachments) {
|
||||||
attachmentIds.add(sendAttachment(attachment));
|
attachmentIds.add(new PushAttachmentPointer(attachment.getContentType(),
|
||||||
|
sendAttachment(attachment)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return attachmentIds;
|
return attachmentIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String sendAttachment(PushAttachment attachment) throws IOException, RateLimitException {
|
private String sendAttachment(PushAttachmentData attachment) throws IOException {
|
||||||
Pair<String, String> response = makeRequestForResponseHeader(String.format(ATTACHMENT_PATH, ""),
|
Pair<String, String> response = makeRequestForResponseHeader(String.format(ATTACHMENT_PATH, ""),
|
||||||
"GET", null, "Content-Location");
|
"GET", null, "Content-Location");
|
||||||
|
|
||||||
@ -130,34 +131,52 @@ public class PushServiceSocket {
|
|||||||
|
|
||||||
uploadExternalFile("PUT", contentLocation, attachment.getData());
|
uploadExternalFile("PUT", contentLocation, attachment.getData());
|
||||||
|
|
||||||
return new Gson().fromJson(response.second, AttachmentDescriptor.class).getId();
|
return new Gson().fromJson(response.second, AttachmentKey.class).getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void retrieveDirectory(Context context ) {
|
public List<File> retrieveAttachments(List<PushAttachmentPointer> attachmentIds)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
List<File> attachments = new LinkedList<File>();
|
||||||
|
|
||||||
|
for (PushAttachmentPointer attachmentId : attachmentIds) {
|
||||||
|
Pair<String, String> response = makeRequestForResponseHeader(String.format(ATTACHMENT_PATH, attachmentId.getKey()),
|
||||||
|
"GET", null, "Content-Location");
|
||||||
|
|
||||||
|
Log.w("PushServiceSocket", "Attachment: " + attachmentId.getKey() + " is at: " + response.first);
|
||||||
|
|
||||||
|
File attachment = File.createTempFile("attachment", ".tmp", context.getFilesDir());
|
||||||
|
downloadExternalFile(response.first, attachment);
|
||||||
|
|
||||||
|
attachments.add(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pair<DirectoryDescriptor, File> retrieveDirectory() {
|
||||||
try {
|
try {
|
||||||
DirectoryDescriptor directoryDescriptor = new Gson().fromJson(makeRequest(DIRECTORY_PATH, "GET", null),
|
DirectoryDescriptor directoryDescriptor = new Gson().fromJson(makeRequest(DIRECTORY_PATH, "GET", null),
|
||||||
DirectoryDescriptor.class);
|
DirectoryDescriptor.class);
|
||||||
|
|
||||||
File directoryData = File.createTempFile("directory", ".dat", context.getFilesDir());
|
File directoryData = File.createTempFile("directory", ".dat", context.getFilesDir());
|
||||||
|
|
||||||
downloadExternalFile(directoryDescriptor.getUrl(), directoryData);
|
downloadExternalFile(directoryDescriptor.getUrl(), directoryData);
|
||||||
|
|
||||||
NumberFilter.getInstance(context).update(directoryData,
|
return new Pair<DirectoryDescriptor, File>(directoryDescriptor, directoryData);
|
||||||
directoryDescriptor.getCapacity(),
|
|
||||||
directoryDescriptor.getHashCount(),
|
|
||||||
directoryDescriptor.getVersion());
|
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w("PushServiceSocket", ioe);
|
Log.w("PushServiceSocket", ioe);
|
||||||
} catch (RateLimitException e) {
|
return null;
|
||||||
Log.w("PushServiceSocket", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void downloadExternalFile(String url, File localDestination)
|
private void downloadExternalFile(String url, File localDestination)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
URL downloadUrl = new URL(url);
|
URL downloadUrl = new URL(url);
|
||||||
HttpsURLConnection connection = (HttpsURLConnection) downloadUrl.openConnection();
|
HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
|
||||||
|
connection.setRequestProperty("Content-Type", "application/octet-stream");
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
connection.setDoInput(true);
|
connection.setDoInput(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -166,7 +185,7 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OutputStream output = new FileOutputStream(localDestination);
|
OutputStream output = new FileOutputStream(localDestination);
|
||||||
InputStream input = new GZIPInputStream(connection.getInputStream());
|
InputStream input = connection.getInputStream();
|
||||||
byte[] buffer = new byte[4096];
|
byte[] buffer = new byte[4096];
|
||||||
int read;
|
int read;
|
||||||
|
|
||||||
@ -175,6 +194,7 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output.close();
|
output.close();
|
||||||
|
Log.w("PushServiceSocket", "Downloaded: " + url + " to: " + localDestination.getAbsolutePath());
|
||||||
} finally {
|
} finally {
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
}
|
}
|
||||||
@ -205,7 +225,7 @@ public class PushServiceSocket {
|
|||||||
|
|
||||||
private Pair<String, String> makeRequestForResponseHeader(String urlFragment, String method,
|
private Pair<String, String> makeRequestForResponseHeader(String urlFragment, String method,
|
||||||
String body, String responseHeader)
|
String body, String responseHeader)
|
||||||
throws IOException, RateLimitException
|
throws IOException
|
||||||
{
|
{
|
||||||
HttpURLConnection connection = makeBaseRequest(urlFragment, method, body);
|
HttpURLConnection connection = makeBaseRequest(urlFragment, method, body);
|
||||||
String response = Util.readFully(connection.getInputStream());
|
String response = Util.readFully(connection.getInputStream());
|
||||||
@ -216,7 +236,7 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String makeRequest(String urlFragment, String method, String body)
|
private String makeRequest(String urlFragment, String method, String body)
|
||||||
throws IOException, RateLimitException
|
throws IOException
|
||||||
{
|
{
|
||||||
HttpURLConnection connection = makeBaseRequest(urlFragment, method, body);
|
HttpURLConnection connection = makeBaseRequest(urlFragment, method, body);
|
||||||
String response = Util.readFully(connection.getInputStream());
|
String response = Util.readFully(connection.getInputStream());
|
||||||
@ -227,7 +247,7 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private HttpURLConnection makeBaseRequest(String urlFragment, String method, String body)
|
private HttpURLConnection makeBaseRequest(String urlFragment, String method, String body)
|
||||||
throws IOException, RateLimitException
|
throws IOException
|
||||||
{
|
{
|
||||||
HttpURLConnection connection = getConnection(urlFragment, method);
|
HttpURLConnection connection = getConnection(urlFragment, method);
|
||||||
|
|
||||||
@ -314,7 +334,7 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GcmRegistrationId {
|
private static class GcmRegistrationId {
|
||||||
private String gcmRegistrationId;
|
private String gcmRegistrationId;
|
||||||
|
|
||||||
public GcmRegistrationId() {}
|
public GcmRegistrationId() {}
|
||||||
@ -324,10 +344,10 @@ public class PushServiceSocket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AttachmentDescriptor {
|
private static class AttachmentKey {
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
public AttachmentDescriptor(String id) {
|
public AttachmentKey(String id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package org.whispersystems.textsecure.push;
|
package org.whispersystems.textsecure.push;
|
||||||
|
|
||||||
|
|
||||||
public class RateLimitException extends Exception {
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class RateLimitException extends IOException {
|
||||||
public RateLimitException(String s) {
|
public RateLimitException(String s) {
|
||||||
super(s);
|
super(s);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class Util {
|
public class Util {
|
||||||
public static boolean isEmpty(String value) {
|
public static boolean isEmpty(String value) {
|
||||||
@ -55,4 +57,18 @@ public class Util {
|
|||||||
|
|
||||||
return new String(bout.toByteArray());
|
return new String(bout.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String join(Collection<String> list, String delimiter) {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
for (String item : list) {
|
||||||
|
result.append(item);
|
||||||
|
|
||||||
|
if (++i < list.size())
|
||||||
|
result.append(delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|||||||
import org.thoughtcrime.securesms.util.Trimmer;
|
import org.thoughtcrime.securesms.util.Trimmer;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.textsecure.push.PushServiceSocket;
|
import org.whispersystems.textsecure.push.PushServiceSocket;
|
||||||
import org.whispersystems.textsecure.push.RateLimitException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -361,9 +360,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredSherlockPr
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w("ApplicationPreferencesActivity", e);
|
Log.w("ApplicationPreferencesActivity", e);
|
||||||
return NETWORK_ERROR;
|
return NETWORK_ERROR;
|
||||||
} catch (RateLimitException e) {
|
|
||||||
Log.w("ApplicationPreferencesActivity", e);
|
|
||||||
return NETWORK_ERROR;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
|
@ -452,12 +452,12 @@ public class RegistrationProgressActivity extends SherlockActivity {
|
|||||||
PushServiceSocket socket = new PushServiceSocket(context, e164number, password);
|
PushServiceSocket socket = new PushServiceSocket(context, e164number, password);
|
||||||
socket.verifyAccount(code);
|
socket.verifyAccount(code);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w("RegistrationProgressActivity", e);
|
|
||||||
return NETWORK_ERROR;
|
|
||||||
} catch (RateLimitException e) {
|
} catch (RateLimitException e) {
|
||||||
Log.w("RegistrationProgressActivity", e);
|
Log.w("RegistrationProgressActivity", e);
|
||||||
return RATE_LIMIT_ERROR;
|
return RATE_LIMIT_ERROR;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w("RegistrationProgressActivity", e);
|
||||||
|
return NETWORK_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
@ -539,12 +539,12 @@ public class RegistrationProgressActivity extends SherlockActivity {
|
|||||||
socket.createAccount(true);
|
socket.createAccount(true);
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
} catch (IOException e) {
|
|
||||||
Log.w("RegistrationProgressActivity", e);
|
|
||||||
return NETWORK_ERROR;
|
|
||||||
} catch (RateLimitException e) {
|
} catch (RateLimitException e) {
|
||||||
Log.w("RegistrationProgressActivity", e);
|
Log.w("RegistrationProgressActivity", e);
|
||||||
return RATE_LIMIT_EXCEEDED;
|
return RATE_LIMIT_EXCEEDED;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w("RegistrationProgressActivity", e);
|
||||||
|
return NETWORK_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
|
@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.TextTransport;
|
import org.thoughtcrime.securesms.mms.TextTransport;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
@ -212,7 +213,7 @@ public class DecryptingQueue {
|
|||||||
RetrieveConf plaintextPdu = new RetrieveConf(plaintextGenericPdu.getPduHeaders(),
|
RetrieveConf plaintextPdu = new RetrieveConf(plaintextGenericPdu.getPduHeaders(),
|
||||||
plaintextGenericPdu.getBody());
|
plaintextGenericPdu.getBody());
|
||||||
Log.w("DecryptingQueue", "Successfully decrypted MMS!");
|
Log.w("DecryptingQueue", "Successfully decrypted MMS!");
|
||||||
database.insertSecureDecryptedMessageInbox(masterSecret, plaintextPdu, threadId);
|
database.insertSecureDecryptedMessageInbox(masterSecret, new IncomingMediaMessage(plaintextPdu), threadId);
|
||||||
database.delete(messageId);
|
database.delete(messageId);
|
||||||
} catch (RecipientFormattingException rfe) {
|
} catch (RecipientFormattingException rfe) {
|
||||||
Log.w("DecryptingQueue", rfe);
|
Log.w("DecryptingQueue", rfe);
|
||||||
|
@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
|||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.PartParser;
|
import org.thoughtcrime.securesms.mms.PartParser;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.mms.TextSlide;
|
import org.thoughtcrime.securesms.mms.TextSlide;
|
||||||
@ -59,11 +60,9 @@ import ws.com.google.android.mms.InvalidHeaderValueException;
|
|||||||
import ws.com.google.android.mms.MmsException;
|
import ws.com.google.android.mms.MmsException;
|
||||||
import ws.com.google.android.mms.pdu.CharacterSets;
|
import ws.com.google.android.mms.pdu.CharacterSets;
|
||||||
import ws.com.google.android.mms.pdu.EncodedStringValue;
|
import ws.com.google.android.mms.pdu.EncodedStringValue;
|
||||||
import ws.com.google.android.mms.pdu.MultimediaMessagePdu;
|
|
||||||
import ws.com.google.android.mms.pdu.NotificationInd;
|
import ws.com.google.android.mms.pdu.NotificationInd;
|
||||||
import ws.com.google.android.mms.pdu.PduBody;
|
import ws.com.google.android.mms.pdu.PduBody;
|
||||||
import ws.com.google.android.mms.pdu.PduHeaders;
|
import ws.com.google.android.mms.pdu.PduHeaders;
|
||||||
import ws.com.google.android.mms.pdu.RetrieveConf;
|
|
||||||
import ws.com.google.android.mms.pdu.SendReq;
|
import ws.com.google.android.mms.pdu.SendReq;
|
||||||
|
|
||||||
// XXXX Clean up MMS efficiency:
|
// XXXX Clean up MMS efficiency:
|
||||||
@ -177,27 +176,23 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getThreadIdFor(RetrieveConf retrieved) throws RecipientFormattingException {
|
private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException {
|
||||||
try {
|
try {
|
||||||
|
PduHeaders headers = retrieved.getPduHeaders();
|
||||||
Set<String> group = new HashSet<String>();
|
Set<String> group = new HashSet<String>();
|
||||||
|
|
||||||
EncodedStringValue encodedFrom = retrieved.getFrom();
|
EncodedStringValue encodedFrom = headers.getEncodedStringValue(PduHeaders.FROM);
|
||||||
group.add(new String(encodedFrom.getTextString(), CharacterSets.MIMENAME_ISO_8859_1));
|
group.add(new String(encodedFrom.getTextString(), CharacterSets.MIMENAME_ISO_8859_1));
|
||||||
|
|
||||||
EncodedStringValue[] encodedCcList = retrieved.getCc();
|
EncodedStringValue[] encodedCcList = headers.getEncodedStringValues(PduHeaders.CC);
|
||||||
if (encodedCcList != null) {
|
if (encodedCcList != null) {
|
||||||
for (EncodedStringValue encodedCc : encodedCcList) {
|
for (EncodedStringValue encodedCc : encodedCcList) {
|
||||||
group.add(new String(encodedCc.getTextString(), CharacterSets.MIMENAME_ISO_8859_1));
|
group.add(new String(encodedCc.getTextString(), CharacterSets.MIMENAME_ISO_8859_1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
String recipientsList = Util.join(group, ",");
|
||||||
for (String recipient : group) {
|
Recipients recipients = RecipientFactory.getRecipientsFromString(context, recipientsList, false);
|
||||||
sb.append(recipient);
|
|
||||||
sb.append(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, sb.toString(), false);
|
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
@ -280,7 +275,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(READ, 1);
|
contentValues.put(READ, 1);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, THREAD_ID + " = ?", new String[] {threadId+""});
|
database.update(TABLE_NAME, contentValues, THREAD_ID + " = ?", new String[] {threadId + ""});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAllMessagesRead() {
|
public void setAllMessagesRead() {
|
||||||
@ -359,7 +354,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
return new Reader(masterSecret, cursor);
|
return new Reader(masterSecret, cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<Long, Long> insertMessageInbox(MasterSecret masterSecret, RetrieveConf retrieved,
|
private Pair<Long, Long> insertMessageInbox(MasterSecret masterSecret, IncomingMediaMessage retrieved,
|
||||||
String contentLocation, long threadId, long mailbox)
|
String contentLocation, long threadId, long mailbox)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
@ -367,11 +362,13 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
ContentValues contentValues = getContentValuesFromHeader(headers);
|
ContentValues contentValues = getContentValuesFromHeader(headers);
|
||||||
boolean unread = Util.isDefaultSmsProvider(context) || ((mailbox & Types.SECURE_MESSAGE_BIT) != 0);
|
boolean unread = Util.isDefaultSmsProvider(context) || ((mailbox & Types.SECURE_MESSAGE_BIT) != 0);
|
||||||
|
|
||||||
if (!org.thoughtcrime.securesms.util.Util.isEmpty(retrieved.getCc())) {
|
if (threadId == -1 || retrieved.isGroupMessage()) {
|
||||||
try {
|
try {
|
||||||
threadId = getThreadIdFor(retrieved);
|
threadId = getThreadIdFor(retrieved);
|
||||||
} catch (RecipientFormattingException e) {
|
} catch (RecipientFormattingException e) {
|
||||||
Log.w("MmsDatabase", e);
|
Log.w("MmsDatabase", e);
|
||||||
|
if (threadId == -1)
|
||||||
|
throw new MmsException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,10 +379,12 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis() / 1000);
|
contentValues.put(DATE_RECEIVED, System.currentTimeMillis() / 1000);
|
||||||
contentValues.put(READ, unread ? 0 : 1);
|
contentValues.put(READ, unread ? 0 : 1);
|
||||||
|
|
||||||
if (!contentValues.containsKey(DATE_SENT))
|
if (!contentValues.containsKey(DATE_SENT)) {
|
||||||
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
|
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
|
||||||
|
}
|
||||||
|
|
||||||
long messageId = insertMediaMessage(masterSecret, retrieved, contentValues);
|
long messageId = insertMediaMessage(masterSecret, retrieved.getPduHeaders(),
|
||||||
|
retrieved.getBody(), contentValues);
|
||||||
|
|
||||||
if (unread) {
|
if (unread) {
|
||||||
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
||||||
@ -398,7 +397,8 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
return new Pair<Long, Long>(messageId, threadId);
|
return new Pair<Long, Long>(messageId, threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<Long, Long> insertMessageInbox(MasterSecret masterSecret, RetrieveConf retrieved,
|
public Pair<Long, Long> insertMessageInbox(MasterSecret masterSecret,
|
||||||
|
IncomingMediaMessage retrieved,
|
||||||
String contentLocation, long threadId)
|
String contentLocation, long threadId)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
@ -406,7 +406,8 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
Types.BASE_INBOX_TYPE | Types.ENCRYPTION_SYMMETRIC_BIT);
|
Types.BASE_INBOX_TYPE | Types.ENCRYPTION_SYMMETRIC_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pair<Long, Long> insertSecureMessageInbox(MasterSecret masterSecret, RetrieveConf retrieved,
|
public Pair<Long, Long> insertSecureMessageInbox(MasterSecret masterSecret,
|
||||||
|
IncomingMediaMessage retrieved,
|
||||||
String contentLocation, long threadId)
|
String contentLocation, long threadId)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
@ -415,7 +416,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Pair<Long, Long> insertSecureDecryptedMessageInbox(MasterSecret masterSecret,
|
public Pair<Long, Long> insertSecureDecryptedMessageInbox(MasterSecret masterSecret,
|
||||||
RetrieveConf retrieved,
|
IncomingMediaMessage retrieved,
|
||||||
long threadId)
|
long threadId)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
@ -425,11 +426,11 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
|
|
||||||
public Pair<Long, Long> insertMessageInbox(NotificationInd notification) {
|
public Pair<Long, Long> insertMessageInbox(NotificationInd notification) {
|
||||||
try {
|
try {
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
PduHeaders headers = notification.getPduHeaders();
|
|
||||||
ContentValues contentValues = getContentValuesFromHeader(headers);
|
|
||||||
long threadId = getThreadIdFor(notification);
|
|
||||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||||
|
long threadId = getThreadIdFor(notification);
|
||||||
|
PduHeaders headers = notification.getPduHeaders();
|
||||||
|
ContentValues contentValues = getContentValuesFromHeader(headers);
|
||||||
|
|
||||||
Log.w("MmsDatabse", "Message received type: " + headers.getOctet(PduHeaders.MESSAGE_TYPE));
|
Log.w("MmsDatabse", "Message received type: " + headers.getOctet(PduHeaders.MESSAGE_TYPE));
|
||||||
|
|
||||||
@ -486,21 +487,22 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
|
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
|
||||||
contentValues.remove(ADDRESS);
|
contentValues.remove(ADDRESS);
|
||||||
|
|
||||||
long messageId = insertMediaMessage(masterSecret, sendRequest, contentValues);
|
long messageId = insertMediaMessage(masterSecret, sendRequest.getPduHeaders(),
|
||||||
|
sendRequest.getBody(), contentValues);
|
||||||
Trimmer.trimThread(context, threadId);
|
Trimmer.trimThread(context, threadId);
|
||||||
|
|
||||||
return messageId;
|
return messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertMediaMessage(MasterSecret masterSecret,
|
private long insertMediaMessage(MasterSecret masterSecret,
|
||||||
MultimediaMessagePdu message,
|
PduHeaders headers,
|
||||||
|
PduBody body,
|
||||||
ContentValues contentValues)
|
ContentValues contentValues)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
PartDatabase partsDatabase = getPartDatabase(masterSecret);
|
PartDatabase partsDatabase = getPartDatabase(masterSecret);
|
||||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||||
PduBody body = message.getBody();
|
|
||||||
|
|
||||||
if (Types.isSymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX))) {
|
if (Types.isSymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX))) {
|
||||||
String messageText = PartParser.getMessageText(body);
|
String messageText = PartParser.getMessageText(body);
|
||||||
@ -515,7 +517,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
|||||||
|
|
||||||
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
||||||
|
|
||||||
addressDatabase.insertAddressesForId(messageId, message.getPduHeaders());
|
addressDatabase.insertAddressesForId(messageId, headers);
|
||||||
partsDatabase.insertParts(messageId, body);
|
partsDatabase.insertParts(messageId, body);
|
||||||
|
|
||||||
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
|
||||||
|
@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.service.RegistrationService;
|
|||||||
import org.thoughtcrime.securesms.service.SendReceiveService;
|
import org.thoughtcrime.securesms.service.SendReceiveService;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.textsecure.push.IncomingGcmMessage;
|
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||||
import org.whispersystems.textsecure.push.PushServiceSocket;
|
import org.whispersystems.textsecure.push.PushServiceSocket;
|
||||||
import org.whispersystems.textsecure.push.RateLimitException;
|
import org.whispersystems.textsecure.push.RateLimitException;
|
||||||
import org.whispersystems.textsecure.util.Util;
|
import org.whispersystems.textsecure.util.Util;
|
||||||
@ -33,8 +33,6 @@ public class GcmIntentService extends GCMBaseIntentService {
|
|||||||
getGcmSocket(context).registerGcmId(registrationId);
|
getGcmSocket(context).registerGcmId(registrationId);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w("GcmIntentService", e);
|
Log.w("GcmIntentService", e);
|
||||||
} catch (RateLimitException e) {
|
|
||||||
Log.w("GcmIntentService", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,22 +43,30 @@ public class GcmIntentService extends GCMBaseIntentService {
|
|||||||
getGcmSocket(context).unregisterGcmId();
|
getGcmSocket(context).unregisterGcmId();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w("GcmIntentService", ioe);
|
Log.w("GcmIntentService", ioe);
|
||||||
} catch (RateLimitException e) {
|
|
||||||
Log.w("GcmIntentService", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMessage(Context context, Intent intent) {
|
protected void onMessage(Context context, Intent intent) {
|
||||||
Log.w("GcmIntentService", "Got GCM message!");
|
|
||||||
String data = intent.getStringExtra("message");
|
String data = intent.getStringExtra("message");
|
||||||
Log.w("GcmIntentService", "GCM message: " + data);
|
Log.w("GcmIntentService", "GCM message: " + data);
|
||||||
|
|
||||||
if (Util.isEmpty(data))
|
if (Util.isEmpty(data))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IncomingGcmMessage message = new Gson().fromJson(data, IncomingGcmMessage.class);
|
IncomingPushMessage message = new Gson().fromJson(data, IncomingPushMessage.class);
|
||||||
|
|
||||||
|
if (!message.hasAttachments()) handleIncomingTextMessage(context, message);
|
||||||
|
else handleIncomingMediaMessage(context, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onError(Context context, String s) {
|
||||||
|
Log.w("GcmIntentService", "GCM Error: " + s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleIncomingTextMessage(Context context, IncomingPushMessage message) {
|
||||||
ArrayList<IncomingTextMessage> messages = new ArrayList<IncomingTextMessage>();
|
ArrayList<IncomingTextMessage> messages = new ArrayList<IncomingTextMessage>();
|
||||||
messages.add(new IncomingTextMessage(message));
|
messages.add(new IncomingTextMessage(message));
|
||||||
|
|
||||||
@ -70,9 +76,11 @@ public class GcmIntentService extends GCMBaseIntentService {
|
|||||||
context.startService(receivedIntent);
|
context.startService(receivedIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void handleIncomingMediaMessage(Context context, IncomingPushMessage message) {
|
||||||
protected void onError(Context context, String s) {
|
Intent receivedIntent = new Intent(context, SendReceiveService.class);
|
||||||
Log.w("GcmIntentService", "GCM Error: " + s);
|
receivedIntent.setAction(SendReceiveService.RECEIVE_PUSH_MMS_ACTION);
|
||||||
|
receivedIntent.putExtra("media_message", message);
|
||||||
|
context.startService(receivedIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PushServiceSocket getGcmSocket(Context context) {
|
private PushServiceSocket getGcmSocket(Context context) {
|
||||||
|
86
src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java
Normal file
86
src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package org.thoughtcrime.securesms.mms;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||||
|
import org.whispersystems.textsecure.push.PushAttachmentPointer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ws.com.google.android.mms.pdu.CharacterSets;
|
||||||
|
import ws.com.google.android.mms.pdu.EncodedStringValue;
|
||||||
|
import ws.com.google.android.mms.pdu.PduBody;
|
||||||
|
import ws.com.google.android.mms.pdu.PduHeaders;
|
||||||
|
import ws.com.google.android.mms.pdu.PduPart;
|
||||||
|
import ws.com.google.android.mms.pdu.RetrieveConf;
|
||||||
|
|
||||||
|
public class IncomingMediaMessage {
|
||||||
|
|
||||||
|
private final PduHeaders headers;
|
||||||
|
private final PduBody body;
|
||||||
|
|
||||||
|
public IncomingMediaMessage(RetrieveConf retreived) {
|
||||||
|
this.headers = retreived.getPduHeaders();
|
||||||
|
this.body = retreived.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncomingMediaMessage(String localNumber, IncomingPushMessage message, List<File> attachments)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
this.headers = new PduHeaders();
|
||||||
|
this.body = new PduBody();
|
||||||
|
|
||||||
|
this.headers.setEncodedStringValue(new EncodedStringValue(message.getSource()), PduHeaders.FROM);
|
||||||
|
this.headers.appendEncodedStringValue(new EncodedStringValue(localNumber), PduHeaders.TO);
|
||||||
|
|
||||||
|
for (String destination : message.getDestinations()) {
|
||||||
|
if (!destination.equals(localNumber)) {
|
||||||
|
this.headers.appendEncodedStringValue(new EncodedStringValue(destination), PduHeaders.CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.headers.setLongInteger(message.getTimestampMillis() / 1000, PduHeaders.DATE);
|
||||||
|
|
||||||
|
if (message.getMessageText() != null && message.getMessageText().length() > 0) {
|
||||||
|
PduPart text = new PduPart();
|
||||||
|
text.setData(message.getMessageText().getBytes());
|
||||||
|
text.setContentType("text/plain".getBytes(CharacterSets.MIMENAME_ISO_8859_1));
|
||||||
|
body.addPart(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<PushAttachmentPointer> descriptors = message.getAttachments().iterator();
|
||||||
|
|
||||||
|
if (attachments != null) {
|
||||||
|
for (File attachment : attachments) {
|
||||||
|
PduPart media = new PduPart();
|
||||||
|
FileInputStream fin = new FileInputStream(attachment);
|
||||||
|
byte[] data = Util.readFully(fin);
|
||||||
|
PushAttachmentPointer descriptor = descriptors.next();
|
||||||
|
|
||||||
|
Log.w("IncomingMediaMessage", "Adding part: " + descriptor.getContentType() + " with length: " + data.length);
|
||||||
|
|
||||||
|
media.setContentType(descriptor.getContentType().getBytes(CharacterSets.MIMENAME_ISO_8859_1));
|
||||||
|
media.setData(data);
|
||||||
|
body.addPart(media);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PduHeaders getPduHeaders() {
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PduBody getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGroupMessage() {
|
||||||
|
return !Util.isEmpty(headers.getEncodedStringValues(PduHeaders.CC));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
||||||
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.MmsDownloadHelper;
|
import org.thoughtcrime.securesms.mms.MmsDownloadHelper;
|
||||||
import org.thoughtcrime.securesms.mms.MmsRadio;
|
import org.thoughtcrime.securesms.mms.MmsRadio;
|
||||||
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
||||||
@ -177,11 +178,13 @@ public class MmsDownloader {
|
|||||||
long messageId, long threadId, RetrieveConf retrieved)
|
long messageId, long threadId, RetrieveConf retrieved)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||||
|
IncomingMediaMessage message = new IncomingMediaMessage(retrieved);
|
||||||
|
|
||||||
Pair<Long, Long> messageAndThreadId;
|
Pair<Long, Long> messageAndThreadId;
|
||||||
|
|
||||||
if (retrieved.getSubject() != null && WirePrefix.isEncryptedMmsSubject(retrieved.getSubject().getString())) {
|
if (retrieved.getSubject() != null && WirePrefix.isEncryptedMmsSubject(retrieved.getSubject().getString())) {
|
||||||
messageAndThreadId = database.insertSecureMessageInbox(masterSecret, retrieved,
|
messageAndThreadId = database.insertSecureMessageInbox(masterSecret, message,
|
||||||
contentLocation, threadId);
|
contentLocation, threadId);
|
||||||
|
|
||||||
if (masterSecret != null)
|
if (masterSecret != null)
|
||||||
@ -189,7 +192,7 @@ public class MmsDownloader {
|
|||||||
messageAndThreadId.second, retrieved);
|
messageAndThreadId.second, retrieved);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
messageAndThreadId = database.insertMessageInbox(masterSecret, retrieved,
|
messageAndThreadId = database.insertMessageInbox(masterSecret, message,
|
||||||
contentLocation, threadId);
|
contentLocation, threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,17 @@ import android.util.Pair;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||||
|
import org.whispersystems.textsecure.push.PushServiceSocket;
|
||||||
|
import org.whispersystems.textsecure.push.RateLimitException;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ws.com.google.android.mms.MmsException;
|
||||||
import ws.com.google.android.mms.pdu.GenericPdu;
|
import ws.com.google.android.mms.pdu.GenericPdu;
|
||||||
import ws.com.google.android.mms.pdu.NotificationInd;
|
import ws.com.google.android.mms.pdu.NotificationInd;
|
||||||
import ws.com.google.android.mms.pdu.PduHeaders;
|
import ws.com.google.android.mms.pdu.PduHeaders;
|
||||||
@ -39,6 +48,54 @@ public class MmsReceiver {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void process(MasterSecret masterSecret, Intent intent) {
|
||||||
|
try {
|
||||||
|
if (intent.getAction().equals(SendReceiveService.RECEIVE_MMS_ACTION)) {
|
||||||
|
handleMmsNotification(intent);
|
||||||
|
} else if (intent.getAction().equals(SendReceiveService.RECEIVE_PUSH_MMS_ACTION)) {
|
||||||
|
handlePushMedia(masterSecret, intent);
|
||||||
|
}
|
||||||
|
} catch (MmsException e) {
|
||||||
|
Log.w("MmsReceiver", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMmsNotification(Intent intent) {
|
||||||
|
byte[] mmsData = intent.getByteArrayExtra("data");
|
||||||
|
PduParser parser = new PduParser(mmsData);
|
||||||
|
GenericPdu pdu = parser.parse();
|
||||||
|
|
||||||
|
if (pdu.getMessageType() == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) {
|
||||||
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||||
|
Pair<Long, Long> messageAndThreadId = database.insertMessageInbox((NotificationInd)pdu);
|
||||||
|
|
||||||
|
Log.w("MmsReceiver", "Inserted received MMS notification...");
|
||||||
|
scheduleDownload((NotificationInd)pdu, messageAndThreadId.first, messageAndThreadId.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handlePushMedia(MasterSecret masterSecret, Intent intent) throws MmsException {
|
||||||
|
IncomingPushMessage pushMessage = intent.getParcelableExtra("media_message");
|
||||||
|
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||||
|
String password = TextSecurePreferences.getPushServerPassword(context);
|
||||||
|
PushServiceSocket socket = new PushServiceSocket(context, localNumber, password);
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<File> attachments = socket.retrieveAttachments(pushMessage.getAttachments());
|
||||||
|
IncomingMediaMessage message = new IncomingMediaMessage(localNumber, pushMessage, attachments);
|
||||||
|
|
||||||
|
DatabaseFactory.getMmsDatabase(context).insertMessageInbox(masterSecret, message, "", -1);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w("MmsReceiver", e);
|
||||||
|
try {
|
||||||
|
IncomingMediaMessage message = new IncomingMediaMessage(localNumber, pushMessage, null);
|
||||||
|
DatabaseFactory.getMmsDatabase(context).insertMessageInbox(masterSecret, message, "", -1);
|
||||||
|
} catch (IOException e1) {
|
||||||
|
throw new MmsException(e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void scheduleDownload(NotificationInd pdu, long messageId, long threadId) {
|
private void scheduleDownload(NotificationInd pdu, long messageId, long threadId) {
|
||||||
Intent intent = new Intent(SendReceiveService.DOWNLOAD_MMS_ACTION, null, context, SendReceiveService.class);
|
Intent intent = new Intent(SendReceiveService.DOWNLOAD_MMS_ACTION, null, context, SendReceiveService.class);
|
||||||
intent.putExtra("content_location", new String(pdu.getContentLocation()));
|
intent.putExtra("content_location", new String(pdu.getContentLocation()));
|
||||||
@ -50,21 +107,4 @@ public class MmsReceiver {
|
|||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void process(MasterSecret masterSecret, Intent intent) {
|
|
||||||
byte[] mmsData = intent.getByteArrayExtra("data");
|
|
||||||
PduParser parser = new PduParser(mmsData);
|
|
||||||
GenericPdu pdu = parser.parse();
|
|
||||||
|
|
||||||
if (pdu.getMessageType() == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) {
|
|
||||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
|
||||||
Pair<Long, Long> messageAndThreadId = database.insertMessageInbox((NotificationInd)pdu);
|
|
||||||
// long threadId = database.getThreadIdForMessage(messageId);
|
|
||||||
|
|
||||||
// MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
|
|
||||||
scheduleDownload((NotificationInd)pdu, messageAndThreadId.first, messageAndThreadId.second);
|
|
||||||
|
|
||||||
Log.w("MmsReceiverService", "Inserted received notification...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,24 +5,23 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.SharedPreferences.Editor;
|
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.google.android.gcm.GCMRegistrar;
|
import com.google.android.gcm.GCMRegistrar;
|
||||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.gcm.GcmIntentService;
|
import org.thoughtcrime.securesms.gcm.GcmIntentService;
|
||||||
import org.thoughtcrime.securesms.gcm.GcmRegistrationTimeoutException;
|
import org.thoughtcrime.securesms.gcm.GcmRegistrationTimeoutException;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
import org.whispersystems.textsecure.directory.DirectoryDescriptor;
|
||||||
|
import org.whispersystems.textsecure.directory.NumberFilter;
|
||||||
import org.whispersystems.textsecure.push.PushServiceSocket;
|
import org.whispersystems.textsecure.push.PushServiceSocket;
|
||||||
import org.whispersystems.textsecure.push.RateLimitException;
|
|
||||||
import org.whispersystems.textsecure.util.Util;
|
import org.whispersystems.textsecure.util.Util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -172,7 +171,8 @@ public class RegistrationService extends Service {
|
|||||||
String gcmRegistrationId = waitForGcmRegistrationId();
|
String gcmRegistrationId = waitForGcmRegistrationId();
|
||||||
|
|
||||||
socket.registerGcmId(gcmRegistrationId);
|
socket.registerGcmId(gcmRegistrationId);
|
||||||
socket.retrieveDirectory(this);
|
Pair<DirectoryDescriptor, File> directory = socket.retrieveDirectory();
|
||||||
|
NumberFilter.getInstance(this).update(directory.first, directory.second);
|
||||||
|
|
||||||
markAsVerified(number, password);
|
markAsVerified(number, password);
|
||||||
|
|
||||||
@ -190,10 +190,6 @@ public class RegistrationService extends Service {
|
|||||||
Log.w("RegistrationService", e);
|
Log.w("RegistrationService", e);
|
||||||
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
|
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
|
||||||
broadcastComplete(false);
|
broadcastComplete(false);
|
||||||
} catch (RateLimitException e) {
|
|
||||||
Log.w("RegistrationService", e);
|
|
||||||
setState(new RegistrationState(RegistrationState.STATE_NETWORK_ERROR));
|
|
||||||
broadcastComplete(false);
|
|
||||||
} finally {
|
} finally {
|
||||||
shutdownGcmRegistrationListener();
|
shutdownGcmRegistrationListener();
|
||||||
}
|
}
|
||||||
@ -222,7 +218,8 @@ public class RegistrationService extends Service {
|
|||||||
String gcmRegistrationId = waitForGcmRegistrationId();
|
String gcmRegistrationId = waitForGcmRegistrationId();
|
||||||
|
|
||||||
socket.registerGcmId(gcmRegistrationId);
|
socket.registerGcmId(gcmRegistrationId);
|
||||||
socket.retrieveDirectory(this);
|
Pair<DirectoryDescriptor, File> directory = socket.retrieveDirectory();
|
||||||
|
NumberFilter.getInstance(this).update(directory.first, directory.second);
|
||||||
|
|
||||||
markAsVerified(number, password);
|
markAsVerified(number, password);
|
||||||
|
|
||||||
@ -244,10 +241,6 @@ public class RegistrationService extends Service {
|
|||||||
Log.w("RegistrationService", e);
|
Log.w("RegistrationService", e);
|
||||||
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
|
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
|
||||||
broadcastComplete(false);
|
broadcastComplete(false);
|
||||||
} catch (RateLimitException e) {
|
|
||||||
Log.w("RegistrationService", e);
|
|
||||||
setState(new RegistrationState(RegistrationState.STATE_NETWORK_ERROR));
|
|
||||||
broadcastComplete(false);
|
|
||||||
} finally {
|
} finally {
|
||||||
shutdownChallengeListener();
|
shutdownChallengeListener();
|
||||||
shutdownGcmRegistrationListener();
|
shutdownGcmRegistrationListener();
|
||||||
|
@ -51,6 +51,7 @@ public class SendReceiveService extends Service {
|
|||||||
public static final String RECEIVE_SMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.RECEIVE_SMS_ACTION";
|
public static final String RECEIVE_SMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.RECEIVE_SMS_ACTION";
|
||||||
public static final String SEND_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.SEND_MMS_ACTION";
|
public static final String SEND_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.SEND_MMS_ACTION";
|
||||||
public static final String RECEIVE_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.RECEIVE_MMS_ACTION";
|
public static final String RECEIVE_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.RECEIVE_MMS_ACTION";
|
||||||
|
public static final String RECEIVE_PUSH_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.RECEIVE_PUSH_MMS_ACTION";
|
||||||
public static final String DOWNLOAD_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_ACTION";
|
public static final String DOWNLOAD_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_ACTION";
|
||||||
public static final String DOWNLOAD_MMS_CONNECTIVITY_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_CONNECTIVITY_ACTION";
|
public static final String DOWNLOAD_MMS_CONNECTIVITY_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_CONNECTIVITY_ACTION";
|
||||||
public static final String DOWNLOAD_MMS_PENDING_APN_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_PENDING_APN_ACTION";
|
public static final String DOWNLOAD_MMS_PENDING_APN_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_PENDING_APN_ACTION";
|
||||||
@ -92,19 +93,21 @@ public class SendReceiveService extends Service {
|
|||||||
public void onStart(Intent intent, int startId) {
|
public void onStart(Intent intent, int startId) {
|
||||||
if (intent == null) return;
|
if (intent == null) return;
|
||||||
|
|
||||||
if (intent.getAction().equals(SEND_SMS_ACTION))
|
String action = intent.getAction();
|
||||||
|
|
||||||
|
if (action.equals(SEND_SMS_ACTION))
|
||||||
scheduleSecretRequiredIntent(SEND_SMS, intent);
|
scheduleSecretRequiredIntent(SEND_SMS, intent);
|
||||||
else if (intent.getAction().equals(RECEIVE_SMS_ACTION))
|
else if (action.equals(RECEIVE_SMS_ACTION))
|
||||||
scheduleIntent(RECEIVE_SMS, intent);
|
scheduleIntent(RECEIVE_SMS, intent);
|
||||||
else if (intent.getAction().equals(SENT_SMS_ACTION))
|
else if (action.equals(SENT_SMS_ACTION))
|
||||||
scheduleIntent(SEND_SMS, intent);
|
scheduleIntent(SEND_SMS, intent);
|
||||||
else if (intent.getAction().equals(DELIVERED_SMS_ACTION))
|
else if (action.equals(DELIVERED_SMS_ACTION))
|
||||||
scheduleIntent(SEND_SMS, intent);
|
scheduleIntent(SEND_SMS, intent);
|
||||||
else if (intent.getAction().equals(SEND_MMS_ACTION))
|
else if (action.equals(SEND_MMS_ACTION))
|
||||||
scheduleSecretRequiredIntent(SEND_MMS, intent);
|
scheduleSecretRequiredIntent(SEND_MMS, intent);
|
||||||
else if (intent.getAction().equals(RECEIVE_MMS_ACTION))
|
else if (action.equals(RECEIVE_MMS_ACTION) || action.equals(RECEIVE_PUSH_MMS_ACTION))
|
||||||
scheduleIntent(RECEIVE_MMS, intent);
|
scheduleIntent(RECEIVE_MMS, intent);
|
||||||
else if (intent.getAction().equals(DOWNLOAD_MMS_ACTION))
|
else if (action.equals(DOWNLOAD_MMS_ACTION))
|
||||||
scheduleSecretRequiredIntent(DOWNLOAD_MMS, intent);
|
scheduleSecretRequiredIntent(DOWNLOAD_MMS, intent);
|
||||||
else if (intent.getAction().equals(DOWNLOAD_MMS_PENDING_APN_ACTION))
|
else if (intent.getAction().equals(DOWNLOAD_MMS_PENDING_APN_ACTION))
|
||||||
scheduleSecretRequiredIntent(DOWNLOAD_MMS_PENDING, intent);
|
scheduleSecretRequiredIntent(DOWNLOAD_MMS_PENDING, intent);
|
||||||
|
@ -4,7 +4,7 @@ import android.os.Parcel;
|
|||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.telephony.SmsMessage;
|
import android.telephony.SmsMessage;
|
||||||
|
|
||||||
import org.whispersystems.textsecure.push.IncomingGcmMessage;
|
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ public class IncomingTextMessage implements Parcelable {
|
|||||||
this.sentTimestampMillis = message.getTimestampMillis();
|
this.sentTimestampMillis = message.getTimestampMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingTextMessage(IncomingGcmMessage message) {
|
public IncomingTextMessage(IncomingPushMessage message) {
|
||||||
this.message = message.getMessageText();
|
this.message = message.getMessageText();
|
||||||
this.sender = message.getSource();
|
this.sender = message.getSource();
|
||||||
this.protocol = 31337;
|
this.protocol = 31337;
|
||||||
|
@ -8,7 +8,7 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
|||||||
import org.thoughtcrime.securesms.mms.PartParser;
|
import org.thoughtcrime.securesms.mms.PartParser;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.textsecure.push.PushAttachment;
|
import org.whispersystems.textsecure.push.PushAttachmentData;
|
||||||
import org.whispersystems.textsecure.push.PushServiceSocket;
|
import org.whispersystems.textsecure.push.PushServiceSocket;
|
||||||
import org.whispersystems.textsecure.push.RateLimitException;
|
import org.whispersystems.textsecure.push.RateLimitException;
|
||||||
import org.whispersystems.textsecure.util.PhoneNumberFormatter;
|
import org.whispersystems.textsecure.util.PhoneNumberFormatter;
|
||||||
@ -52,11 +52,11 @@ public class PushTransport extends BaseTransport {
|
|||||||
|
|
||||||
public void deliver(SendReq message, List<String> destinations) throws IOException {
|
public void deliver(SendReq message, List<String> destinations) throws IOException {
|
||||||
try {
|
try {
|
||||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||||
String password = TextSecurePreferences.getPushServerPassword(context);
|
String password = TextSecurePreferences.getPushServerPassword(context);
|
||||||
PushServiceSocket socket = new PushServiceSocket(context, localNumber, password);
|
PushServiceSocket socket = new PushServiceSocket(context, localNumber, password);
|
||||||
String messageText = PartParser.getMessageText(message.getBody());
|
String messageText = PartParser.getMessageText(message.getBody());
|
||||||
List<PushAttachment> attachments = getAttachmentsFromBody(message.getBody());
|
List<PushAttachmentData> attachments = getAttachmentsFromBody(message.getBody());
|
||||||
|
|
||||||
if (attachments.isEmpty()) socket.sendMessage(destinations, messageText);
|
if (attachments.isEmpty()) socket.sendMessage(destinations, messageText);
|
||||||
else socket.sendMessage(destinations, messageText, attachments);
|
else socket.sendMessage(destinations, messageText, attachments);
|
||||||
@ -66,8 +66,8 @@ public class PushTransport extends BaseTransport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PushAttachment> getAttachmentsFromBody(PduBody body) {
|
private List<PushAttachmentData> getAttachmentsFromBody(PduBody body) {
|
||||||
List<PushAttachment> attachments = new LinkedList<PushAttachment>();
|
List<PushAttachmentData> attachments = new LinkedList<PushAttachmentData>();
|
||||||
|
|
||||||
for (int i=0;i<body.getPartsNum();i++) {
|
for (int i=0;i<body.getPartsNum();i++) {
|
||||||
String contentType = Util.toIsoString(body.getPart(i).getContentType());
|
String contentType = Util.toIsoString(body.getPart(i).getContentType());
|
||||||
@ -76,7 +76,7 @@ public class PushTransport extends BaseTransport {
|
|||||||
ContentType.isAudioType(contentType) ||
|
ContentType.isAudioType(contentType) ||
|
||||||
ContentType.isVideoType(contentType))
|
ContentType.isVideoType(contentType))
|
||||||
{
|
{
|
||||||
attachments.add(new PushAttachment(contentType, body.getPart(i).getData()));
|
attachments.add(new PushAttachmentData(contentType, body.getPart(i).getData()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,11 @@ import android.provider.Telephony;
|
|||||||
import org.thoughtcrime.securesms.mms.MmsRadio;
|
import org.thoughtcrime.securesms.mms.MmsRadio;
|
||||||
import org.whispersystems.textsecure.util.PhoneNumberFormatter;
|
import org.whispersystems.textsecure.util.PhoneNumberFormatter;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -151,6 +155,19 @@ public class Util {
|
|||||||
return PhoneNumberFormatter.formatNumber(number, localNumber);
|
return PhoneNumberFormatter.formatNumber(number, localNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] readFully(InputStream in) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[4069];
|
||||||
|
|
||||||
|
int read;
|
||||||
|
|
||||||
|
while ((read = in.read(buffer)) != -1) {
|
||||||
|
baos.write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
|
||||||
|
in.close();
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isDefaultSmsProvider(Context context){
|
public static boolean isDefaultSmsProvider(Context context){
|
||||||
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) ||
|
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) ||
|
||||||
|
Loading…
Reference in New Issue
Block a user