diff --git a/src/org/thoughtcrime/securesms/service/SmsReceiver.java b/src/org/thoughtcrime/securesms/service/SmsReceiver.java index c00b637210..6c830fa539 100644 --- a/src/org/thoughtcrime/securesms/service/SmsReceiver.java +++ b/src/org/thoughtcrime/securesms/service/SmsReceiver.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,12 +10,20 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.service; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.telephony.SmsMessage; +import android.util.Log; + import org.thoughtcrime.securesms.ApplicationPreferencesActivity; import org.thoughtcrime.securesms.crypto.DecryptingQueue; import org.thoughtcrime.securesms.crypto.InvalidKeyException; @@ -30,106 +38,98 @@ import org.thoughtcrime.securesms.protocol.WirePrefix; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.sms.MultipartMessageHandler; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.telephony.SmsMessage; -import android.util.Log; - public class SmsReceiver { private MultipartMessageHandler multipartMessageHandler = new MultipartMessageHandler(); - + private final Context context; - + public SmsReceiver(Context context) { this.context = context; } - + private String assembleSecureMessageFragments(String sender, String messageBody) { String localPrefix; - + if (WirePrefix.isEncryptedMessage(messageBody)) { localPrefix = Prefix.ASYMMETRIC_ENCRYPT; } else { localPrefix = Prefix.KEY_EXCHANGE; } - + Log.w("SMSReceiverService", "Calculated local prefix for message: " + messageBody + " - Local Prefix: " + localPrefix); messageBody = messageBody.substring(WirePrefix.PREFIX_SIZE); - + Log.w("SMSReceiverService", "Parsed off wire prefix: " + messageBody); - + if (!multipartMessageHandler.isManualTransport(messageBody)) return localPrefix + messageBody; else return multipartMessageHandler.processPotentialMultipartMessage(localPrefix, sender, messageBody); - + } - + private String assembleMessageFragments(SmsMessage[] messages) { StringBuilder body = new StringBuilder(); - + for (SmsMessage message : messages) { body.append(message.getDisplayMessageBody()); } - + String messageBody = body.toString(); - + if (WirePrefix.isEncryptedMessage(messageBody) || WirePrefix.isKeyExchange(messageBody)) { return assembleSecureMessageFragments(messages[0].getDisplayOriginatingAddress(), messageBody); } else { return messageBody; } } - + private void storeSecureMessage(MasterSecret masterSecret, SmsMessage message, String messageBody) { long messageId = DatabaseFactory.getSmsDatabase(context).insertSecureMessageReceived(message, messageBody); Log.w("SmsReceiver", "Inserted secure message received: " + messageId); - if (masterSecret != null) - DecryptingQueue.scheduleDecryption(context, masterSecret, messageId, message.getDisplayOriginatingAddress(), messageBody); + if (masterSecret != null) + DecryptingQueue.scheduleDecryption(context, masterSecret, messageId, message.getDisplayOriginatingAddress(), messageBody); } - + private long storeStandardMessage(MasterSecret masterSecret, SmsMessage message, String messageBody) { if (masterSecret != null) return DatabaseFactory.getEncryptingSmsDatabase(context).insertMessageReceived(masterSecret, message, messageBody); else if (MasterSecretUtil.hasAsymmericMasterSecret(context)) return DatabaseFactory.getEncryptingSmsDatabase(context).insertMessageReceived(MasterSecretUtil.getAsymmetricMasterSecret(context, null), message, messageBody); - else return DatabaseFactory.getSmsDatabase(context).insertMessageReceived(message, messageBody); + else return DatabaseFactory.getSmsDatabase(context).insertMessageReceived(message, messageBody); } private void storeKeyExchangeMessage(MasterSecret masterSecret, SmsMessage message, String messageBody) { if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean(ApplicationPreferencesActivity.AUTO_KEY_EXCHANGE_PREF, true)) { try { - Recipient recipient = new Recipient(null, message.getDisplayOriginatingAddress(), null); - KeyExchangeMessage keyExchangeMessage = new KeyExchangeMessage(messageBody); - KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipient); - - Log.w("SmsReceiver", "Received key with fingerprint: " + keyExchangeMessage.getPublicKey().getFingerprint()); - - if (processor.isStale(keyExchangeMessage)) { - messageBody = messageBody.substring(Prefix.KEY_EXCHANGE.length()); - messageBody = Prefix.STALE_KEY_EXCHANGE + messageBody; - } else if (!processor.hasCompletedSession() || processor.hasSameSessionIdentity(keyExchangeMessage)) { - messageBody = messageBody.substring(Prefix.KEY_EXCHANGE.length()); - messageBody = Prefix.PROCESSED_KEY_EXCHANGE + messageBody; - long messageId = storeStandardMessage(masterSecret, message, messageBody); - long threadId = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageId); - - processor.processKeyExchangeMessage(keyExchangeMessage, threadId); - return; - } + Recipient recipient = new Recipient(null, message.getDisplayOriginatingAddress(), null); + KeyExchangeMessage keyExchangeMessage = new KeyExchangeMessage(messageBody); + KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipient); + + Log.w("SmsReceiver", "Received key with fingerprint: " + keyExchangeMessage.getPublicKey().getFingerprint()); + + if (processor.isStale(keyExchangeMessage)) { + messageBody = messageBody.substring(Prefix.KEY_EXCHANGE.length()); + messageBody = Prefix.STALE_KEY_EXCHANGE + messageBody; + } else if (!processor.hasCompletedSession() || processor.hasSameSessionIdentity(keyExchangeMessage)) { + messageBody = messageBody.substring(Prefix.KEY_EXCHANGE.length()); + messageBody = Prefix.PROCESSED_KEY_EXCHANGE + messageBody; + long messageId = storeStandardMessage(masterSecret, message, messageBody); + long threadId = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageId); + + processor.processKeyExchangeMessage(keyExchangeMessage, threadId); + return; + } } catch (InvalidVersionException e) { - Log.w("SmsReceiver", e); + Log.w("SmsReceiver", e); } catch (InvalidKeyException e) { - Log.w("SmsReceiver", e); + Log.w("SmsReceiver", e); } } storeStandardMessage(masterSecret, message, messageBody); } - + private boolean storeMessage(MasterSecret masterSecret, SmsMessage message, String messageBody) { if (messageBody.startsWith(Prefix.ASYMMETRIC_ENCRYPT)) { storeSecureMessage(masterSecret, message, messageBody); @@ -138,48 +138,48 @@ public class SmsReceiver { } else { storeStandardMessage(masterSecret, message, messageBody); } - + return true; } private SmsMessage[] parseMessages(Bundle bundle) { Object[] pdus = (Object[])bundle.get("pdus"); SmsMessage[] messages = new SmsMessage[pdus.length]; - + for (int i=0;i. */ package org.thoughtcrime.securesms.service; -import java.util.ArrayList; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.telephony.SmsManager; +import android.util.Log; import org.thoughtcrime.securesms.crypto.MasterCipher; import org.thoughtcrime.securesms.crypto.MasterSecret; @@ -32,24 +38,18 @@ import org.thoughtcrime.securesms.sms.MultipartMessageHandler; import org.thoughtcrime.securesms.sms.SmsTransportDetails; import org.thoughtcrime.securesms.util.InvalidMessageException; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.telephony.SmsManager; -import android.util.Log; +import java.util.ArrayList; public class SmsSender { private final MultipartMessageHandler multipartMessageHandler = new MultipartMessageHandler(); - + private final Context context; - + public SmsSender(Context context) { this.context = context; } - + public void process(MasterSecret masterSecret, Intent intent) { MasterCipher masterCipher = new MasterCipher(masterSecret); long messageId = intent.getLongExtra("message_id", -1); @@ -60,44 +60,44 @@ public class SmsSender { try { if (messageId == -1) c = DatabaseFactory.getSmsDatabase(context).getOutgoingMessages(); else c = DatabaseFactory.getSmsDatabase(context).getMessage(messageId); - - if (c != null && c.moveToFirst()) { - do { - messageId = c.getLong(c.getColumnIndexOrThrow(SmsDatabase.ID)); - String body = c.getString(c.getColumnIndexOrThrow(SmsDatabase.BODY)); - String address = c.getString(c.getColumnIndexOrThrow(SmsDatabase.ADDRESS)); - String messageText = getClearTextBody(masterCipher, body); - long type = c.getLong(c.getColumnIndexOrThrow(SmsDatabase.TYPE)); - - if (!SmsDatabase.Types.isPendingMessageType(type)) - continue; - - if (isSecureMessage(type)) - messageText = getAsymmetricEncrypt(masterSecret, messageText, address); - - Log.w("SMSSenderService", "Actually delivering: " + messageId); - deliverTextMessage(address, messageText, messageId, type); - } while (c.moveToNext()); - } + if (c != null && c.moveToFirst()) { + do { + messageId = c.getLong(c.getColumnIndexOrThrow(SmsDatabase.ID)); + String body = c.getString(c.getColumnIndexOrThrow(SmsDatabase.BODY)); + String address = c.getString(c.getColumnIndexOrThrow(SmsDatabase.ADDRESS)); + String messageText = getClearTextBody(masterCipher, body); + long type = c.getLong(c.getColumnIndexOrThrow(SmsDatabase.TYPE)); + + if (!SmsDatabase.Types.isPendingMessageType(type)) + continue; + + if (isSecureMessage(type)) + messageText = getAsymmetricEncrypt(masterSecret, messageText, address); + + Log.w("SMSSenderService", "Actually delivering: " + messageId); + + deliverTextMessage(address, messageText, messageId, type); + } while (c.moveToNext()); + } } finally { if (c != null) - c.close(); + c.close(); } } - + private String getClearTextBody(MasterCipher masterCipher, String body) { if (body.startsWith(Prefix.SYMMETRIC_ENCRYPT)) { try { - return masterCipher.decryptBody(body.substring(Prefix.SYMMETRIC_ENCRYPT.length())); + return masterCipher.decryptBody(body.substring(Prefix.SYMMETRIC_ENCRYPT.length())); } catch (InvalidMessageException e) { - return "Error decrypting message."; + return "Error decrypting message."; } } else { return body; } } - + private ArrayList constructSentIntents(long messageId, long type, ArrayList messages) { ArrayList sentIntents = new ArrayList(messages.size()); @@ -107,10 +107,10 @@ public class SmsSender { pending.putExtra("message_id", messageId); sentIntents.add(PendingIntent.getBroadcast(context, 0, pending, 0)); } - + return sentIntents; } - + private void deliverGSMTransportTextMessage(String recipient, String text, long messageId, long type) { ArrayList messages = SmsManager.getDefault().divideMessage(text); ArrayList sentIntents = constructSentIntents(messageId, type, messages); @@ -128,7 +128,7 @@ public class SmsSender { private void deliverSecureTransportTextMessage(String recipient, String text, long messageId, long type) { WirePrefix prefix; - + if (isSecureMessage(type)) { prefix = new SecureMessageWirePrefix(); text = text.substring(Prefix.ASYMMETRIC_ENCRYPT.length()); @@ -136,12 +136,12 @@ public class SmsSender { prefix = new KeyExchangeWirePrefix(); text = text.substring(Prefix.KEY_EXCHANGE.length()); } - + if (!multipartMessageHandler.isManualTransport(text)) { deliverGSMTransportTextMessage(recipient, prefix.calculatePrefix(text) + text, messageId, type); return; } - + ArrayList messages = multipartMessageHandler.divideMessage(recipient, text, prefix); ArrayList sentIntents = constructSentIntents(messageId, type, messages); for (int i=0;i