Support for incoming attachments.

1) Refactored MMS layer to use abstracted types.

2) Added support for retrieving attachment IDs.
This commit is contained in:
Moxie Marlinspike
2013-07-18 17:42:45 -07:00
parent 4bb337a3a0
commit 9287d413ac
23 changed files with 501 additions and 193 deletions

View File

@@ -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);
}

View File

@@ -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...");
}
}
}

View File

@@ -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();

View File

@@ -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);