From 68747142d65d06f31e34b401fc0e395d98963ae0 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Wed, 11 Jun 2014 15:31:59 -0700 Subject: [PATCH] Add correct contextual menu options on 'Send' button. [Send TextSecure message | Send unencrypted SMS | Send encrypted SMS] // FREEBIE --- res/menu/conversation_button_context.xml | 5 - ...versation_button_context_insecure_push.xml | 8 ++ ...onversation_button_context_secure_push.xml | 10 ++ ...conversation_button_context_secure_sms.xml | 8 ++ res/values/strings.xml | 5 +- .../securesms/ConversationActivity.java | 91 ++++++++++++------- .../securesms/GroupCreateActivity.java | 2 +- .../crypto/KeyExchangeInitiator.java | 2 +- .../crypto/KeyExchangeProcessorV2.java | 2 +- .../database/EncryptingSmsDatabase.java | 4 +- .../securesms/database/MmsDatabase.java | 8 +- .../securesms/database/SmsDatabase.java | 5 +- .../securesms/sms/MessageSender.java | 12 ++- 13 files changed, 107 insertions(+), 55 deletions(-) delete mode 100644 res/menu/conversation_button_context.xml create mode 100644 res/menu/conversation_button_context_insecure_push.xml create mode 100644 res/menu/conversation_button_context_secure_push.xml create mode 100644 res/menu/conversation_button_context_secure_sms.xml diff --git a/res/menu/conversation_button_context.xml b/res/menu/conversation_button_context.xml deleted file mode 100644 index d6929404a7..0000000000 --- a/res/menu/conversation_button_context.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/res/menu/conversation_button_context_insecure_push.xml b/res/menu/conversation_button_context_insecure_push.xml new file mode 100644 index 0000000000..81dcf7419b --- /dev/null +++ b/res/menu/conversation_button_context_insecure_push.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/res/menu/conversation_button_context_secure_push.xml b/res/menu/conversation_button_context_secure_push.xml new file mode 100644 index 0000000000..7c60057cf2 --- /dev/null +++ b/res/menu/conversation_button_context_secure_push.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/res/menu/conversation_button_context_secure_sms.xml b/res/menu/conversation_button_context_secure_sms.xml new file mode 100644 index 0000000000..457505e7bd --- /dev/null +++ b/res/menu/conversation_button_context_secure_sms.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 185e16f392..0a37494291 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -781,7 +781,9 @@ Refresh contact list - Send unencrypted + Send TextSecure message + Send unencrypted SMS + Send encrypted SMS Call @@ -841,6 +843,7 @@ Verified + diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index b3b06986ee..072bf79497 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -193,7 +193,6 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi @Override protected void onResume() { - super.onResume(); dynamicTheme.onResume(this); dynamicLanguage.onResume(this); @@ -312,16 +311,28 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - if (isEncryptedConversation) { - android.view.MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.conversation_button_context, menu); + if (isEncryptedConversation && isSingleConversation()) { + boolean isPushDestination = DirectoryHelper.isPushDestination(this, getRecipients()); + Recipient primaryRecipient = getRecipients() == null ? null : getRecipients().getPrimaryRecipient(); + boolean hasSession = Session.hasSession(this, masterSecret, primaryRecipient); + + int context; + + if (isPushDestination && hasSession) context = R.menu.conversation_button_context_secure_push; + else if (isPushDestination) context = R.menu.conversation_button_context_insecure_push; + else if (hasSession) context = R.menu.conversation_button_context_secure_sms; + else return; + + getMenuInflater().inflate(context, menu); } } @Override public boolean onContextItemSelected(android.view.MenuItem item) { switch (item.getItemId()) { - case R.id.menu_context_send_unencrypted: sendMessage(true); return true; + case R.id.menu_context_send_push: sendMessage(false, false); return true; + case R.id.menu_context_send_encrypted_sms: sendMessage(false, true); return true; + case R.id.menu_context_send_unencrypted_sms: sendMessage(true, true); return true; } return false; @@ -402,7 +413,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi new OutgoingEndSessionMessage(new OutgoingTextMessage(getRecipients(), "TERMINATE")); long allocatedThreadId = MessageSender.send(self, masterSecret, - endSessionMessage, threadId); + endSessionMessage, threadId, false); sendComplete(recipients, allocatedThreadId, allocatedThreadId != self.threadId); } else { @@ -444,7 +455,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(self, getRecipients(), context, null); - MessageSender.send(self, masterSecret, outgoingMessage, threadId); + MessageSender.send(self, masterSecret, outgoingMessage, threadId, false); DatabaseFactory.getGroupDatabase(self).remove(groupId, TextSecurePreferences.getLocalNumber(self)); initializeEnabledCheck(); } catch (IOException e) { @@ -1009,45 +1020,22 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi fragment.scrollToBottom(); } - private void sendMessage(boolean forcePlaintext) { + private void sendMessage(boolean forcePlaintext, boolean forceSms) { try { Recipients recipients = getRecipients(); if (recipients == null) throw new RecipientFormattingException("Badly formatted"); - String body = getMessage(); long allocatedThreadId; if ((!recipients.isSingleRecipient() || recipients.isEmailRecipient()) && !isMmsEnabled) { handleManualMmsRequired(); return; } else if (attachmentManager.isAttachmentPresent() || !recipients.isSingleRecipient() || recipients.isGroupRecipient() || recipients.isEmailRecipient()) { - SlideDeck slideDeck; - - if (attachmentManager.isAttachmentPresent()) slideDeck = attachmentManager.getSlideDeck(); - else slideDeck = new SlideDeck(); - - OutgoingMediaMessage outgoingMessage = new OutgoingMediaMessage(this, recipients, slideDeck, - body, distributionType); - - if (isEncryptedConversation && !forcePlaintext) { - outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessage); - } - - allocatedThreadId = MessageSender.send(this, masterSecret, outgoingMessage, threadId); + allocatedThreadId = sendMediaMessage(forcePlaintext, forceSms); } else { - OutgoingTextMessage message; - - if (isEncryptedConversation && !forcePlaintext) { - message = new OutgoingEncryptedMessage(recipients, body); - } else { - message = new OutgoingTextMessage(recipients, body); - } - - Log.w(TAG, "Sending message..."); - allocatedThreadId = MessageSender.send(ConversationActivity.this, masterSecret, - message, threadId); + allocatedThreadId = sendTextMessage(forcePlaintext, forceSms); } sendComplete(recipients, allocatedThreadId, allocatedThreadId != this.threadId); @@ -1065,6 +1053,41 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi } } + private long sendMediaMessage(boolean forcePlaintext, boolean forceSms) + throws InvalidMessageException, MmsException + { + SlideDeck slideDeck; + + if (attachmentManager.isAttachmentPresent()) slideDeck = attachmentManager.getSlideDeck(); + else slideDeck = new SlideDeck(); + + OutgoingMediaMessage outgoingMessage = new OutgoingMediaMessage(this, recipients, slideDeck, + getMessage(), distributionType); + + if (isEncryptedConversation && !forcePlaintext) { + outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessage); + } + + return MessageSender.send(this, masterSecret, outgoingMessage, threadId, forceSms); + } + + private long sendTextMessage(boolean forcePlaintext, boolean forceSms) + throws InvalidMessageException + { + OutgoingTextMessage message; + + if (isEncryptedConversation && !forcePlaintext) { + message = new OutgoingEncryptedMessage(recipients, getMessage()); + } else { + message = new OutgoingTextMessage(recipients, getMessage()); + } + + Log.w(TAG, "Sending message..."); + + return MessageSender.send(ConversationActivity.this, masterSecret, message, threadId, forceSms); + } + + // Listeners private class AttachmentTypeListener implements DialogInterface.OnClickListener { @@ -1092,7 +1115,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi private class SendButtonListener implements OnClickListener, TextView.OnEditorActionListener { @Override public void onClick(View v) { - sendMessage(false); + sendMessage(false, false); } @Override diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index ebd8ded7ad..68de5474c7 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -459,7 +459,7 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv .build(); OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(this, groupRecipient, context, avatar); - long threadId = MessageSender.send(this, masterSecret, outgoingMessage, -1); + long threadId = MessageSender.send(this, masterSecret, outgoingMessage, -1, false); return new Pair(threadId, groupRecipient); } catch (RecipientFormattingException e) { diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java index 679030cdce..6921f05e6d 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeInitiator.java @@ -77,7 +77,7 @@ public class KeyExchangeInitiator { sessionRecordV2.getSessionState().setPendingKeyExchange(sequence, baseKey, ephemeralKey, identityKey); sessionRecordV2.save(); - MessageSender.send(context, masterSecret, textMessage, -1); + MessageSender.send(context, masterSecret, textMessage, -1, false); } private static boolean hasInitiatedSession(Context context, MasterSecret masterSecret, diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java index ce501e5c78..e8bae08205 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java @@ -206,7 +206,7 @@ public class KeyExchangeProcessorV2 extends KeyExchangeProcessor { OutgoingKeyExchangeMessage textMessage = new OutgoingKeyExchangeMessage(recipient, ourMessage.serialize()); - MessageSender.send(context, masterSecret, textMessage, threadId); + MessageSender.send(context, masterSecret, textMessage, threadId, false); } if (message.getSequence() != sessionRecord.getSessionState().getPendingKeyExchangeSequence()) { diff --git a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java index ab65267565..b566f54d28 100644 --- a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java @@ -59,13 +59,13 @@ public class EncryptingSmsDatabase extends SmsDatabase { } public List insertMessageOutbox(MasterSecret masterSecret, long threadId, - OutgoingTextMessage message) + OutgoingTextMessage message, boolean forceSms) { long type = Types.BASE_OUTBOX_TYPE; message = message.withBody(getEncryptedBody(masterSecret, message.getMessageBody())); type |= Types.ENCRYPTION_SYMMETRIC_BIT; - return insertMessageOutbox(threadId, message, type); + return insertMessageOutbox(threadId, message, type, forceSms); } public Pair insertMessageInbox(MasterSecret masterSecret, diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index 3d4a398414..fed8abb753 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -572,14 +572,14 @@ public class MmsDatabase extends Database implements MmsSmsColumns { Trimmer.trimThread(context, threadId); } - public long insertMessageOutbox(MasterSecret masterSecret, OutgoingMediaMessage message, long threadId) + public long insertMessageOutbox(MasterSecret masterSecret, OutgoingMediaMessage message, + long threadId, boolean forceSms) throws MmsException { long type = Types.BASE_OUTBOX_TYPE | Types.ENCRYPTION_SYMMETRIC_BIT; - if (message.isSecure()) { - type |= Types.SECURE_MESSAGE_BIT; - } + if (message.isSecure()) type |= Types.SECURE_MESSAGE_BIT; + if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT; if (message.isGroup()) { if (((OutgoingGroupMediaMessage)message).isGroupUpdate()) type |= Types.GROUP_UPDATE_BIT; diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java index b57bbb3c71..e4cf49ba38 100644 --- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -362,10 +362,13 @@ public class SmsDatabase extends Database implements MmsSmsColumns { return insertMessageInbox(message, Types.BASE_INBOX_TYPE); } - protected List insertMessageOutbox(long threadId, OutgoingTextMessage message, long type) { + protected List insertMessageOutbox(long threadId, OutgoingTextMessage message, + long type, boolean forceSms) + { if (message.isKeyExchange()) type |= Types.KEY_EXCHANGE_BIT; else if (message.isSecureMessage()) type |= Types.SECURE_MESSAGE_BIT; else if (message.isEndSession()) type |= Types.END_SESSION_BIT; + if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT; long date = System.currentTimeMillis(); List messageIds = new LinkedList(); diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index 09b89147e8..b9ccf36540 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -32,14 +32,14 @@ import ws.com.google.android.mms.MmsException; public class MessageSender { public static long send(Context context, MasterSecret masterSecret, - OutgoingTextMessage message, long threadId) + OutgoingTextMessage message, long threadId, + boolean forceSms) { if (threadId == -1) threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(message.getRecipients()); List messageIds = DatabaseFactory.getEncryptingSmsDatabase(context) - .insertMessageOutbox(masterSecret, threadId, message); - + .insertMessageOutbox(masterSecret, threadId, message, forceSms); for (long messageId : messageIds) { Log.w("SMSSender", "Got message id for new message: " + messageId); @@ -53,14 +53,16 @@ public class MessageSender { return threadId; } - public static long send(Context context, MasterSecret masterSecret, OutgoingMediaMessage message, long threadId) + public static long send(Context context, MasterSecret masterSecret, + OutgoingMediaMessage message, + long threadId, boolean forceSms) throws MmsException { if (threadId == -1) threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(message.getRecipients(), message.getDistributionType()); long messageId = DatabaseFactory.getMmsDatabase(context) - .insertMessageOutbox(masterSecret, message, threadId); + .insertMessageOutbox(masterSecret, message, threadId, forceSms); Intent intent = new Intent(SendReceiveService.SEND_MMS_ACTION, null, context, SendReceiveService.class);