private void deliver(MasterSecret masterSecret, SmsMessageRecord message) throws UndeliverableMessageException, InsecureFallbackApprovalException { if (message.isSecure() || message.isKeyExchange() || message.isEndSession()) { deliverSecureMessage(masterSecret, message); } else { deliverPlaintextMessage(message); } }
private void deliverPlaintextMessage(SmsMessageRecord message) throws UndeliverableMessageException { String recipient = message.getIndividualRecipient().getNumber(); // See issue #1516 for bug report, and discussion on commits related to #4833 for problems // related to the original fix to #1516. This still may not be a correct fix if networks allow // SMS/MMS sending to alphanumeric recipients other than email addresses, but should also // help to fix issue #3099. if (!NumberUtil.isValidEmail(recipient)) { recipient = PhoneNumberUtils.stripSeparators( PhoneNumberUtils.convertKeypadLettersToDigits(recipient)); } if (!NumberUtil.isValidSmsOrEmail(recipient)) { throw new UndeliverableMessageException("Not a valid SMS destination! " + recipient); } ArrayList<String> messages = SmsManager.getDefault().divideMessage(message.getBody().getBody()); ArrayList<PendingIntent> sentIntents = constructSentIntents(message.getId(), message.getType(), messages, false); ArrayList<PendingIntent> deliveredIntents = constructDeliveredIntents(message.getId(), message.getType(), messages); // NOTE 11/04/14 -- There's apparently a bug where for some unknown recipients // and messages, this will throw an NPE. We have no idea why, so we're just // catching it and marking the message as a failure. That way at least it doesn't // repeatedly crash every time you start the app. try { getSmsManagerFor(message.getSubscriptionId()) .sendMultipartTextMessage(recipient, null, messages, sentIntents, deliveredIntents); } catch (NullPointerException npe) { Log.w(TAG, npe); Log.w(TAG, "Recipient: " + recipient); Log.w(TAG, "Message Parts: " + messages.size()); try { for (int i = 0; i < messages.size(); i++) { getSmsManagerFor(message.getSubscriptionId()) .sendTextMessage( recipient, null, messages.get(i), sentIntents.get(i), deliveredIntents == null ? null : deliveredIntents.get(i)); } } catch (NullPointerException npe2) { Log.w(TAG, npe); throw new UndeliverableMessageException(npe2); } } }
private void deliverSecureMessage(MasterSecret masterSecret, SmsMessageRecord message) throws UndeliverableMessageException, InsecureFallbackApprovalException { MultipartSmsMessageHandler multipartMessageHandler = new MultipartSmsMessageHandler(); OutgoingTextMessage transportMessage = OutgoingTextMessage.from(message); if (message.isSecure() || message.isEndSession()) { transportMessage = getAsymmetricEncrypt(masterSecret, transportMessage); } ArrayList<String> messages = multipartMessageHandler.divideMessage(transportMessage); ArrayList<PendingIntent> sentIntents = constructSentIntents(message.getId(), message.getType(), messages, message.isSecure()); ArrayList<PendingIntent> deliveredIntents = constructDeliveredIntents(message.getId(), message.getType(), messages); Log.w("SmsTransport", "Secure divide into message parts: " + messages.size()); for (int i = 0; i < messages.size(); i++) { // NOTE 11/04/14 -- There's apparently a bug where for some unknown recipients // and messages, this will throw an NPE. We have no idea why, so we're just // catching it and marking the message as a failure. That way at least it // doesn't repeatedly crash every time you start the app. try { SmsManager.getDefault() .sendTextMessage( message.getIndividualRecipient().getNumber(), null, messages.get(i), sentIntents.get(i), deliveredIntents == null ? null : deliveredIntents.get(i)); } catch (NullPointerException npe) { Log.w(TAG, npe); Log.w(TAG, "Recipient: " + message.getIndividualRecipient().getNumber()); Log.w(TAG, "Message Total Parts/Current: " + messages.size() + "/" + i); Log.w(TAG, "Message Part Length: " + messages.get(i).getBytes().length); throw new UndeliverableMessageException(npe); } catch (IllegalArgumentException iae) { Log.w(TAG, iae); throw new UndeliverableMessageException(iae); } } }
@Override public void onSend(MasterSecret masterSecret) throws NoSuchMessageException { EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); SmsMessageRecord record = database.getMessage(masterSecret, messageId); try { Log.w(TAG, "Sending message: " + messageId); deliver(masterSecret, record); } catch (UndeliverableMessageException ude) { Log.w(TAG, ude); DatabaseFactory.getSmsDatabase(context).markAsSentFailed(record.getId()); MessageNotifier.notifyMessageDeliveryFailed( context, record.getRecipients(), record.getThreadId()); } catch (InsecureFallbackApprovalException ifae) { Log.w(TAG, ifae); DatabaseFactory.getSmsDatabase(context).markAsPendingInsecureSmsFallback(record.getId()); MessageNotifier.notifyMessageDeliveryFailed( context, record.getRecipients(), record.getThreadId()); } }
public static OutgoingTextMessage from(SmsMessageRecord record) { if (record.isSecure()) { return new OutgoingEncryptedMessage( record.getIndividualRecipient(), record.getBody().getBody()); } else if (record.isKeyExchange()) { return new OutgoingKeyExchangeMessage( record.getIndividualRecipient(), record.getBody().getBody()); } else if (record.isEndSession()) { return new OutgoingEndSessionMessage( new OutgoingTextMessage(record.getIndividualRecipient(), record.getBody().getBody())); } else { return new OutgoingTextMessage(record.getIndividualRecipient(), record.getBody().getBody()); } }