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.OutputStream;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
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 {
|
||||
|
||||
private List<String> destinations;
|
||||
private String messageText;
|
||||
private List<String> attachments;
|
||||
private List<String> destinations;
|
||||
private String messageText;
|
||||
private List<PushAttachmentPointer> attachments;
|
||||
|
||||
public OutgoingPushMessage(String destination, String messageText) {
|
||||
this.destinations = new LinkedList<String>();
|
||||
this.attachments = new LinkedList<String>();
|
||||
this.attachments = new LinkedList<PushAttachmentPointer>();
|
||||
this.messageText = messageText;
|
||||
this.destinations.add(destination);
|
||||
}
|
||||
@ -19,11 +19,11 @@ public class OutgoingPushMessage {
|
||||
public OutgoingPushMessage(List<String> destinations, String messageText) {
|
||||
this.destinations = destinations;
|
||||
this.messageText = messageText;
|
||||
this.attachments = new LinkedList<String>();
|
||||
this.attachments = new LinkedList<PushAttachmentPointer>();
|
||||
}
|
||||
|
||||
public OutgoingPushMessage(List<String> destinations, String messageText,
|
||||
List<String> attachments)
|
||||
List<PushAttachmentPointer> attachments)
|
||||
{
|
||||
this.destinations = destinations;
|
||||
this.messageText = messageText;
|
||||
@ -38,7 +38,7 @@ public class OutgoingPushMessage {
|
||||
return messageText;
|
||||
}
|
||||
|
||||
public List<String> getAttachments() {
|
||||
public List<PushAttachmentPointer> getAttachments() {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
package org.whispersystems.textsecure.push;
|
||||
|
||||
public class PushAttachment {
|
||||
public class PushAttachmentData {
|
||||
|
||||
private final String contentType;
|
||||
private final byte[] data;
|
||||
|
||||
public PushAttachment(String contentType, byte[] data) {
|
||||
public PushAttachmentData(String contentType, byte[] data) {
|
||||
this.contentType = contentType;
|
||||
this.data = data;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
public class GcmMessageResponse {
|
||||
public class PushMessageResponse {
|
||||
private List<String> success;
|
||||
private List<String> failure;
|
||||
|
@ -23,8 +23,6 @@ import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
@ -46,11 +44,13 @@ public class PushServiceSocket {
|
||||
private static final String MESSAGE_PATH = "/v1/messages/";
|
||||
private static final String ATTACHMENT_PATH = "/v1/attachments/%s";
|
||||
|
||||
private final Context context;
|
||||
private final String localNumber;
|
||||
private final String password;
|
||||
private final TrustManagerFactory trustManagerFactory;
|
||||
|
||||
public PushServiceSocket(Context context, String localNumber, String password) {
|
||||
this.context = context.getApplicationContext();
|
||||
this.localNumber = localNumber;
|
||||
this.password = password;
|
||||
this.trustManagerFactory = initializeTrustManagerFactory(context);
|
||||
@ -70,54 +70,55 @@ public class PushServiceSocket {
|
||||
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);
|
||||
}
|
||||
|
||||
public void sendMessage(String recipient, String messageText)
|
||||
throws IOException, RateLimitException
|
||||
throws IOException
|
||||
{
|
||||
OutgoingPushMessage message = new OutgoingPushMessage(recipient, messageText);
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
public void sendMessage(List<String> recipients, String messageText)
|
||||
throws IOException, RateLimitException
|
||||
throws IOException
|
||||
{
|
||||
OutgoingPushMessage message = new OutgoingPushMessage(recipients, messageText);
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
public void sendMessage(List<String> recipients, String messageText,
|
||||
List<PushAttachment> attachments)
|
||||
throws IOException, RateLimitException
|
||||
List<PushAttachmentData> attachments)
|
||||
throws IOException
|
||||
{
|
||||
List<String> attachmentIds = sendAttachments(attachments);
|
||||
OutgoingPushMessage message = new OutgoingPushMessage(recipients, messageText, attachmentIds);
|
||||
List<PushAttachmentPointer> attachmentIds = sendAttachments(attachments);
|
||||
OutgoingPushMessage message = new OutgoingPushMessage(recipients, messageText, attachmentIds);
|
||||
sendMessage(message);
|
||||
}
|
||||
|
||||
private void sendMessage(OutgoingPushMessage message) throws IOException, RateLimitException {
|
||||
String responseText = makeRequest(MESSAGE_PATH, "POST", new Gson().toJson(message));
|
||||
GcmMessageResponse response = new Gson().fromJson(responseText, GcmMessageResponse.class);
|
||||
private void sendMessage(OutgoingPushMessage message) throws IOException {
|
||||
String responseText = makeRequest(MESSAGE_PATH, "POST", new Gson().toJson(message));
|
||||
PushMessageResponse response = new Gson().fromJson(responseText, PushMessageResponse.class);
|
||||
|
||||
if (response.getFailure().size() != 0)
|
||||
throw new IOException("Got send failure: " + response.getFailure().get(0));
|
||||
}
|
||||
|
||||
private List<String> sendAttachments(List<PushAttachment> attachments)
|
||||
throws IOException, RateLimitException
|
||||
private List<PushAttachmentPointer> sendAttachments(List<PushAttachmentData> attachments)
|
||||
throws IOException
|
||||
{
|
||||
List<String> attachmentIds = new LinkedList<String>();
|
||||
List<PushAttachmentPointer> attachmentIds = new LinkedList<PushAttachmentPointer>();
|
||||
|
||||
for (PushAttachment attachment : attachments) {
|
||||
attachmentIds.add(sendAttachment(attachment));
|
||||
for (PushAttachmentData attachment : attachments) {
|
||||
attachmentIds.add(new PushAttachmentPointer(attachment.getContentType(),
|
||||
sendAttachment(attachment)));
|
||||
}
|
||||
|
||||
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, ""),
|
||||
"GET", null, "Content-Location");
|
||||
|
||||
@ -130,34 +131,52 @@ public class PushServiceSocket {
|
||||
|
||||
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 {
|
||||
DirectoryDescriptor directoryDescriptor = new Gson().fromJson(makeRequest(DIRECTORY_PATH, "GET", null),
|
||||
DirectoryDescriptor.class);
|
||||
|
||||
File directoryData = File.createTempFile("directory", ".dat", context.getFilesDir());
|
||||
|
||||
downloadExternalFile(directoryDescriptor.getUrl(), directoryData);
|
||||
|
||||
NumberFilter.getInstance(context).update(directoryData,
|
||||
directoryDescriptor.getCapacity(),
|
||||
directoryDescriptor.getHashCount(),
|
||||
directoryDescriptor.getVersion());
|
||||
|
||||
return new Pair<DirectoryDescriptor, File>(directoryDescriptor, directoryData);
|
||||
} catch (IOException ioe) {
|
||||
Log.w("PushServiceSocket", ioe);
|
||||
} catch (RateLimitException e) {
|
||||
Log.w("PushServiceSocket", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadExternalFile(String url, File localDestination)
|
||||
throws IOException
|
||||
{
|
||||
URL downloadUrl = new URL(url);
|
||||
HttpsURLConnection connection = (HttpsURLConnection) downloadUrl.openConnection();
|
||||
URL downloadUrl = new URL(url);
|
||||
HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
|
||||
connection.setRequestProperty("Content-Type", "application/octet-stream");
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setDoInput(true);
|
||||
|
||||
try {
|
||||
@ -166,7 +185,7 @@ public class PushServiceSocket {
|
||||
}
|
||||
|
||||
OutputStream output = new FileOutputStream(localDestination);
|
||||
InputStream input = new GZIPInputStream(connection.getInputStream());
|
||||
InputStream input = connection.getInputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
|
||||
@ -175,6 +194,7 @@ public class PushServiceSocket {
|
||||
}
|
||||
|
||||
output.close();
|
||||
Log.w("PushServiceSocket", "Downloaded: " + url + " to: " + localDestination.getAbsolutePath());
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
@ -205,7 +225,7 @@ public class PushServiceSocket {
|
||||
|
||||
private Pair<String, String> makeRequestForResponseHeader(String urlFragment, String method,
|
||||
String body, String responseHeader)
|
||||
throws IOException, RateLimitException
|
||||
throws IOException
|
||||
{
|
||||
HttpURLConnection connection = makeBaseRequest(urlFragment, method, body);
|
||||
String response = Util.readFully(connection.getInputStream());
|
||||
@ -216,7 +236,7 @@ public class PushServiceSocket {
|
||||
}
|
||||
|
||||
private String makeRequest(String urlFragment, String method, String body)
|
||||
throws IOException, RateLimitException
|
||||
throws IOException
|
||||
{
|
||||
HttpURLConnection connection = makeBaseRequest(urlFragment, method, body);
|
||||
String response = Util.readFully(connection.getInputStream());
|
||||
@ -227,7 +247,7 @@ public class PushServiceSocket {
|
||||
}
|
||||
|
||||
private HttpURLConnection makeBaseRequest(String urlFragment, String method, String body)
|
||||
throws IOException, RateLimitException
|
||||
throws IOException
|
||||
{
|
||||
HttpURLConnection connection = getConnection(urlFragment, method);
|
||||
|
||||
@ -314,7 +334,7 @@ public class PushServiceSocket {
|
||||
}
|
||||
}
|
||||
|
||||
private class GcmRegistrationId {
|
||||
private static class GcmRegistrationId {
|
||||
private String gcmRegistrationId;
|
||||
|
||||
public GcmRegistrationId() {}
|
||||
@ -324,10 +344,10 @@ public class PushServiceSocket {
|
||||
}
|
||||
}
|
||||
|
||||
private class AttachmentDescriptor {
|
||||
private static class AttachmentKey {
|
||||
private String id;
|
||||
|
||||
public AttachmentDescriptor(String id) {
|
||||
public AttachmentKey(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
package org.whispersystems.textsecure.push;
|
||||
|
||||
|
||||
public class RateLimitException extends Exception {
|
||||
import java.io.IOException;
|
||||
|
||||
public class RateLimitException extends IOException {
|
||||
public RateLimitException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class Util {
|
||||
public static boolean isEmpty(String value) {
|
||||
@ -55,4 +57,18 @@ public class Util {
|
||||
|
||||
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.Util;
|
||||
import org.whispersystems.textsecure.push.PushServiceSocket;
|
||||
import org.whispersystems.textsecure.push.RateLimitException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -361,9 +360,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredSherlockPr
|
||||
} catch (IOException e) {
|
||||
Log.w("ApplicationPreferencesActivity", e);
|
||||
return NETWORK_ERROR;
|
||||
} catch (RateLimitException e) {
|
||||
Log.w("ApplicationPreferencesActivity", e);
|
||||
return NETWORK_ERROR;
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
|
@ -452,12 +452,12 @@ public class RegistrationProgressActivity extends SherlockActivity {
|
||||
PushServiceSocket socket = new PushServiceSocket(context, e164number, password);
|
||||
socket.verifyAccount(code);
|
||||
return SUCCESS;
|
||||
} catch (IOException e) {
|
||||
Log.w("RegistrationProgressActivity", e);
|
||||
return NETWORK_ERROR;
|
||||
} catch (RateLimitException e) {
|
||||
Log.w("RegistrationProgressActivity", e);
|
||||
return RATE_LIMIT_ERROR;
|
||||
} catch (IOException e) {
|
||||
Log.w("RegistrationProgressActivity", e);
|
||||
return NETWORK_ERROR;
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
@ -539,12 +539,12 @@ public class RegistrationProgressActivity extends SherlockActivity {
|
||||
socket.createAccount(true);
|
||||
|
||||
return SUCCESS;
|
||||
} catch (IOException e) {
|
||||
Log.w("RegistrationProgressActivity", e);
|
||||
return NETWORK_ERROR;
|
||||
} catch (RateLimitException e) {
|
||||
Log.w("RegistrationProgressActivity", e);
|
||||
return RATE_LIMIT_EXCEEDED;
|
||||
} catch (IOException e) {
|
||||
Log.w("RegistrationProgressActivity", e);
|
||||
return NETWORK_ERROR;
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
|
@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.TextTransport;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@ -212,7 +213,7 @@ public class DecryptingQueue {
|
||||
RetrieveConf plaintextPdu = new RetrieveConf(plaintextGenericPdu.getPduHeaders(),
|
||||
plaintextGenericPdu.getBody());
|
||||
Log.w("DecryptingQueue", "Successfully decrypted MMS!");
|
||||
database.insertSecureDecryptedMessageInbox(masterSecret, plaintextPdu, threadId);
|
||||
database.insertSecureDecryptedMessageInbox(masterSecret, new IncomingMediaMessage(plaintextPdu), threadId);
|
||||
database.delete(messageId);
|
||||
} catch (RecipientFormattingException 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.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.PartParser;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
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.pdu.CharacterSets;
|
||||
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.PduBody;
|
||||
import ws.com.google.android.mms.pdu.PduHeaders;
|
||||
import ws.com.google.android.mms.pdu.RetrieveConf;
|
||||
import ws.com.google.android.mms.pdu.SendReq;
|
||||
|
||||
// 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 {
|
||||
PduHeaders headers = retrieved.getPduHeaders();
|
||||
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));
|
||||
|
||||
EncodedStringValue[] encodedCcList = retrieved.getCc();
|
||||
EncodedStringValue[] encodedCcList = headers.getEncodedStringValues(PduHeaders.CC);
|
||||
if (encodedCcList != null) {
|
||||
for (EncodedStringValue encodedCc : encodedCcList) {
|
||||
group.add(new String(encodedCc.getTextString(), CharacterSets.MIMENAME_ISO_8859_1));
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String recipient : group) {
|
||||
sb.append(recipient);
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, sb.toString(), false);
|
||||
String recipientsList = Util.join(group, ",");
|
||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, recipientsList, false);
|
||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError(e);
|
||||
@ -280,7 +275,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
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() {
|
||||
@ -359,7 +354,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
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)
|
||||
throws MmsException
|
||||
{
|
||||
@ -367,11 +362,13 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
ContentValues contentValues = getContentValuesFromHeader(headers);
|
||||
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 {
|
||||
threadId = getThreadIdFor(retrieved);
|
||||
} catch (RecipientFormattingException 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(READ, unread ? 0 : 1);
|
||||
|
||||
if (!contentValues.containsKey(DATE_SENT))
|
||||
if (!contentValues.containsKey(DATE_SENT)) {
|
||||
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) {
|
||||
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
|
||||
@ -398,7 +397,8 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
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)
|
||||
throws MmsException
|
||||
{
|
||||
@ -406,7 +406,8 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
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)
|
||||
throws MmsException
|
||||
{
|
||||
@ -415,7 +416,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
}
|
||||
|
||||
public Pair<Long, Long> insertSecureDecryptedMessageInbox(MasterSecret masterSecret,
|
||||
RetrieveConf retrieved,
|
||||
IncomingMediaMessage retrieved,
|
||||
long threadId)
|
||||
throws MmsException
|
||||
{
|
||||
@ -425,11 +426,11 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
|
||||
public Pair<Long, Long> insertMessageInbox(NotificationInd notification) {
|
||||
try {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
PduHeaders headers = notification.getPduHeaders();
|
||||
ContentValues contentValues = getContentValuesFromHeader(headers);
|
||||
long threadId = getThreadIdFor(notification);
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
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));
|
||||
|
||||
@ -486,21 +487,22 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
|
||||
contentValues.remove(ADDRESS);
|
||||
|
||||
long messageId = insertMediaMessage(masterSecret, sendRequest, contentValues);
|
||||
long messageId = insertMediaMessage(masterSecret, sendRequest.getPduHeaders(),
|
||||
sendRequest.getBody(), contentValues);
|
||||
Trimmer.trimThread(context, threadId);
|
||||
|
||||
return messageId;
|
||||
}
|
||||
|
||||
private long insertMediaMessage(MasterSecret masterSecret,
|
||||
MultimediaMessagePdu message,
|
||||
PduHeaders headers,
|
||||
PduBody body,
|
||||
ContentValues contentValues)
|
||||
throws MmsException
|
||||
{
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
PartDatabase partsDatabase = getPartDatabase(masterSecret);
|
||||
MmsAddressDatabase addressDatabase = DatabaseFactory.getMmsAddressDatabase(context);
|
||||
PduBody body = message.getBody();
|
||||
|
||||
if (Types.isSymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX))) {
|
||||
String messageText = PartParser.getMessageText(body);
|
||||
@ -515,7 +517,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
|
||||
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
||||
|
||||
addressDatabase.insertAddressesForId(messageId, message.getPduHeaders());
|
||||
addressDatabase.insertAddressesForId(messageId, headers);
|
||||
partsDatabase.insertParts(messageId, body);
|
||||
|
||||
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.sms.IncomingTextMessage;
|
||||
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.RateLimitException;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
@ -33,8 +33,6 @@ public class GcmIntentService extends GCMBaseIntentService {
|
||||
getGcmSocket(context).registerGcmId(registrationId);
|
||||
} catch (IOException e) {
|
||||
Log.w("GcmIntentService", e);
|
||||
} catch (RateLimitException e) {
|
||||
Log.w("GcmIntentService", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,22 +43,30 @@ public class GcmIntentService extends GCMBaseIntentService {
|
||||
getGcmSocket(context).unregisterGcmId();
|
||||
} catch (IOException ioe) {
|
||||
Log.w("GcmIntentService", ioe);
|
||||
} catch (RateLimitException e) {
|
||||
Log.w("GcmIntentService", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onMessage(Context context, Intent intent) {
|
||||
Log.w("GcmIntentService", "Got GCM message!");
|
||||
String data = intent.getStringExtra("message");
|
||||
Log.w("GcmIntentService", "GCM message: " + data);
|
||||
|
||||
if (Util.isEmpty(data))
|
||||
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>();
|
||||
messages.add(new IncomingTextMessage(message));
|
||||
|
||||
@ -70,9 +76,11 @@ public class GcmIntentService extends GCMBaseIntentService {
|
||||
context.startService(receivedIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onError(Context context, String s) {
|
||||
Log.w("GcmIntentService", "GCM Error: " + s);
|
||||
private void handleIncomingMediaMessage(Context context, IncomingPushMessage message) {
|
||||
Intent receivedIntent = new Intent(context, SendReceiveService.class);
|
||||
receivedIntent.setAction(SendReceiveService.RECEIVE_PUSH_MMS_ACTION);
|
||||
receivedIntent.putExtra("media_message", message);
|
||||
context.startService(receivedIntent);
|
||||
}
|
||||
|
||||
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.model.NotificationMmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.MmsDownloadHelper;
|
||||
import org.thoughtcrime.securesms.mms.MmsRadio;
|
||||
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
||||
@ -177,11 +178,13 @@ public class MmsDownloader {
|
||||
long messageId, long threadId, RetrieveConf retrieved)
|
||||
throws MmsException
|
||||
{
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
IncomingMediaMessage message = new IncomingMediaMessage(retrieved);
|
||||
|
||||
Pair<Long, Long> messageAndThreadId;
|
||||
|
||||
if (retrieved.getSubject() != null && WirePrefix.isEncryptedMmsSubject(retrieved.getSubject().getString())) {
|
||||
messageAndThreadId = database.insertSecureMessageInbox(masterSecret, retrieved,
|
||||
messageAndThreadId = database.insertSecureMessageInbox(masterSecret, message,
|
||||
contentLocation, threadId);
|
||||
|
||||
if (masterSecret != null)
|
||||
@ -189,7 +192,7 @@ public class MmsDownloader {
|
||||
messageAndThreadId.second, retrieved);
|
||||
|
||||
} else {
|
||||
messageAndThreadId = database.insertMessageInbox(masterSecret, retrieved,
|
||||
messageAndThreadId = database.insertMessageInbox(masterSecret, message,
|
||||
contentLocation, threadId);
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,17 @@ import android.util.Pair;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
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.NotificationInd;
|
||||
import ws.com.google.android.mms.pdu.PduHeaders;
|
||||
@ -39,6 +48,54 @@ public class MmsReceiver {
|
||||
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) {
|
||||
Intent intent = new Intent(SendReceiveService.DOWNLOAD_MMS_ACTION, null, context, SendReceiveService.class);
|
||||
intent.putExtra("content_location", new String(pdu.getContentLocation()));
|
||||
@ -50,21 +107,4 @@ public class MmsReceiver {
|
||||
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.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.google.android.gcm.GCMRegistrar;
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.gcm.GcmIntentService;
|
||||
import org.thoughtcrime.securesms.gcm.GcmRegistrationTimeoutException;
|
||||
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.RateLimitException;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -172,7 +171,8 @@ public class RegistrationService extends Service {
|
||||
String gcmRegistrationId = waitForGcmRegistrationId();
|
||||
|
||||
socket.registerGcmId(gcmRegistrationId);
|
||||
socket.retrieveDirectory(this);
|
||||
Pair<DirectoryDescriptor, File> directory = socket.retrieveDirectory();
|
||||
NumberFilter.getInstance(this).update(directory.first, directory.second);
|
||||
|
||||
markAsVerified(number, password);
|
||||
|
||||
@ -190,10 +190,6 @@ public class RegistrationService extends Service {
|
||||
Log.w("RegistrationService", e);
|
||||
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
|
||||
broadcastComplete(false);
|
||||
} catch (RateLimitException e) {
|
||||
Log.w("RegistrationService", e);
|
||||
setState(new RegistrationState(RegistrationState.STATE_NETWORK_ERROR));
|
||||
broadcastComplete(false);
|
||||
} finally {
|
||||
shutdownGcmRegistrationListener();
|
||||
}
|
||||
@ -222,7 +218,8 @@ public class RegistrationService extends Service {
|
||||
String gcmRegistrationId = waitForGcmRegistrationId();
|
||||
|
||||
socket.registerGcmId(gcmRegistrationId);
|
||||
socket.retrieveDirectory(this);
|
||||
Pair<DirectoryDescriptor, File> directory = socket.retrieveDirectory();
|
||||
NumberFilter.getInstance(this).update(directory.first, directory.second);
|
||||
|
||||
markAsVerified(number, password);
|
||||
|
||||
@ -244,10 +241,6 @@ public class RegistrationService extends Service {
|
||||
Log.w("RegistrationService", e);
|
||||
setState(new RegistrationState(RegistrationState.STATE_GCM_TIMEOUT));
|
||||
broadcastComplete(false);
|
||||
} catch (RateLimitException e) {
|
||||
Log.w("RegistrationService", e);
|
||||
setState(new RegistrationState(RegistrationState.STATE_NETWORK_ERROR));
|
||||
broadcastComplete(false);
|
||||
} finally {
|
||||
shutdownChallengeListener();
|
||||
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 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_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_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";
|
||||
@ -92,19 +93,21 @@ public class SendReceiveService extends Service {
|
||||
public void onStart(Intent intent, int startId) {
|
||||
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);
|
||||
else if (intent.getAction().equals(RECEIVE_SMS_ACTION))
|
||||
else if (action.equals(RECEIVE_SMS_ACTION))
|
||||
scheduleIntent(RECEIVE_SMS, intent);
|
||||
else if (intent.getAction().equals(SENT_SMS_ACTION))
|
||||
else if (action.equals(SENT_SMS_ACTION))
|
||||
scheduleIntent(SEND_SMS, intent);
|
||||
else if (intent.getAction().equals(DELIVERED_SMS_ACTION))
|
||||
else if (action.equals(DELIVERED_SMS_ACTION))
|
||||
scheduleIntent(SEND_SMS, intent);
|
||||
else if (intent.getAction().equals(SEND_MMS_ACTION))
|
||||
else if (action.equals(SEND_MMS_ACTION))
|
||||
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);
|
||||
else if (intent.getAction().equals(DOWNLOAD_MMS_ACTION))
|
||||
else if (action.equals(DOWNLOAD_MMS_ACTION))
|
||||
scheduleSecretRequiredIntent(DOWNLOAD_MMS, intent);
|
||||
else if (intent.getAction().equals(DOWNLOAD_MMS_PENDING_APN_ACTION))
|
||||
scheduleSecretRequiredIntent(DOWNLOAD_MMS_PENDING, intent);
|
||||
|
@ -4,7 +4,7 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.telephony.SmsMessage;
|
||||
|
||||
import org.whispersystems.textsecure.push.IncomingGcmMessage;
|
||||
import org.whispersystems.textsecure.push.IncomingPushMessage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -40,7 +40,7 @@ public class IncomingTextMessage implements Parcelable {
|
||||
this.sentTimestampMillis = message.getTimestampMillis();
|
||||
}
|
||||
|
||||
public IncomingTextMessage(IncomingGcmMessage message) {
|
||||
public IncomingTextMessage(IncomingPushMessage message) {
|
||||
this.message = message.getMessageText();
|
||||
this.sender = message.getSource();
|
||||
this.protocol = 31337;
|
||||
|
@ -8,7 +8,7 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.mms.PartParser;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
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.RateLimitException;
|
||||
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 {
|
||||
try {
|
||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||
String password = TextSecurePreferences.getPushServerPassword(context);
|
||||
PushServiceSocket socket = new PushServiceSocket(context, localNumber, password);
|
||||
String messageText = PartParser.getMessageText(message.getBody());
|
||||
List<PushAttachment> attachments = getAttachmentsFromBody(message.getBody());
|
||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||
String password = TextSecurePreferences.getPushServerPassword(context);
|
||||
PushServiceSocket socket = new PushServiceSocket(context, localNumber, password);
|
||||
String messageText = PartParser.getMessageText(message.getBody());
|
||||
List<PushAttachmentData> attachments = getAttachmentsFromBody(message.getBody());
|
||||
|
||||
if (attachments.isEmpty()) socket.sendMessage(destinations, messageText);
|
||||
else socket.sendMessage(destinations, messageText, attachments);
|
||||
@ -66,8 +66,8 @@ public class PushTransport extends BaseTransport {
|
||||
}
|
||||
}
|
||||
|
||||
private List<PushAttachment> getAttachmentsFromBody(PduBody body) {
|
||||
List<PushAttachment> attachments = new LinkedList<PushAttachment>();
|
||||
private List<PushAttachmentData> getAttachmentsFromBody(PduBody body) {
|
||||
List<PushAttachmentData> attachments = new LinkedList<PushAttachmentData>();
|
||||
|
||||
for (int i=0;i<body.getPartsNum();i++) {
|
||||
String contentType = Util.toIsoString(body.getPart(i).getContentType());
|
||||
@ -76,7 +76,7 @@ public class PushTransport extends BaseTransport {
|
||||
ContentType.isAudioType(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.whispersystems.textsecure.util.PhoneNumberFormatter;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -151,6 +155,19 @@ public class Util {
|
||||
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){
|
||||
return (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) ||
|
||||
|
Loading…
Reference in New Issue
Block a user