mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-16 16:41:29 +00:00
Remove the Canonical Address Database
This was a holdover from Signal's origins as a pure SMS app. It causes problems, depends on undefined device specific behavior, and should no longer be necessary now that we have all the information we need to E164 all numbers. // FREEBIE
This commit is contained in:
parent
e452862813
commit
737810475e
@ -203,7 +203,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
versionCode 275
|
versionCode 276
|
||||||
versionName "4.8.1"
|
versionName "4.8.1"
|
||||||
|
|
||||||
minSdkVersion 9
|
minSdkVersion 9
|
||||||
|
@ -17,6 +17,7 @@ import android.widget.AdapterView;
|
|||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.loaders.BlockedContactsLoader;
|
import org.thoughtcrime.securesms.database.loaders.BlockedContactsLoader;
|
||||||
import org.thoughtcrime.securesms.preferences.BlockedContactListItem;
|
import org.thoughtcrime.securesms.preferences.BlockedContactListItem;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
@ -24,6 +25,8 @@ import org.thoughtcrime.securesms.recipients.Recipients;
|
|||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity {
|
public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity {
|
||||||
|
|
||||||
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||||
@ -105,7 +108,7 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
|
|||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
Recipients recipients = ((BlockedContactListItem)view).getRecipients();
|
Recipients recipients = ((BlockedContactListItem)view).getRecipients();
|
||||||
Intent intent = new Intent(getActivity(), RecipientPreferenceActivity.class);
|
Intent intent = new Intent(getActivity(), RecipientPreferenceActivity.class);
|
||||||
intent.putExtra(RecipientPreferenceActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(RecipientPreferenceActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
|
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
@ -124,8 +127,10 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bindView(View view, Context context, Cursor cursor) {
|
public void bindView(View view, Context context, Cursor cursor) {
|
||||||
String recipientIds = cursor.getString(1);
|
String addressesConcat = cursor.getString(1);
|
||||||
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientIds, true);
|
List<Address> addresses = Address.fromSerializedList(addressesConcat, " ");
|
||||||
|
|
||||||
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses.toArray(new Address[0]), true);
|
||||||
|
|
||||||
((BlockedContactListItem) view).set(recipients);
|
((BlockedContactListItem) view).set(recipients);
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,11 @@ import android.support.v7.app.AlertDialog;
|
|||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MmsAddressDatabase;
|
import org.thoughtcrime.securesms.database.MmsAddressDatabase;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
@ -28,12 +27,9 @@ import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.thoughtcrime.securesms.util.VerifySpan;
|
import org.thoughtcrime.securesms.util.VerifySpan;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||||
import org.whispersystems.libsignal.state.IdentityKeyStore;
|
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -53,10 +49,8 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||||||
{
|
{
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
try {
|
Recipient recipient = RecipientFactory.getRecipientFor(context, mismatch.getAddress(), false);
|
||||||
Recipient recipient = RecipientFactory.getRecipientForId(context, mismatch.getRecipientId(), false);
|
|
||||||
String name = recipient.toShortString();
|
String name = recipient.toShortString();
|
||||||
String number = Util.canonicalizeNumber(context, recipient.getNumber());
|
|
||||||
String introduction = String.format(context.getString(R.string.ConfirmIdentityDialog_your_safety_number_with_s_has_changed), name, name);
|
String introduction = String.format(context.getString(R.string.ConfirmIdentityDialog_your_safety_number_with_s_has_changed), name, name);
|
||||||
SpannableString spannableString = new SpannableString(introduction + " " +
|
SpannableString spannableString = new SpannableString(introduction + " " +
|
||||||
context.getString(R.string.ConfirmIdentityDialog_you_may_wish_to_verify_your_safety_number_with_this_contact));
|
context.getString(R.string.ConfirmIdentityDialog_you_may_wish_to_verify_your_safety_number_with_this_contact));
|
||||||
@ -68,11 +62,8 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||||||
setTitle(name);
|
setTitle(name);
|
||||||
setMessage(spannableString);
|
setMessage(spannableString);
|
||||||
|
|
||||||
setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ConfirmIdentityDialog_accept), new AcceptListener(masterSecret, messageRecord, mismatch, number));
|
setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ConfirmIdentityDialog_accept), new AcceptListener(masterSecret, messageRecord, mismatch, recipient.getAddress()));
|
||||||
setButton(AlertDialog.BUTTON_NEGATIVE, context.getString(android.R.string.cancel), new CancelListener());
|
setButton(AlertDialog.BUTTON_NEGATIVE, context.getString(android.R.string.cancel), new CancelListener());
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -91,13 +82,13 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||||||
private final MasterSecret masterSecret;
|
private final MasterSecret masterSecret;
|
||||||
private final MessageRecord messageRecord;
|
private final MessageRecord messageRecord;
|
||||||
private final IdentityKeyMismatch mismatch;
|
private final IdentityKeyMismatch mismatch;
|
||||||
private final String number;
|
private final Address address;
|
||||||
|
|
||||||
private AcceptListener(MasterSecret masterSecret, MessageRecord messageRecord, IdentityKeyMismatch mismatch, String number) {
|
private AcceptListener(MasterSecret masterSecret, MessageRecord messageRecord, IdentityKeyMismatch mismatch, Address address) {
|
||||||
this.masterSecret = masterSecret;
|
this.masterSecret = masterSecret;
|
||||||
this.messageRecord = messageRecord;
|
this.messageRecord = messageRecord;
|
||||||
this.mismatch = mismatch;
|
this.mismatch = mismatch;
|
||||||
this.number = number;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -107,7 +98,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
synchronized (SESSION_LOCK) {
|
synchronized (SESSION_LOCK) {
|
||||||
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(number, 1);
|
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(address.toPhoneString(), 1);
|
||||||
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());
|
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());
|
||||||
|
|
||||||
identityKeyStore.saveIdentity(mismatchAddress, mismatch.getIdentityKey(), true);
|
identityKeyStore.saveIdentity(mismatchAddress, mismatch.getIdentityKey(), true);
|
||||||
@ -151,16 +142,16 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||||||
|
|
||||||
if (messageRecord.isMms()) {
|
if (messageRecord.isMms()) {
|
||||||
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
||||||
mismatch.getRecipientId(),
|
mismatch.getAddress(),
|
||||||
mismatch.getIdentityKey());
|
mismatch.getIdentityKey());
|
||||||
|
|
||||||
Recipients recipients = mmsAddressDatabase.getRecipientsForId(messageRecord.getId());
|
Recipients recipients = mmsAddressDatabase.getRecipientsForId(messageRecord.getId());
|
||||||
|
|
||||||
if (recipients.isGroupRecipient()) MessageSender.resendGroupMessage(getContext(), masterSecret, messageRecord, mismatch.getRecipientId());
|
if (recipients.isGroupRecipient()) MessageSender.resendGroupMessage(getContext(), masterSecret, messageRecord, mismatch.getAddress());
|
||||||
else MessageSender.resend(getContext(), masterSecret, messageRecord);
|
else MessageSender.resend(getContext(), masterSecret, messageRecord);
|
||||||
} else {
|
} else {
|
||||||
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
||||||
mismatch.getRecipientId(),
|
mismatch.getAddress(),
|
||||||
mismatch.getIdentityKey());
|
mismatch.getIdentityKey());
|
||||||
|
|
||||||
MessageSender.resend(getContext(), masterSecret, messageRecord);
|
MessageSender.resend(getContext(), masterSecret, messageRecord);
|
||||||
@ -173,13 +164,13 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
|
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
|
||||||
|
|
||||||
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
||||||
mismatch.getRecipientId(),
|
mismatch.getAddress(),
|
||||||
mismatch.getIdentityKey());
|
mismatch.getIdentityKey());
|
||||||
|
|
||||||
boolean legacy = !messageRecord.isContentBundleKeyExchange();
|
boolean legacy = !messageRecord.isContentBundleKeyExchange();
|
||||||
|
|
||||||
SignalServiceEnvelope envelope = new SignalServiceEnvelope(SignalServiceProtos.Envelope.Type.PREKEY_BUNDLE_VALUE,
|
SignalServiceEnvelope envelope = new SignalServiceEnvelope(SignalServiceProtos.Envelope.Type.PREKEY_BUNDLE_VALUE,
|
||||||
messageRecord.getIndividualRecipient().getNumber(),
|
messageRecord.getIndividualRecipient().getAddress().toPhoneString(),
|
||||||
messageRecord.getRecipientDeviceId(), "",
|
messageRecord.getRecipientDeviceId(), "",
|
||||||
messageRecord.getDateSent(),
|
messageRecord.getDateSent(),
|
||||||
legacy ? Base64.decode(messageRecord.getBody().getBody()) : null,
|
legacy ? Base64.decode(messageRecord.getBody().getBody()) : null,
|
||||||
@ -189,8 +180,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
|||||||
|
|
||||||
ApplicationContext.getInstance(getContext())
|
ApplicationContext.getInstance(getContext())
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new PushDecryptJob(getContext(), pushId, messageRecord.getId(),
|
.add(new PushDecryptJob(getContext(), pushId, messageRecord.getId()));
|
||||||
messageRecord.getIndividualRecipient().getNumber()));
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.DraftDatabase;
|
import org.thoughtcrime.securesms.database.DraftDatabase;
|
||||||
import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
|
import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
|
||||||
@ -164,7 +165,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.LinkedList;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
@ -191,7 +192,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
{
|
{
|
||||||
private static final String TAG = ConversationActivity.class.getSimpleName();
|
private static final String TAG = ConversationActivity.class.getSimpleName();
|
||||||
|
|
||||||
public static final String RECIPIENTS_EXTRA = "recipients";
|
public static final String ADDRESSES_EXTRA = "addresses";
|
||||||
public static final String THREAD_ID_EXTRA = "thread_id";
|
public static final String THREAD_ID_EXTRA = "thread_id";
|
||||||
public static final String IS_ARCHIVED_EXTRA = "is_archived";
|
public static final String IS_ARCHIVED_EXTRA = "is_archived";
|
||||||
public static final String TEXT_EXTRA = "draft_text";
|
public static final String TEXT_EXTRA = "draft_text";
|
||||||
@ -409,7 +410,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
addAttachmentContactInfo(data.getData());
|
addAttachmentContactInfo(data.getData());
|
||||||
break;
|
break;
|
||||||
case GROUP_EDIT:
|
case GROUP_EDIT:
|
||||||
recipients = RecipientFactory.getRecipientsForIds(this, data.getLongArrayExtra(GroupCreateActivity.GROUP_RECIPIENT_EXTRA), true);
|
recipients = RecipientFactory.getRecipientsFor(this, RecipientFactory.getRecipientFor(this, (Address)data.getParcelableExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA), true), true);
|
||||||
recipients.addListener(this);
|
recipients.addListener(this);
|
||||||
titleView.setTitle(recipients);
|
titleView.setTitle(recipients);
|
||||||
setBlockedUserState(recipients, isSecureText, isDefaultSms);
|
setBlockedUserState(recipients, isSecureText, isDefaultSms);
|
||||||
@ -421,7 +422,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ADD_CONTACT:
|
case ADD_CONTACT:
|
||||||
recipients = RecipientFactory.getRecipientsForIds(ConversationActivity.this, recipients.getIds(), true);
|
recipients = RecipientFactory.getRecipientsFor(this, recipients.getAddresses(), true);
|
||||||
recipients.addListener(this);
|
recipients.addListener(this);
|
||||||
fragment.reloadList();
|
fragment.reloadList();
|
||||||
break;
|
break;
|
||||||
@ -679,7 +680,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
composeText.appendInvite(inviteText);
|
composeText.appendInvite(inviteText);
|
||||||
} else {
|
} else {
|
||||||
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
||||||
intent.setData(Uri.parse("smsto:" + recipients.getPrimaryRecipient().getNumber()));
|
intent.setData(Uri.parse("smsto:" + recipients.getPrimaryRecipient().getAddress().serialize()));
|
||||||
intent.putExtra("sms_body", inviteText);
|
intent.putExtra("sms_body", inviteText);
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, inviteText);
|
intent.putExtra(Intent.EXTRA_TEXT, inviteText);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
@ -725,7 +726,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private void handleViewMedia() {
|
private void handleViewMedia() {
|
||||||
Intent intent = new Intent(this, MediaOverviewActivity.class);
|
Intent intent = new Intent(this, MediaOverviewActivity.class);
|
||||||
intent.putExtra(MediaOverviewActivity.THREAD_ID_EXTRA, threadId);
|
intent.putExtra(MediaOverviewActivity.THREAD_ID_EXTRA, threadId);
|
||||||
intent.putExtra(MediaOverviewActivity.RECIPIENT_EXTRA, recipients.getPrimaryRecipient().getRecipientId());
|
intent.putExtra(MediaOverviewActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,7 +747,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
Context self = ConversationActivity.this;
|
Context self = ConversationActivity.this;
|
||||||
try {
|
try {
|
||||||
byte[] groupId = GroupUtil.getDecodedId(getRecipients().getPrimaryRecipient().getNumber());
|
byte[] groupId = GroupUtil.getDecodedId(getRecipients().getPrimaryRecipient().getAddress().toGroupString());
|
||||||
DatabaseFactory.getGroupDatabase(self).setActive(groupId, false);
|
DatabaseFactory.getGroupDatabase(self).setActive(groupId, false);
|
||||||
|
|
||||||
GroupContext context = GroupContext.newBuilder()
|
GroupContext context = GroupContext.newBuilder()
|
||||||
@ -756,7 +757,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipients(), context, null, System.currentTimeMillis(), 0);
|
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipients(), context, null, System.currentTimeMillis(), 0);
|
||||||
MessageSender.send(self, masterSecret, outgoingMessage, threadId, false, null);
|
MessageSender.send(self, masterSecret, outgoingMessage, threadId, false, null);
|
||||||
DatabaseFactory.getGroupDatabase(self).remove(groupId, TextSecurePreferences.getLocalNumber(self));
|
DatabaseFactory.getGroupDatabase(self).remove(groupId, Address.fromSerialized(TextSecurePreferences.getLocalNumber(self)));
|
||||||
initializeEnabledCheck();
|
initializeEnabledCheck();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
@ -771,7 +772,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
private void handleEditPushGroup() {
|
private void handleEditPushGroup() {
|
||||||
Intent intent = new Intent(ConversationActivity.this, GroupCreateActivity.class);
|
Intent intent = new Intent(ConversationActivity.this, GroupCreateActivity.class);
|
||||||
intent.putExtra(GroupCreateActivity.GROUP_RECIPIENT_EXTRA, recipients.getPrimaryRecipient().getRecipientId());
|
intent.putExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA, recipients.getPrimaryRecipient().getAddress());
|
||||||
startActivityForResult(intent, GROUP_EDIT);
|
startActivityForResult(intent, GROUP_EDIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,7 +814,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
if (isSecureText) {
|
if (isSecureText) {
|
||||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||||
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL);
|
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL);
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_NUMBER, recipient.getNumber());
|
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, recipient.getAddress());
|
||||||
startService(intent);
|
startService(intent);
|
||||||
|
|
||||||
Intent activityIntent = new Intent(this, WebRtcCallActivity.class);
|
Intent activityIntent = new Intent(this, WebRtcCallActivity.class);
|
||||||
@ -822,7 +823,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
Intent dialIntent = new Intent(Intent.ACTION_DIAL,
|
Intent dialIntent = new Intent(Intent.ACTION_DIAL,
|
||||||
Uri.parse("tel:" + recipient.getNumber()));
|
Uri.parse("tel:" + recipient.getAddress().serialize()));
|
||||||
startActivity(dialIntent);
|
startActivity(dialIntent);
|
||||||
} catch (ActivityNotFoundException anfe) {
|
} catch (ActivityNotFoundException anfe) {
|
||||||
Log.w(TAG, anfe);
|
Log.w(TAG, anfe);
|
||||||
@ -838,9 +839,15 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleAddToContacts() {
|
private void handleAddToContacts() {
|
||||||
|
if (recipients.getPrimaryRecipient().getAddress().isGroup()) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipients.getPrimaryRecipient().getNumber());
|
if (recipients.getPrimaryRecipient().getAddress().isEmail()) {
|
||||||
|
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, recipients.getPrimaryRecipient().getAddress().toEmailString());
|
||||||
|
} else {
|
||||||
|
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipients.getPrimaryRecipient().getAddress().toPhoneString());
|
||||||
|
}
|
||||||
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
||||||
startActivityForResult(intent, ADD_CONTACT);
|
startActivityForResult(intent, ADD_CONTACT);
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
@ -1103,12 +1110,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
if (recipients.isGroupRecipient()) {
|
if (recipients.isGroupRecipient()) {
|
||||||
recipients = DatabaseFactory.getGroupDatabase(ConversationActivity.this)
|
recipients = DatabaseFactory.getGroupDatabase(ConversationActivity.this)
|
||||||
.getGroupMembers(GroupUtil.getDecodedId(recipients.getPrimaryRecipient().getNumber()), false);
|
.getGroupMembers(GroupUtil.getDecodedId(recipients.getPrimaryRecipient().getAddress().toGroupString()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (long recipientId : recipients.getIds()) {
|
for (Address recipientAddress : recipients.getAddresses()) {
|
||||||
Log.w(TAG, "Loading identity for: " + recipientId);
|
Log.w(TAG, "Loading identity for: " + recipientAddress);
|
||||||
identityRecordList.add(identityDatabase.getIdentity(recipientId));
|
identityRecordList.add(identityDatabase.getIdentity(recipientAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
String message = null;
|
String message = null;
|
||||||
@ -1206,7 +1213,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent intent = new Intent(ConversationActivity.this, RecipientPreferenceActivity.class);
|
Intent intent = new Intent(ConversationActivity.this, RecipientPreferenceActivity.class);
|
||||||
intent.putExtra(RecipientPreferenceActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(RecipientPreferenceActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
intent.putExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA,
|
intent.putExtra(RecipientPreferenceActivity.CAN_HAVE_SAFETY_NUMBER_EXTRA,
|
||||||
isSecureText && !isSelfConversation());
|
isSecureText && !isSelfConversation());
|
||||||
|
|
||||||
@ -1253,7 +1260,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private void initializeResources() {
|
private void initializeResources() {
|
||||||
if (recipients != null) recipients.removeListener(this);
|
if (recipients != null) recipients.removeListener(this);
|
||||||
|
|
||||||
recipients = RecipientFactory.getRecipientsForIds(this, getIntent().getLongArrayExtra(RECIPIENTS_EXTRA), true);
|
recipients = RecipientFactory.getRecipientsFor(this, Address.fromParcelable(getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA)), true);
|
||||||
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
|
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
|
||||||
archived = getIntent().getBooleanExtra(IS_ARCHIVED_EXTRA, false);
|
archived = getIntent().getBooleanExtra(IS_ARCHIVED_EXTRA, false);
|
||||||
distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
|
distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
|
||||||
@ -1295,7 +1302,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
public void onRecipientPreferenceUpdate(final RecipientPreferenceEvent event) {
|
public void onRecipientPreferenceUpdate(final RecipientPreferenceEvent event) {
|
||||||
if (event.getRecipients().getSortedIdsString().equals(this.recipients.getSortedIdsString())) {
|
if (Arrays.equals(event.getRecipients().getAddresses(), this.recipients.getAddresses())) {
|
||||||
new RecipientPreferencesTask().execute(this.recipients);
|
new RecipientPreferencesTask().execute(this.recipients);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1319,9 +1326,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Log.w(TAG, "Group update received...");
|
Log.w(TAG, "Group update received...");
|
||||||
if (recipients != null) {
|
if (recipients != null) {
|
||||||
long[] ids = recipients.getIds();
|
|
||||||
Log.w(TAG, "Looking up new recipients...");
|
Log.w(TAG, "Looking up new recipients...");
|
||||||
recipients = RecipientFactory.getRecipientsForIds(context, ids, true);
|
recipients = RecipientFactory.getRecipientsFor(context, recipients.getAddresses(), true);
|
||||||
recipients.addListener(ConversationActivity.this);
|
recipients.addListener(ConversationActivity.this);
|
||||||
onModified(recipients);
|
onModified(recipients);
|
||||||
fragment.reloadList();
|
fragment.reloadList();
|
||||||
@ -1501,7 +1507,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
if (!isGroupConversation()) return false;
|
if (!isGroupConversation()) return false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
byte[] groupId = GroupUtil.getDecodedId(getRecipients().getPrimaryRecipient().getNumber());
|
byte[] groupId = GroupUtil.getDecodedId(getRecipients().getPrimaryRecipient().getAddress().toGroupString());
|
||||||
GroupRecord record = DatabaseFactory.getGroupDatabase(this).getGroup(groupId);
|
GroupRecord record = DatabaseFactory.getGroupDatabase(this).getGroup(groupId);
|
||||||
|
|
||||||
return record != null && record.isActive();
|
return record != null && record.isActive();
|
||||||
@ -1516,7 +1522,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
if (!recipients.isSingleRecipient()) return false;
|
if (!recipients.isSingleRecipient()) return false;
|
||||||
if (recipients.getPrimaryRecipient().isGroupRecipient()) return false;
|
if (recipients.getPrimaryRecipient().isGroupRecipient()) return false;
|
||||||
|
|
||||||
return Util.isOwnNumber(this, recipients.getPrimaryRecipient().getNumber());
|
return Util.isOwnNumber(this, recipients.getPrimaryRecipient().getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isGroupConversation() {
|
private boolean isGroupConversation() {
|
||||||
@ -2000,7 +2006,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
Optional<RecipientsPreferences> prefs = DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
|
Optional<RecipientsPreferences> prefs = DatabaseFactory.getRecipientPreferenceDatabase(ConversationActivity.this)
|
||||||
.getRecipientsPreferences(recipients[0].getIds());
|
.getRecipientsPreferences(recipients[0].getAddresses());
|
||||||
return new Pair<>(recipients[0], prefs.orNull());
|
return new Pair<>(recipients[0], prefs.orNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2023,7 +2029,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
synchronized (SESSION_LOCK) {
|
synchronized (SESSION_LOCK) {
|
||||||
for (IdentityRecord identityRecord : unverifiedIdentities) {
|
for (IdentityRecord identityRecord : unverifiedIdentities) {
|
||||||
identityDatabase.setVerified(identityRecord.getRecipientId(),
|
identityDatabase.setVerified(identityRecord.getAddress(),
|
||||||
identityRecord.getIdentityKey(),
|
identityRecord.getIdentityKey(),
|
||||||
VerifiedStatus.DEFAULT);
|
VerifiedStatus.DEFAULT);
|
||||||
}
|
}
|
||||||
@ -2046,7 +2052,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
Log.w(TAG, "onClicked: " + unverifiedIdentities.size());
|
Log.w(TAG, "onClicked: " + unverifiedIdentities.size());
|
||||||
if (unverifiedIdentities.size() == 1) {
|
if (unverifiedIdentities.size() == 1) {
|
||||||
Intent intent = new Intent(ConversationActivity.this, VerifyIdentityActivity.class);
|
Intent intent = new Intent(ConversationActivity.this, VerifyIdentityActivity.class);
|
||||||
intent.putExtra(VerifyIdentityActivity.RECIPIENT_ID_EXTRA, unverifiedIdentities.get(0).getRecipientId());
|
intent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, unverifiedIdentities.get(0).getAddress());
|
||||||
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(unverifiedIdentities.get(0).getIdentityKey()));
|
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(unverifiedIdentities.get(0).getIdentityKey()));
|
||||||
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, false);
|
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, false);
|
||||||
|
|
||||||
@ -2055,7 +2061,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
String[] unverifiedNames = new String[unverifiedIdentities.size()];
|
String[] unverifiedNames = new String[unverifiedIdentities.size()];
|
||||||
|
|
||||||
for (int i=0;i<unverifiedIdentities.size();i++) {
|
for (int i=0;i<unverifiedIdentities.size();i++) {
|
||||||
unverifiedNames[i] = RecipientFactory.getRecipientForId(ConversationActivity.this, unverifiedIdentities.get(i).getRecipientId(), false).toShortString();
|
unverifiedNames[i] = RecipientFactory.getRecipientFor(ConversationActivity.this, unverifiedIdentities.get(i).getAddress(), false).toShortString();
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(ConversationActivity.this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(ConversationActivity.this);
|
||||||
@ -2065,7 +2071,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
Intent intent = new Intent(ConversationActivity.this, VerifyIdentityActivity.class);
|
Intent intent = new Intent(ConversationActivity.this, VerifyIdentityActivity.class);
|
||||||
intent.putExtra(VerifyIdentityActivity.RECIPIENT_ID_EXTRA, unverifiedIdentities.get(which).getRecipientId());
|
intent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, unverifiedIdentities.get(which).getAddress());
|
||||||
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(unverifiedIdentities.get(which).getIdentityKey()));
|
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(unverifiedIdentities.get(which).getIdentityKey()));
|
||||||
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, false);
|
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, false);
|
||||||
|
|
||||||
|
@ -53,19 +53,14 @@ import android.widget.Toast;
|
|||||||
import org.thoughtcrime.securesms.ConversationAdapter.HeaderViewHolder;
|
import org.thoughtcrime.securesms.ConversationAdapter.HeaderViewHolder;
|
||||||
import org.thoughtcrime.securesms.ConversationAdapter.ItemClickListener;
|
import org.thoughtcrime.securesms.ConversationAdapter.ItemClickListener;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
|
||||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
|
||||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
|
||||||
import org.thoughtcrime.securesms.database.loaders.ConversationLoader;
|
import org.thoughtcrime.securesms.database.loaders.ConversationLoader;
|
||||||
import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
@ -76,8 +71,6 @@ import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
|||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -191,8 +184,8 @@ public class ConversationFragment extends Fragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeResources() {
|
private void initializeResources() {
|
||||||
this.recipients = RecipientFactory.getRecipientsForIds(getActivity(), getActivity().getIntent().getLongArrayExtra("recipients"), true);
|
this.recipients = RecipientFactory.getRecipientsFor(getActivity(), Address.fromParcelable(getActivity().getIntent().getParcelableArrayExtra(ConversationActivity.ADDRESSES_EXTRA)), true);
|
||||||
this.threadId = this.getActivity().getIntent().getLongExtra("thread_id", -1);
|
this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1);
|
||||||
this.lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1);
|
this.lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1);
|
||||||
this.firstLoad = true;
|
this.firstLoad = true;
|
||||||
|
|
||||||
@ -366,7 +359,7 @@ public class ConversationFragment extends Fragment
|
|||||||
intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, message.getId());
|
intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, message.getId());
|
||||||
intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, threadId);
|
intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, threadId);
|
||||||
intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, message.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
|
intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, message.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
|
||||||
intent.putExtra(MessageDetailsActivity.RECIPIENTS_IDS_EXTRA, recipients.getIds());
|
intent.putExtra(MessageDetailsActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, (!recipients.isSingleRecipient() || recipients.isGroupRecipient()) && message.isPush());
|
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, (!recipients.isSingleRecipient() || recipients.isGroupRecipient()) && message.isPush());
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
@ -578,7 +578,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
Intent intent = new Intent(context, MediaPreviewActivity.class);
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
intent.setDataAndType(slide.getUri(), slide.getContentType());
|
intent.setDataAndType(slide.getUri(), slide.getContentType());
|
||||||
if (!messageRecord.isOutgoing()) intent.putExtra(MediaPreviewActivity.RECIPIENT_EXTRA, recipient.getRecipientId());
|
if (!messageRecord.isOutgoing()) intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, recipient.getAddress());
|
||||||
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, messageRecord.getTimestamp());
|
intent.putExtra(MediaPreviewActivity.DATE_EXTRA, messageRecord.getTimestamp());
|
||||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize());
|
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize());
|
||||||
intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, messageRecord.getThreadId());
|
intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, messageRecord.getThreadId());
|
||||||
@ -635,7 +635,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, messageRecord.getThreadId());
|
intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, messageRecord.getThreadId());
|
||||||
intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, messageRecord.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
|
intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, messageRecord.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
|
||||||
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, groupThread && messageRecord.isPush());
|
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, groupThread && messageRecord.isPush());
|
||||||
intent.putExtra(MessageDetailsActivity.RECIPIENTS_IDS_EXTRA, conversationRecipients.getIds());
|
intent.putExtra(MessageDetailsActivity.ADDRESSES_EXTRA, conversationRecipients.getAddresses());
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
} else if (!messageRecord.isOutgoing() && messageRecord.isIdentityMismatchFailure()) {
|
} else if (!messageRecord.isOutgoing() && messageRecord.isIdentityMismatchFailure()) {
|
||||||
handleApproveIdentity();
|
handleApproveIdentity();
|
||||||
@ -680,7 +680,7 @@ public class ConversationItem extends LinearLayout
|
|||||||
ApplicationContext.getInstance(context)
|
ApplicationContext.getInstance(context)
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new SmsSendJob(context, messageRecord.getId(),
|
.add(new SmsSendJob(context, messageRecord.getId(),
|
||||||
messageRecord.getIndividualRecipient().getNumber()));
|
messageRecord.getIndividualRecipient().getAddress().serialize()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -24,10 +24,10 @@ import android.os.AsyncTask;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.app.ActionBar;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.support.v4.view.MenuItemCompat;
|
import android.support.v4.view.MenuItemCompat;
|
||||||
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.widget.SearchView;
|
import android.support.v7.widget.SearchView;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@ -39,7 +39,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.service.DirectoryRefreshListener;
|
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
@ -163,7 +162,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
|||||||
@Override
|
@Override
|
||||||
public void onCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeen) {
|
public void onCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeen) {
|
||||||
Intent intent = new Intent(this, ConversationActivity.class);
|
Intent intent = new Intent(this, ConversationActivity.class);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
||||||
intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis());
|
intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis());
|
||||||
|
@ -29,6 +29,7 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
@ -79,8 +80,8 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
|
|||||||
ThreadRecord record = getThreadRecord(cursor);
|
ThreadRecord record = getThreadRecord(cursor);
|
||||||
StringBuilder builder = new StringBuilder("" + record.getThreadId());
|
StringBuilder builder = new StringBuilder("" + record.getThreadId());
|
||||||
|
|
||||||
for (long recipientId : record.getRecipients().getIds()) {
|
for (Address address : record.getRecipients().getAddresses()) {
|
||||||
builder.append("::").append(recipientId);
|
builder.append("::").append(address.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Conversions.byteArrayToLong(digest.digest(builder.toString().getBytes()));
|
return Conversions.byteArrayToLong(digest.digest(builder.toString().getBytes()));
|
||||||
|
@ -56,7 +56,7 @@ public class ConversationListArchiveActivity extends PassphraseRequiredActionBar
|
|||||||
@Override
|
@Override
|
||||||
public void onCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeenTime) {
|
public void onCreateConversation(long threadId, Recipients recipients, int distributionType, long lastSeenTime) {
|
||||||
Intent intent = new Intent(this, ConversationActivity.class);
|
Intent intent = new Intent(this, ConversationActivity.class);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||||
intent.putExtra(ConversationActivity.IS_ARCHIVED_EXTRA, true);
|
intent.putExtra(ConversationActivity.IS_ARCHIVED_EXTRA, true);
|
||||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
||||||
|
@ -84,7 +84,7 @@ public class ConversationPopupActivity extends ConversationActivity {
|
|||||||
public void onSuccess(Long result) {
|
public void onSuccess(Long result) {
|
||||||
ActivityOptionsCompat transition = ActivityOptionsCompat.makeScaleUpAnimation(getWindow().getDecorView(), 0, 0, getWindow().getAttributes().width, getWindow().getAttributes().height);
|
ActivityOptionsCompat transition = ActivityOptionsCompat.makeScaleUpAnimation(getWindow().getDecorView(), 0, 0, getWindow().getAttributes().width, getWindow().getAttributes().height);
|
||||||
Intent intent = new Intent(ConversationPopupActivity.this, ConversationActivity.class);
|
Intent intent = new Intent(ConversationPopupActivity.this, ConversationActivity.class);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, getRecipients().getIds());
|
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, getRecipients().getAddresses());
|
||||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, result);
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, result);
|
||||||
|
|
||||||
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
|
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
|
||||||
|
@ -69,14 +69,14 @@ public class ConversationTitleView extends LinearLayout {
|
|||||||
private void setRecipientTitle(Recipient recipient) {
|
private void setRecipientTitle(Recipient recipient) {
|
||||||
if (!recipient.isGroupRecipient()) {
|
if (!recipient.isGroupRecipient()) {
|
||||||
if (TextUtils.isEmpty(recipient.getName())) {
|
if (TextUtils.isEmpty(recipient.getName())) {
|
||||||
this.title.setText(recipient.getNumber());
|
this.title.setText(recipient.getAddress().serialize());
|
||||||
this.subtitle.setText(null);
|
this.subtitle.setText(null);
|
||||||
this.subtitle.setVisibility(View.GONE);
|
this.subtitle.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
this.title.setText(recipient.getName());
|
this.title.setText(recipient.getName());
|
||||||
|
|
||||||
if (recipient.getCustomLabel() != null) this.subtitle.setText(recipient.getCustomLabel());
|
if (recipient.getCustomLabel() != null) this.subtitle.setText(recipient.getCustomLabel());
|
||||||
else this.subtitle.setText(recipient.getNumber());
|
else this.subtitle.setText(recipient.getAddress().serialize());
|
||||||
|
|
||||||
this.subtitle.setVisibility(View.VISIBLE);
|
this.subtitle.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ public class ConversationUpdateItem extends LinearLayout
|
|||||||
public void onSuccess(Optional<IdentityRecord> result) {
|
public void onSuccess(Optional<IdentityRecord> result) {
|
||||||
if (result.isPresent()) {
|
if (result.isPresent()) {
|
||||||
Intent intent = new Intent(getContext(), VerifyIdentityActivity.class);
|
Intent intent = new Intent(getContext(), VerifyIdentityActivity.class);
|
||||||
intent.putExtra(VerifyIdentityActivity.RECIPIENT_ID_EXTRA, sender.getRecipientId());
|
intent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, sender.getAddress());
|
||||||
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(result.get().getIdentityKey()));
|
intent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(result.get().getIdentityKey()));
|
||||||
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, result.get().getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
|
intent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, result.get().getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||||||
public static final int CONTACTS_ACCOUNT_VERSION = 136;
|
public static final int CONTACTS_ACCOUNT_VERSION = 136;
|
||||||
public static final int MEDIA_DOWNLOAD_CONTROLS_VERSION = 151;
|
public static final int MEDIA_DOWNLOAD_CONTROLS_VERSION = 151;
|
||||||
public static final int REDPHONE_SUPPORT_VERSION = 157;
|
public static final int REDPHONE_SUPPORT_VERSION = 157;
|
||||||
// public static final int FINGERPRINTS_NON_BLOCKING_VESRION = 212;
|
public static final int NO_MORE_CANONICAL_DB_VERSION = 276;
|
||||||
|
|
||||||
private static final SortedSet<Integer> UPGRADE_VERSIONS = new TreeSet<Integer>() {{
|
private static final SortedSet<Integer> UPGRADE_VERSIONS = new TreeSet<Integer>() {{
|
||||||
add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION);
|
add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION);
|
||||||
@ -82,7 +82,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||||||
add(MIGRATE_SESSION_PLAINTEXT);
|
add(MIGRATE_SESSION_PLAINTEXT);
|
||||||
add(MEDIA_DOWNLOAD_CONTROLS_VERSION);
|
add(MEDIA_DOWNLOAD_CONTROLS_VERSION);
|
||||||
add(REDPHONE_SUPPORT_VERSION);
|
add(REDPHONE_SUPPORT_VERSION);
|
||||||
// add(FINGERPRINTS_NON_BLOCKING_VESRION);
|
add(NO_MORE_CANONICAL_DB_VERSION);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
private MasterSecret masterSecret;
|
private MasterSecret masterSecret;
|
||||||
@ -233,10 +233,6 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||||||
.add(new DirectoryRefreshJob(getApplicationContext()));
|
.add(new DirectoryRefreshJob(getApplicationContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (params[0] < FINGERPRINTS_NON_BLOCKING_VESRION) {
|
|
||||||
// TextSecurePreferences.setBlockingIdentityUpdates(getApplicationContext(), true);
|
|
||||||
// }
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,8 +270,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||||||
ApplicationContext.getInstance(getApplicationContext())
|
ApplicationContext.getInstance(getApplicationContext())
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new PushDecryptJob(getApplicationContext(),
|
.add(new PushDecryptJob(getApplicationContext(),
|
||||||
pushReader.getLong(pushReader.getColumnIndexOrThrow(PushDatabase.ID)),
|
pushReader.getLong(pushReader.getColumnIndexOrThrow(PushDatabase.ID))));
|
||||||
pushReader.getString(pushReader.getColumnIndexOrThrow(PushDatabase.SOURCE))));
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (pushReader != null)
|
if (pushReader != null)
|
||||||
|
@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.contacts.RecipientsEditor;
|
|||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
@ -66,12 +67,11 @@ import org.thoughtcrime.securesms.util.BitmapUtil;
|
|||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
|
||||||
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter;
|
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter;
|
||||||
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter.OnRecipientDeletedListener;
|
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter.OnRecipientDeletedListener;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||||
|
|
||||||
@ -95,8 +95,8 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
private final static String TAG = GroupCreateActivity.class.getSimpleName();
|
private final static String TAG = GroupCreateActivity.class.getSimpleName();
|
||||||
|
|
||||||
public static final String GROUP_RECIPIENT_EXTRA = "group_recipient";
|
public static final String GROUP_ADDRESS_EXTRA = "group_recipient";
|
||||||
public static final String GROUP_THREAD_EXTRA = "group_thread";
|
public static final String GROUP_THREAD_EXTRA = "group_thread";
|
||||||
|
|
||||||
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||||
@ -174,9 +174,8 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
private static boolean isActiveInDirectory(Context context, Recipient recipient) {
|
private static boolean isActiveInDirectory(Context context, Recipient recipient) {
|
||||||
try {
|
try {
|
||||||
return TextSecureDirectory.getInstance(context)
|
return TextSecureDirectory.getInstance(context).isSecureTextSupported(recipient.getAddress());
|
||||||
.isSecureTextSupported(Util.canonicalizeNumber(context, recipient.getNumber()));
|
} catch (NotInDirectoryException e) {
|
||||||
} catch (NotInDirectoryException | InvalidNumberException e) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,11 +212,13 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeExistingGroup() {
|
private void initializeExistingGroup() {
|
||||||
final String encodedGroupId = RecipientFactory.getRecipientForId(this, getIntent().getLongExtra(GROUP_RECIPIENT_EXTRA, -1), true)
|
final Address groupAddress = getIntent().getParcelableExtra(GROUP_ADDRESS_EXTRA);
|
||||||
.getNumber();
|
|
||||||
byte[] groupId;
|
byte[] groupId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
groupId = GroupUtil.getDecodedId(encodedGroupId);
|
if (groupAddress != null) groupId = GroupUtil.getDecodedId(groupAddress.toGroupString());
|
||||||
|
else groupId = null;
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
Log.w(TAG, "Couldn't decode the encoded groupId passed in via intent", ioe);
|
Log.w(TAG, "Couldn't decode the encoded groupId passed in via intent", ioe);
|
||||||
groupId = null;
|
groupId = null;
|
||||||
@ -286,7 +287,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
Intent intent = new Intent(this, ConversationActivity.class);
|
Intent intent = new Intent(this, ConversationActivity.class);
|
||||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
|
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
@ -310,9 +311,12 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
switch (reqCode) {
|
switch (reqCode) {
|
||||||
case PICK_CONTACT:
|
case PICK_CONTACT:
|
||||||
List<String> selected = data.getStringArrayListExtra("contacts");
|
List<String> selected = data.getStringArrayListExtra("contacts");
|
||||||
|
|
||||||
for (String contact : selected) {
|
for (String contact : selected) {
|
||||||
final Recipient recipient = RecipientFactory.getRecipientsFromString(this, contact, false).getPrimaryRecipient();
|
Address address = Address.fromExternal(this, contact);
|
||||||
if (recipient != null) addSelectedContacts(recipient);
|
Recipient recipient = RecipientFactory.getRecipientFor(this, address, false);
|
||||||
|
|
||||||
|
addSelectedContacts(recipient);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -470,7 +474,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
if (!activity.isFinishing()) {
|
if (!activity.isFinishing()) {
|
||||||
Intent intent = activity.getIntent();
|
Intent intent = activity.getIntent();
|
||||||
intent.putExtra(GROUP_THREAD_EXTRA, result.get().getThreadId());
|
intent.putExtra(GROUP_THREAD_EXTRA, result.get().getThreadId());
|
||||||
intent.putExtra(GROUP_RECIPIENT_EXTRA, result.get().getGroupRecipient().getIds());
|
intent.putExtra(GROUP_ADDRESS_EXTRA, result.get().getGroupRecipient().getPrimaryRecipient().getAddress());
|
||||||
activity.setResult(RESULT_OK, intent);
|
activity.setResult(RESULT_OK, intent);
|
||||||
activity.finish();
|
activity.finish();
|
||||||
}
|
}
|
||||||
@ -508,16 +512,12 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
|
|||||||
final List<Result> results = new LinkedList<>();
|
final List<Result> results = new LinkedList<>();
|
||||||
|
|
||||||
for (Recipient recipient : recipients) {
|
for (Recipient recipient : recipients) {
|
||||||
boolean isPush = isActiveInDirectory(activity, recipient);
|
boolean isPush = isActiveInDirectory(activity, recipient);
|
||||||
String recipientE164 = null;
|
|
||||||
try {
|
|
||||||
recipientE164 = Util.canonicalizeNumber(activity, recipient.getNumber());
|
|
||||||
} catch (InvalidNumberException ine) { /* do nothing */ }
|
|
||||||
|
|
||||||
if (failIfNotPush && !isPush) {
|
if (failIfNotPush && !isPush) {
|
||||||
results.add(new Result(null, false, activity.getString(R.string.GroupCreateActivity_cannot_add_non_push_to_existing_group,
|
results.add(new Result(null, false, activity.getString(R.string.GroupCreateActivity_cannot_add_non_push_to_existing_group,
|
||||||
recipient.getNumber())));
|
recipient.toShortString())));
|
||||||
} else if (TextUtils.equals(TextSecurePreferences.getLocalNumber(activity), recipientE164)) {
|
} else if (TextUtils.equals(TextSecurePreferences.getLocalNumber(activity), recipient.getAddress().serialize())) {
|
||||||
results.add(new Result(null, false, activity.getString(R.string.GroupCreateActivity_youre_already_in_the_group)));
|
results.add(new Result(null, false, activity.getString(R.string.GroupCreateActivity_youre_already_in_the_group)));
|
||||||
} else {
|
} else {
|
||||||
results.add(new Result(recipient, isPush, null));
|
results.add(new Result(recipient, isPush, null));
|
||||||
|
@ -14,9 +14,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
|||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -40,7 +38,7 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, Recipients> {
|
|||||||
@Override
|
@Override
|
||||||
protected Recipients doInBackground(Void... params) {
|
protected Recipients doInBackground(Void... params) {
|
||||||
try {
|
try {
|
||||||
String groupId = recipients.getPrimaryRecipient().getNumber();
|
String groupId = recipients.getPrimaryRecipient().getAddress().toGroupString();
|
||||||
return DatabaseFactory.getGroupDatabase(context)
|
return DatabaseFactory.getGroupDatabase(context)
|
||||||
.getGroupMembers(GroupUtil.getDecodedId(groupId), true);
|
.getGroupMembers(GroupUtil.getDecodedId(groupId), true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -85,7 +83,11 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, Recipients> {
|
|||||||
ContactsContract.QuickContact.MODE_LARGE, null);
|
ContactsContract.QuickContact.MODE_LARGE, null);
|
||||||
} else {
|
} else {
|
||||||
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getNumber());
|
if (recipient.getAddress().isEmail()) {
|
||||||
|
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, recipient.getAddress().toEmailString());
|
||||||
|
} else {
|
||||||
|
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getAddress().toPhoneString());
|
||||||
|
}
|
||||||
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
@ -134,15 +136,7 @@ public class GroupMembersDialog extends AsyncTask<Void, Void, Recipients> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLocalNumber(Recipient recipient) {
|
private boolean isLocalNumber(Recipient recipient) {
|
||||||
try {
|
return Util.isOwnNumber(context, recipient.getAddress());
|
||||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
|
||||||
String e164Number = Util.canonicalizeNumber(context, recipient.getNumber());
|
|
||||||
|
|
||||||
return e164Number != null && e164Number.equals(localNumber);
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import android.widget.Toast;
|
|||||||
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
|
import org.thoughtcrime.securesms.components.ContactFilterToolbar;
|
||||||
import org.thoughtcrime.securesms.components.ContactFilterToolbar.OnFilterChangedListener;
|
import org.thoughtcrime.securesms.components.ContactFilterToolbar.OnFilterChangedListener;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
@ -230,10 +231,10 @@ public class InviteActivity extends PassphraseRequiredActionBarActivity implemen
|
|||||||
if (context == null) return null;
|
if (context == null) return null;
|
||||||
|
|
||||||
for (String number : numbers) {
|
for (String number : numbers) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, number, false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, number)}, false);
|
||||||
|
|
||||||
if (recipients.getPrimaryRecipient() != null) {
|
if (recipients.getPrimaryRecipient() != null) {
|
||||||
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipients.getIds());
|
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipients.getAddresses());
|
||||||
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
||||||
|
|
||||||
MessageSender.send(context, masterSecret, new OutgoingTextMessage(recipients, message, subscriptionId), -1L, true, null);
|
MessageSender.send(context, masterSecret, new OutgoingTextMessage(recipients, message, subscriptionId), -1L, true, null);
|
||||||
|
@ -21,7 +21,6 @@ import android.content.Intent;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
@ -33,8 +32,6 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
|
|||||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
|
|
||||||
public class MediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
|
public class MediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
|
||||||
@ -93,14 +90,10 @@ public class MediaAdapter extends CursorRecyclerViewAdapter<ViewHolder> {
|
|||||||
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
|
intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, mediaRecord.getAttachment().getSize());
|
||||||
intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, threadId);
|
intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, threadId);
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(mediaRecord.getAddress())) {
|
if (mediaRecord.getAddress() != null) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(getContext(),
|
intent.putExtra(MediaPreviewActivity.ADDRESS_EXTRA, mediaRecord.getAddress());
|
||||||
mediaRecord.getAddress(),
|
|
||||||
true);
|
|
||||||
if (recipients != null && recipients.getPrimaryRecipient() != null) {
|
|
||||||
intent.putExtra(MediaPreviewActivity.RECIPIENT_EXTRA, recipients.getPrimaryRecipient().getRecipientId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.setDataAndType(mediaRecord.getAttachment().getDataUri(), mediaRecord.getContentType());
|
intent.setDataAndType(mediaRecord.getAttachment().getDataUri(), mediaRecord.getContentType());
|
||||||
getContext().startActivity(intent);
|
getContext().startActivity(intent);
|
||||||
}
|
}
|
||||||
|
@ -38,12 +38,12 @@ import android.view.WindowManager;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
|
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
|
||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
import org.thoughtcrime.securesms.util.SaveAttachmentTask;
|
||||||
@ -58,7 +58,7 @@ import java.util.List;
|
|||||||
public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor> {
|
public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||||
private final static String TAG = MediaOverviewActivity.class.getSimpleName();
|
private final static String TAG = MediaOverviewActivity.class.getSimpleName();
|
||||||
|
|
||||||
public static final String RECIPIENT_EXTRA = "recipient";
|
public static final String ADDRESSES_EXTRA = "addresses";
|
||||||
public static final String THREAD_ID_EXTRA = "thread_id";
|
public static final String THREAD_ID_EXTRA = "thread_id";
|
||||||
|
|
||||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||||
@ -68,7 +68,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
|
|||||||
private RecyclerView gridView;
|
private RecyclerView gridView;
|
||||||
private GridLayoutManager gridManager;
|
private GridLayoutManager gridManager;
|
||||||
private TextView noImages;
|
private TextView noImages;
|
||||||
private Recipient recipient;
|
private Recipients recipients;
|
||||||
private long threadId;
|
private long threadId;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -113,9 +113,9 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeActionBar() {
|
private void initializeActionBar() {
|
||||||
getSupportActionBar().setTitle(recipient == null
|
getSupportActionBar().setTitle(recipients == null
|
||||||
? getString(R.string.AndroidManifest__all_media)
|
? getString(R.string.AndroidManifest__all_media)
|
||||||
: getString(R.string.AndroidManifest__all_media_named, recipient.toShortString()));
|
: getString(R.string.AndroidManifest__all_media_named, recipients.toShortString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -132,19 +132,20 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity i
|
|||||||
gridView.setLayoutManager(gridManager);
|
gridView.setLayoutManager(gridManager);
|
||||||
gridView.setHasFixedSize(true);
|
gridView.setHasFixedSize(true);
|
||||||
|
|
||||||
final long recipientId = getIntent().getLongExtra(RECIPIENT_EXTRA, -1);
|
Address[] addresses = Address.fromParcelable(getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA));
|
||||||
if (recipientId > -1) {
|
|
||||||
recipient = RecipientFactory.getRecipientForId(this, recipientId, true);
|
if (addresses != null) {
|
||||||
} else if (threadId > -1){
|
recipients = RecipientFactory.getRecipientsFor(this, addresses, true);
|
||||||
recipient = DatabaseFactory.getThreadDatabase(this).getRecipientsForThreadId(threadId).getPrimaryRecipient();
|
} else if (threadId > -1) {
|
||||||
|
recipients = DatabaseFactory.getThreadDatabase(this).getRecipientsForThreadId(threadId);
|
||||||
} else {
|
} else {
|
||||||
recipient = null;
|
recipients = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recipient != null) {
|
if (recipients != null) {
|
||||||
recipient.addListener(new RecipientModifiedListener() {
|
recipients.addListener(new Recipients.RecipientsModifiedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onModified(Recipient recipient) {
|
public void onModified(Recipients recipients) {
|
||||||
initializeActionBar();
|
initializeActionBar();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -34,6 +34,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.components.ZoomingImageView;
|
import org.thoughtcrime.securesms.components.ZoomingImageView;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.mms.VideoSlide;
|
import org.thoughtcrime.securesms.mms.VideoSlide;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
|
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
|
||||||
@ -52,7 +53,7 @@ import java.io.IOException;
|
|||||||
public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener {
|
public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener {
|
||||||
private final static String TAG = MediaPreviewActivity.class.getSimpleName();
|
private final static String TAG = MediaPreviewActivity.class.getSimpleName();
|
||||||
|
|
||||||
public static final String RECIPIENT_EXTRA = "recipient";
|
public static final String ADDRESS_EXTRA = "address";
|
||||||
public static final String THREAD_ID_EXTRA = "thread_id";
|
public static final String THREAD_ID_EXTRA = "thread_id";
|
||||||
public static final String DATE_EXTRA = "date";
|
public static final String DATE_EXTRA = "date";
|
||||||
public static final String SIZE_EXTRA = "size";
|
public static final String SIZE_EXTRA = "size";
|
||||||
@ -143,7 +144,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeResources() {
|
private void initializeResources() {
|
||||||
final long recipientId = getIntent().getLongExtra(RECIPIENT_EXTRA, -1);
|
Address address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
|
||||||
|
|
||||||
mediaUri = getIntent().getData();
|
mediaUri = getIntent().getData();
|
||||||
mediaType = getIntent().getType();
|
mediaType = getIntent().getType();
|
||||||
@ -151,8 +152,8 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
|
|||||||
size = getIntent().getLongExtra(SIZE_EXTRA, 0);
|
size = getIntent().getLongExtra(SIZE_EXTRA, 0);
|
||||||
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
|
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
|
||||||
|
|
||||||
if (recipientId > -1) {
|
if (address != null) {
|
||||||
recipient = RecipientFactory.getRecipientForId(this, recipientId, true);
|
recipient = RecipientFactory.getRecipientFor(this, address, true);
|
||||||
recipient.addListener(this);
|
recipient.addListener(this);
|
||||||
} else {
|
} else {
|
||||||
recipient = null;
|
recipient = null;
|
||||||
|
@ -36,6 +36,7 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
@ -73,7 +74,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||||||
public final static String THREAD_ID_EXTRA = "thread_id";
|
public final static String THREAD_ID_EXTRA = "thread_id";
|
||||||
public final static String IS_PUSH_GROUP_EXTRA = "is_push_group";
|
public final static String IS_PUSH_GROUP_EXTRA = "is_push_group";
|
||||||
public final static String TYPE_EXTRA = "type";
|
public final static String TYPE_EXTRA = "type";
|
||||||
public final static String RECIPIENTS_IDS_EXTRA = "recipients_ids";
|
public final static String ADDRESSES_EXTRA = "addresses";
|
||||||
|
|
||||||
private MasterSecret masterSecret;
|
private MasterSecret masterSecret;
|
||||||
private long threadId;
|
private long threadId;
|
||||||
@ -138,7 +139,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||||||
private void initializeActionBar() {
|
private void initializeActionBar() {
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsForIds(this, getIntent().getLongArrayExtra(RECIPIENTS_IDS_EXTRA), true);
|
Recipients recipients = RecipientFactory.getRecipientsFor(this, Address.fromParcelable(getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA)), true);
|
||||||
recipients.addListener(this);
|
recipients.addListener(this);
|
||||||
|
|
||||||
setActionBarColor(recipients.getColor());
|
setActionBarColor(recipients.getColor());
|
||||||
@ -355,9 +356,9 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||||||
recipients = intermediaryRecipients;
|
recipients = intermediaryRecipients;
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
String groupId = intermediaryRecipients.getPrimaryRecipient().getNumber();
|
Address groupId = intermediaryRecipients.getPrimaryRecipient().getAddress();
|
||||||
recipients = DatabaseFactory.getGroupDatabase(context)
|
recipients = DatabaseFactory.getGroupDatabase(context)
|
||||||
.getGroupMembers(GroupUtil.getDecodedId(groupId), false);
|
.getGroupMembers(GroupUtil.getDecodedId(groupId.toGroupString()), false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
recipients = RecipientFactory.getRecipientsFor(MessageDetailsActivity.this, new LinkedList<Recipient>(), false);
|
recipients = RecipientFactory.getRecipientsFor(MessageDetailsActivity.this, new LinkedList<Recipient>(), false);
|
||||||
|
@ -11,6 +11,10 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
|
|||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
|
import org.thoughtcrime.securesms.util.Conversions;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
public class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.RecyclerListener {
|
public class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.RecyclerListener {
|
||||||
|
|
||||||
@ -43,7 +47,11 @@ public class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsLi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position) {
|
||||||
return recipients.getRecipientsList().get(position).getRecipientId();
|
try {
|
||||||
|
return Conversions.byteArrayToLong(MessageDigest.getInstance("SHA1").digest(recipients.getRecipientsList().get(position).getAddress().serialize().getBytes()));
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -137,7 +137,7 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||||||
private NetworkFailure getNetworkFailure(final MessageRecord record) {
|
private NetworkFailure getNetworkFailure(final MessageRecord record) {
|
||||||
if (record.hasNetworkFailures()) {
|
if (record.hasNetworkFailures()) {
|
||||||
for (final NetworkFailure failure : record.getNetworkFailures()) {
|
for (final NetworkFailure failure : record.getNetworkFailures()) {
|
||||||
if (failure.getRecipientId() == recipient.getRecipientId()) {
|
if (failure.getAddress().equals(recipient.getAddress())) {
|
||||||
return failure;
|
return failure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,7 +148,7 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||||||
private IdentityKeyMismatch getKeyMismatch(final MessageRecord record) {
|
private IdentityKeyMismatch getKeyMismatch(final MessageRecord record) {
|
||||||
if (record.isIdentityMismatchFailure()) {
|
if (record.isIdentityMismatchFailure()) {
|
||||||
for (final IdentityKeyMismatch mismatch : record.getIdentityKeyMismatches()) {
|
for (final IdentityKeyMismatch mismatch : record.getIdentityKeyMismatches()) {
|
||||||
if (mismatch.getRecipientId() == recipient.getRecipientId()) {
|
if (mismatch.getAddress().equals(recipient.getAddress())) {
|
||||||
return mismatch;
|
return mismatch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +188,7 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||||||
mmsDatabase.removeFailure(record.getId(), failure);
|
mmsDatabase.removeFailure(record.getId(), failure);
|
||||||
|
|
||||||
if (record.getRecipients().isGroupRecipient()) {
|
if (record.getRecipients().isGroupRecipient()) {
|
||||||
MessageSender.resendGroupMessage(getContext(), masterSecret, record, failure.getRecipientId());
|
MessageSender.resendGroupMessage(getContext(), masterSecret, record, failure.getAddress());
|
||||||
} else {
|
} else {
|
||||||
MessageSender.resend(getContext(), masterSecret, record);
|
MessageSender.resend(getContext(), masterSecret, record);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
@ -49,10 +50,10 @@ public class NewConversationActivity extends ContactSelectionActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onContactSelected(String number) {
|
public void onContactSelected(String number) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(this, number, true);
|
Recipients recipients = RecipientFactory.getRecipientsFor(this, new Address[] {Address.fromExternal(this, number)}, true);
|
||||||
|
|
||||||
Intent intent = new Intent(this, ConversationActivity.class);
|
Intent intent = new Intent(this, ConversationActivity.class);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA));
|
intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA));
|
||||||
intent.setDataAndType(getIntent().getData(), getIntent().getType());
|
intent.setDataAndType(getIntent().getData(), getIntent().getType());
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.color.MaterialColors;
|
|||||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
@ -48,7 +49,6 @@ import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
|||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@ -57,7 +57,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
{
|
{
|
||||||
private static final String TAG = RecipientPreferenceActivity.class.getSimpleName();
|
private static final String TAG = RecipientPreferenceActivity.class.getSimpleName();
|
||||||
|
|
||||||
public static final String RECIPIENTS_EXTRA = "recipient_ids";
|
public static final String ADDRESSES_EXTRA = "recipient_addresses";
|
||||||
public static final String CAN_HAVE_SAFETY_NUMBER_EXTRA = "can_have_safety_number";
|
public static final String CAN_HAVE_SAFETY_NUMBER_EXTRA = "can_have_safety_number";
|
||||||
|
|
||||||
private static final String PREFERENCE_MUTED = "pref_key_recipient_mute";
|
private static final String PREFERENCE_MUTED = "pref_key_recipient_mute";
|
||||||
@ -86,8 +86,8 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
public void onCreate(Bundle instanceState, @NonNull MasterSecret masterSecret) {
|
public void onCreate(Bundle instanceState, @NonNull MasterSecret masterSecret) {
|
||||||
setContentView(R.layout.recipient_preference_activity);
|
setContentView(R.layout.recipient_preference_activity);
|
||||||
|
|
||||||
long[] recipientIds = getIntent().getLongArrayExtra(RECIPIENTS_EXTRA);
|
Address[] addresses = Address.fromParcelable(getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA));
|
||||||
Recipients recipients = RecipientFactory.getRecipientsForIds(this, recipientIds, true);
|
Recipients recipients = RecipientFactory.getRecipientsFor(this, addresses, true);
|
||||||
|
|
||||||
initializeToolbar();
|
initializeToolbar();
|
||||||
initializeReceivers();
|
initializeReceivers();
|
||||||
@ -95,7 +95,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
recipients.addListener(this);
|
recipients.addListener(this);
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putLongArray(RECIPIENTS_EXTRA, recipientIds);
|
bundle.putParcelableArray(ADDRESSES_EXTRA, addresses);
|
||||||
initFragment(R.id.preference_fragment, new RecipientPreferenceFragment(), masterSecret, null, bundle);
|
initFragment(R.id.preference_fragment, new RecipientPreferenceFragment(), masterSecret, null, bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
this.staleReceiver = new BroadcastReceiver() {
|
this.staleReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsForIds(context, getIntent().getLongArrayExtra(RECIPIENTS_EXTRA), true);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, Address.fromParcelable(getIntent().getParcelableArrayExtra(ADDRESSES_EXTRA)), true);
|
||||||
recipients.addListener(RecipientPreferenceActivity.this);
|
recipients.addListener(RecipientPreferenceActivity.this);
|
||||||
onModified(recipients);
|
onModified(recipients);
|
||||||
}
|
}
|
||||||
@ -234,9 +234,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeRecipients() {
|
private void initializeRecipients() {
|
||||||
this.recipients = RecipientFactory.getRecipientsForIds(getActivity(),
|
this.recipients = RecipientFactory.getRecipientsFor(getActivity(),
|
||||||
getArguments().getLongArray(RECIPIENTS_EXTRA),
|
Address.fromParcelable(getArguments().getParcelableArray(ADDRESSES_EXTRA)),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
this.recipients.addListener(this);
|
this.recipients.addListener(this);
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
recipients.removeListener(RecipientPreferenceFragment.this);
|
recipients.removeListener(RecipientPreferenceFragment.this);
|
||||||
recipients = RecipientFactory.getRecipientsForIds(getActivity(), getArguments().getLongArray(RECIPIENTS_EXTRA), true);
|
recipients = RecipientFactory.getRecipientsFor(getActivity(), Address.fromParcelable(getArguments().getParcelableArray(ADDRESSES_EXTRA)), true);
|
||||||
onModified(recipients);
|
onModified(recipients);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -411,7 +411,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
{
|
{
|
||||||
ApplicationContext.getInstance(context)
|
ApplicationContext.getInstance(context)
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new MultiDeviceContactUpdateJob(context, recipients.getPrimaryRecipient().getRecipientId()));
|
.add(new MultiDeviceContactUpdateJob(context, recipients.getPrimaryRecipient().getAddress()));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -471,7 +471,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
Intent verifyIdentityIntent = new Intent(getActivity(), VerifyIdentityActivity.class);
|
Intent verifyIdentityIntent = new Intent(getActivity(), VerifyIdentityActivity.class);
|
||||||
verifyIdentityIntent.putExtra(VerifyIdentityActivity.RECIPIENT_ID_EXTRA, recipients.getPrimaryRecipient().getRecipientId());
|
verifyIdentityIntent.putExtra(VerifyIdentityActivity.ADDRESS_EXTRA, recipients.getPrimaryRecipient().getAddress());
|
||||||
verifyIdentityIntent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(identityKey.getIdentityKey()));
|
verifyIdentityIntent.putExtra(VerifyIdentityActivity.IDENTITY_EXTRA, new IdentityKeyParcelable(identityKey.getIdentityKey()));
|
||||||
verifyIdentityIntent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, identityKey.getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
|
verifyIdentityIntent.putExtra(VerifyIdentityActivity.VERIFIED_EXTRA, identityKey.getVerifiedStatus() == IdentityDatabase.VerifiedStatus.VERIFIED);
|
||||||
startActivity(verifyIdentityIntent);
|
startActivity(verifyIdentityIntent);
|
||||||
|
@ -23,6 +23,7 @@ import android.database.Cursor;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcel;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@ -35,9 +36,9 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||||
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
import org.thoughtcrime.securesms.providers.PersistentBlobProvider;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
@ -59,9 +60,9 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||||||
{
|
{
|
||||||
private static final String TAG = ShareActivity.class.getSimpleName();
|
private static final String TAG = ShareActivity.class.getSimpleName();
|
||||||
|
|
||||||
public static final String EXTRA_THREAD_ID = "thread_id";
|
public static final String EXTRA_THREAD_ID = "thread_id";
|
||||||
public static final String EXTRA_RECIPIENT_IDS = "recipient_ids";
|
public static final String EXTRA_ADDRESSES_MARSHALLED = "addresses";
|
||||||
public static final String EXTRA_DISTRIBUTION_TYPE = "distribution_type";
|
public static final String EXTRA_DISTRIBUTION_TYPE = "distribution_type";
|
||||||
|
|
||||||
private final DynamicTheme dynamicTheme = new DynamicTheme ();
|
private final DynamicTheme dynamicTheme = new DynamicTheme ();
|
||||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||||
@ -93,6 +94,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onNewIntent(Intent intent) {
|
protected void onNewIntent(Intent intent) {
|
||||||
|
Log.w(TAG, "onNewIntent()");
|
||||||
super.onNewIntent(intent);
|
super.onNewIntent(intent);
|
||||||
setIntent(intent);
|
setIntent(intent);
|
||||||
initializeMedia();
|
initializeMedia();
|
||||||
@ -100,6 +102,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
|
Log.w(TAG, "onResume()");
|
||||||
super.onResume();
|
super.onResume();
|
||||||
dynamicTheme.onResume(this);
|
dynamicTheme.onResume(this);
|
||||||
dynamicLanguage.onResume(this);
|
dynamicLanguage.onResume(this);
|
||||||
@ -163,15 +166,24 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateConversation(long threadId, Recipients recipients, int distributionType) {
|
public void onCreateConversation(long threadId, Recipients recipients, int distributionType) {
|
||||||
createConversation(threadId, recipients, distributionType);
|
createConversation(threadId, recipients.getAddresses(), distributionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleResolvedMedia(Intent intent, boolean animate) {
|
private void handleResolvedMedia(Intent intent, boolean animate) {
|
||||||
long threadId = intent.getLongExtra(EXTRA_THREAD_ID, -1);
|
long threadId = intent.getLongExtra(EXTRA_THREAD_ID, -1);
|
||||||
long[] recipientIds = intent.getLongArrayExtra(EXTRA_RECIPIENT_IDS);
|
int distributionType = intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, -1);
|
||||||
int distributionType = intent.getIntExtra(EXTRA_DISTRIBUTION_TYPE, -1);
|
Address[] addresses = null;
|
||||||
|
|
||||||
boolean hasResolvedDestination = threadId != -1 && recipientIds != null && distributionType != -1;
|
if (intent.hasExtra(EXTRA_ADDRESSES_MARSHALLED)) {
|
||||||
|
Parcel parcel = Parcel.obtain();
|
||||||
|
byte[] marshalled = intent.getByteArrayExtra(EXTRA_ADDRESSES_MARSHALLED);
|
||||||
|
parcel.unmarshall(marshalled, 0, marshalled.length);
|
||||||
|
parcel.setDataPosition(0);
|
||||||
|
addresses = parcel.createTypedArray(Address.CREATOR);
|
||||||
|
parcel.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasResolvedDestination = threadId != -1 && addresses != null && distributionType != -1;
|
||||||
|
|
||||||
if (!hasResolvedDestination && animate) {
|
if (!hasResolvedDestination && animate) {
|
||||||
ViewUtil.fadeIn(fragmentContainer, 300);
|
ViewUtil.fadeIn(fragmentContainer, 300);
|
||||||
@ -180,13 +192,13 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
|
|||||||
fragmentContainer.setVisibility(View.VISIBLE);
|
fragmentContainer.setVisibility(View.VISIBLE);
|
||||||
progressWheel.setVisibility(View.GONE);
|
progressWheel.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
createConversation(threadId, RecipientFactory.getRecipientsForIds(this, recipientIds, true), distributionType);
|
createConversation(threadId, addresses, distributionType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createConversation(long threadId, Recipients recipients, int distributionType) {
|
private void createConversation(long threadId, Address[] addresses, int distributionType) {
|
||||||
final Intent intent = getBaseShareIntent(ConversationActivity.class);
|
final Intent intent = getBaseShareIntent(ConversationActivity.class);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, addresses);
|
||||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||||
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType);
|
||||||
|
|
||||||
|
@ -6,9 +6,11 @@ import android.database.Cursor;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
@ -38,19 +40,20 @@ public class SmsSendtoActivity extends Activity {
|
|||||||
destination = getDestinationForView(original);
|
destination = getDestinationForView(original);
|
||||||
}
|
}
|
||||||
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(this, destination.getDestination(), true);
|
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipients);
|
|
||||||
|
|
||||||
final Intent nextIntent;
|
final Intent nextIntent;
|
||||||
if (recipients.isEmpty()) {
|
|
||||||
|
if (TextUtils.isEmpty(destination.destination)) {
|
||||||
nextIntent = new Intent(this, NewConversationActivity.class);
|
nextIntent = new Intent(this, NewConversationActivity.class);
|
||||||
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
|
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
|
||||||
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
|
||||||
} else {
|
} else {
|
||||||
|
Recipients recipients = RecipientFactory.getRecipientsFor(this, new Address[] {Address.fromExternal(this, destination.getDestination())}, true);
|
||||||
|
long threadId = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipients);
|
||||||
|
|
||||||
nextIntent = new Intent(this, ConversationActivity.class);
|
nextIntent = new Intent(this, ConversationActivity.class);
|
||||||
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
|
nextIntent.putExtra(ConversationActivity.TEXT_EXTRA, destination.getBody());
|
||||||
nextIntent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
nextIntent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||||
nextIntent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
nextIntent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
}
|
}
|
||||||
return nextIntent;
|
return nextIntent;
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
|||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob;
|
||||||
@ -84,7 +85,6 @@ import org.whispersystems.libsignal.fingerprint.Fingerprint;
|
|||||||
import org.whispersystems.libsignal.fingerprint.FingerprintParsingException;
|
import org.whispersystems.libsignal.fingerprint.FingerprintParsingException;
|
||||||
import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException;
|
import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException;
|
||||||
import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
|
import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
@ -100,9 +100,9 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
private static final String TAG = VerifyIdentityActivity.class.getSimpleName();
|
private static final String TAG = VerifyIdentityActivity.class.getSimpleName();
|
||||||
|
|
||||||
public static final String RECIPIENT_ID_EXTRA = "recipient_id";
|
public static final String ADDRESS_EXTRA = "address";
|
||||||
public static final String IDENTITY_EXTRA = "recipient_identity";
|
public static final String IDENTITY_EXTRA = "recipient_identity";
|
||||||
public static final String VERIFIED_EXTRA = "verified_state";
|
public static final String VERIFIED_EXTRA = "verified_state";
|
||||||
|
|
||||||
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||||
@ -118,31 +118,26 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle state, @NonNull MasterSecret masterSecret) {
|
protected void onCreate(Bundle state, @NonNull MasterSecret masterSecret) {
|
||||||
try {
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setTitle(R.string.AndroidManifest__verify_safety_number);
|
||||||
getSupportActionBar().setTitle(R.string.AndroidManifest__verify_safety_number);
|
|
||||||
|
|
||||||
Recipient recipient = RecipientFactory.getRecipientForId(this, getIntent().getLongExtra(RECIPIENT_ID_EXTRA, -1), true);
|
Recipient recipient = RecipientFactory.getRecipientFor(this, (Address)getIntent().getParcelableExtra(ADDRESS_EXTRA), true);
|
||||||
recipient.addListener(this);
|
recipient.addListener(this);
|
||||||
|
|
||||||
setActionBarNotificationBarColor(recipient.getColor());
|
setActionBarNotificationBarColor(recipient.getColor());
|
||||||
|
|
||||||
Bundle extras = new Bundle();
|
Bundle extras = new Bundle();
|
||||||
extras.putLong(VerifyDisplayFragment.REMOTE_RECIPIENT_ID, getIntent().getLongExtra(RECIPIENT_ID_EXTRA, -1));
|
extras.putParcelable(VerifyDisplayFragment.REMOTE_ADDRESS, getIntent().getParcelableExtra(ADDRESS_EXTRA));
|
||||||
extras.putParcelable(VerifyDisplayFragment.REMOTE_IDENTITY, getIntent().getParcelableExtra(IDENTITY_EXTRA));
|
extras.putParcelable(VerifyDisplayFragment.REMOTE_IDENTITY, getIntent().getParcelableExtra(IDENTITY_EXTRA));
|
||||||
extras.putString(VerifyDisplayFragment.REMOTE_NUMBER, Util.canonicalizeNumber(this, recipient.getNumber()));
|
extras.putString(VerifyDisplayFragment.REMOTE_NUMBER, recipient.getAddress().toPhoneString());
|
||||||
extras.putParcelable(VerifyDisplayFragment.LOCAL_IDENTITY, new IdentityKeyParcelable(IdentityKeyUtil.getIdentityKey(this)));
|
extras.putParcelable(VerifyDisplayFragment.LOCAL_IDENTITY, new IdentityKeyParcelable(IdentityKeyUtil.getIdentityKey(this)));
|
||||||
extras.putString(VerifyDisplayFragment.LOCAL_NUMBER, TextSecurePreferences.getLocalNumber(this));
|
extras.putString(VerifyDisplayFragment.LOCAL_NUMBER, TextSecurePreferences.getLocalNumber(this));
|
||||||
extras.putBoolean(VerifyDisplayFragment.VERIFIED_STATE, getIntent().getBooleanExtra(VERIFIED_EXTRA, false));
|
extras.putBoolean(VerifyDisplayFragment.VERIFIED_STATE, getIntent().getBooleanExtra(VERIFIED_EXTRA, false));
|
||||||
|
|
||||||
scanFragment.setScanListener(this);
|
scanFragment.setScanListener(this);
|
||||||
displayFragment.setClickListener(this);
|
displayFragment.setClickListener(this);
|
||||||
|
|
||||||
initFragment(android.R.id.content, displayFragment, masterSecret, dynamicLanguage.getCurrentLocale(), extras);
|
initFragment(android.R.id.content, displayFragment, masterSecret, dynamicLanguage.getCurrentLocale(), extras);
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -198,12 +193,12 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
|
|
||||||
public static class VerifyDisplayFragment extends Fragment implements Recipient.RecipientModifiedListener, CompoundButton.OnCheckedChangeListener {
|
public static class VerifyDisplayFragment extends Fragment implements Recipient.RecipientModifiedListener, CompoundButton.OnCheckedChangeListener {
|
||||||
|
|
||||||
public static final String REMOTE_RECIPIENT_ID = "remote_recipient_id";
|
public static final String REMOTE_ADDRESS = "remote_address";
|
||||||
public static final String REMOTE_NUMBER = "remote_number";
|
public static final String REMOTE_NUMBER = "remote_number";
|
||||||
public static final String REMOTE_IDENTITY = "remote_identity";
|
public static final String REMOTE_IDENTITY = "remote_identity";
|
||||||
public static final String LOCAL_IDENTITY = "local_identity";
|
public static final String LOCAL_IDENTITY = "local_identity";
|
||||||
public static final String LOCAL_NUMBER = "local_number";
|
public static final String LOCAL_NUMBER = "local_number";
|
||||||
public static final String VERIFIED_STATE = "verified_state";
|
public static final String VERIFIED_STATE = "verified_state";
|
||||||
|
|
||||||
private MasterSecret masterSecret;
|
private MasterSecret masterSecret;
|
||||||
private Recipient recipient;
|
private Recipient recipient;
|
||||||
@ -263,12 +258,20 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
public void onCreate(Bundle bundle) {
|
public void onCreate(Bundle bundle) {
|
||||||
super.onCreate(bundle);
|
super.onCreate(bundle);
|
||||||
|
|
||||||
|
Address address = getArguments().getParcelable(REMOTE_ADDRESS);
|
||||||
|
IdentityKeyParcelable localIdentityParcelable = getArguments().getParcelable(LOCAL_IDENTITY);
|
||||||
|
IdentityKeyParcelable remoteIdentityParcelable = getArguments().getParcelable(REMOTE_IDENTITY);
|
||||||
|
|
||||||
|
if (address == null) throw new AssertionError("Address required");
|
||||||
|
if (localIdentityParcelable == null) throw new AssertionError("local identity required");
|
||||||
|
if (remoteIdentityParcelable == null) throw new AssertionError("remote identity required");
|
||||||
|
|
||||||
this.masterSecret = getArguments().getParcelable("master_secret");
|
this.masterSecret = getArguments().getParcelable("master_secret");
|
||||||
this.localNumber = getArguments().getString(LOCAL_NUMBER);
|
this.localNumber = getArguments().getString(LOCAL_NUMBER);
|
||||||
this.localIdentity = ((IdentityKeyParcelable)getArguments().getParcelable(LOCAL_IDENTITY)).get();
|
this.localIdentity = localIdentityParcelable.get();
|
||||||
this.remoteNumber = getArguments().getString(REMOTE_NUMBER);
|
this.remoteNumber = getArguments().getString(REMOTE_NUMBER);
|
||||||
this.recipient = RecipientFactory.getRecipientForId(getActivity(), getArguments().getLong(REMOTE_RECIPIENT_ID), true);
|
this.recipient = RecipientFactory.getRecipientFor(getActivity(), address, true);
|
||||||
this.remoteIdentity = ((IdentityKeyParcelable)getArguments().getParcelable(REMOTE_IDENTITY)).get();
|
this.remoteIdentity = remoteIdentityParcelable.get();
|
||||||
|
|
||||||
this.recipient.addListener(this);
|
this.recipient.addListener(this);
|
||||||
|
|
||||||
@ -589,15 +592,15 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
protected Void doInBackground(Recipient... params) {
|
protected Void doInBackground(Recipient... params) {
|
||||||
synchronized (SESSION_LOCK) {
|
synchronized (SESSION_LOCK) {
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
Log.w(TAG, "Saving identity: " + params[0].getRecipientId());
|
Log.w(TAG, "Saving identity: " + params[0].getAddress());
|
||||||
DatabaseFactory.getIdentityDatabase(getActivity())
|
DatabaseFactory.getIdentityDatabase(getActivity())
|
||||||
.saveIdentity(params[0].getRecipientId(),
|
.saveIdentity(params[0].getAddress(),
|
||||||
remoteIdentity,
|
remoteIdentity,
|
||||||
VerifiedStatus.VERIFIED, false,
|
VerifiedStatus.VERIFIED, false,
|
||||||
System.currentTimeMillis(), true);
|
System.currentTimeMillis(), true);
|
||||||
} else {
|
} else {
|
||||||
DatabaseFactory.getIdentityDatabase(getActivity())
|
DatabaseFactory.getIdentityDatabase(getActivity())
|
||||||
.setVerified(params[0].getRecipientId(),
|
.setVerified(params[0].getAddress(),
|
||||||
remoteIdentity,
|
remoteIdentity,
|
||||||
VerifiedStatus.DEFAULT);
|
VerifiedStatus.DEFAULT);
|
||||||
}
|
}
|
||||||
@ -605,7 +608,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActionBarActivity
|
|||||||
ApplicationContext.getInstance(getActivity())
|
ApplicationContext.getInstance(getActivity())
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new MultiDeviceVerifiedUpdateJob(getActivity(),
|
.add(new MultiDeviceVerifiedUpdateJob(getActivity(),
|
||||||
recipient.getNumber(),
|
recipient.getAddress(),
|
||||||
remoteIdentity,
|
remoteIdentity,
|
||||||
isChecked ? VerifiedStatus.VERIFIED :
|
isChecked ? VerifiedStatus.VERIFIED :
|
||||||
VerifiedStatus.DEFAULT));
|
VerifiedStatus.DEFAULT));
|
||||||
|
@ -258,11 +258,11 @@ public class WebRtcCallActivity extends Activity {
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
synchronized (SESSION_LOCK) {
|
synchronized (SESSION_LOCK) {
|
||||||
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(WebRtcCallActivity.this);
|
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(WebRtcCallActivity.this);
|
||||||
identityKeyStore.saveIdentity(new SignalProtocolAddress(recipient.getNumber(), 1), theirIdentity, true);
|
identityKeyStore.saveIdentity(new SignalProtocolAddress(recipient.getAddress().serialize(), 1), theirIdentity, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
|
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_NUMBER, recipient.getNumber());
|
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, recipient.getAddress());
|
||||||
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL);
|
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL);
|
||||||
startService(intent);
|
startService(intent);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,11 @@ public class AvatarImageView extends ImageView {
|
|||||||
ContactsContract.QuickContact.showQuickContact(getContext(), AvatarImageView.this, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
ContactsContract.QuickContact.showQuickContact(getContext(), AvatarImageView.this, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
||||||
} else if (recipient != null) {
|
} else if (recipient != null) {
|
||||||
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
||||||
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getNumber());
|
if (recipient.getAddress().isEmail()) {
|
||||||
|
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, recipient.getAddress().toEmailString());
|
||||||
|
} else {
|
||||||
|
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getAddress().toPhoneString());
|
||||||
|
}
|
||||||
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
||||||
getContext().startActivity(intent);
|
getContext().startActivity(intent);
|
||||||
}
|
}
|
||||||
|
@ -18,31 +18,28 @@ package org.thoughtcrime.securesms.components;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.AutoCompleteTextView;
|
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
|
||||||
import org.thoughtcrime.securesms.contacts.RecipientsAdapter;
|
import org.thoughtcrime.securesms.contacts.RecipientsAdapter;
|
||||||
import org.thoughtcrime.securesms.contacts.RecipientsEditor;
|
import org.thoughtcrime.securesms.contacts.RecipientsEditor;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients.RecipientsModifiedListener;
|
import org.thoughtcrime.securesms.recipients.Recipients.RecipientsModifiedListener;
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panel component combining both an editable field with a button for
|
* Panel component combining both an editable field with a button for
|
||||||
@ -74,26 +71,11 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientsMod
|
|||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRecipient(String name, String number) {
|
|
||||||
if (name != null) recipientsText.append(name + "< " + number + ">, ");
|
|
||||||
else recipientsText.append(number + ", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRecipients(Recipients recipients) {
|
|
||||||
List<Recipient> recipientList = recipients.getRecipientsList();
|
|
||||||
Iterator<Recipient> iterator = recipientList.iterator();
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Recipient recipient = iterator.next();
|
|
||||||
addRecipient(recipient.getName(), recipient.getNumber());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Recipients getRecipients() throws RecipientFormattingException {
|
public Recipients getRecipients() throws RecipientFormattingException {
|
||||||
String rawText = recipientsText.getText().toString();
|
String rawText = recipientsText.getText().toString();
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(getContext(), rawText, true);
|
Recipients recipients = getRecipientsFromString(getContext(), rawText, true);
|
||||||
|
|
||||||
if (recipients.isEmpty())
|
if (recipients == null || recipients.isEmpty())
|
||||||
throw new RecipientFormattingException("Recipient List Is Empty!");
|
throw new RecipientFormattingException("Recipient List Is Empty!");
|
||||||
|
|
||||||
return recipients;
|
return recipients;
|
||||||
@ -151,7 +133,40 @@ public class PushRecipientsPanel extends RelativeLayout implements RecipientsMod
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void onModified(Recipients recipients) {
|
private @Nullable Recipients getRecipientsFromString(Context context, @NonNull String rawText, boolean asynchronous) {
|
||||||
|
StringTokenizer tokenizer = new StringTokenizer(rawText, ",");
|
||||||
|
List<Address> addresses = new LinkedList<>();
|
||||||
|
|
||||||
|
while (tokenizer.hasMoreTokens()) {
|
||||||
|
String token = tokenizer.nextToken().trim();
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(token)) {
|
||||||
|
if (hasBracketedNumber(token)) addresses.add(Address.fromExternal(context, parseBracketedNumber(token)));
|
||||||
|
else addresses.add(Address.fromExternal(context, token));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addresses.size() == 0) return null;
|
||||||
|
else return RecipientFactory.getRecipientsFor(context, addresses.toArray(new Address[0]), asynchronous);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasBracketedNumber(String recipient) {
|
||||||
|
int openBracketIndex = recipient.indexOf('<');
|
||||||
|
|
||||||
|
return (openBracketIndex != -1) &&
|
||||||
|
(recipient.indexOf('>', openBracketIndex) != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseBracketedNumber(String recipient) {
|
||||||
|
int begin = recipient.indexOf('<');
|
||||||
|
int end = recipient.indexOf('>', begin);
|
||||||
|
String value = recipient.substring(begin + 1, end);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onModified(Recipients recipients) {
|
||||||
recipientsText.populate(recipients);
|
recipientsText.populate(recipients);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,176 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.components;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
|
||||||
import org.thoughtcrime.securesms.contacts.RecipientsAdapter;
|
|
||||||
import org.thoughtcrime.securesms.contacts.RecipientsEditor;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients.RecipientsModifiedListener;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Panel component combining both an editable field with a button for
|
|
||||||
* a list-based contact selector.
|
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*/
|
|
||||||
public class SingleRecipientPanel extends RelativeLayout implements RecipientsModifiedListener {
|
|
||||||
private final String TAG = SingleRecipientPanel.class.getSimpleName();
|
|
||||||
private RecipientsPanelChangedListener panelChangeListener;
|
|
||||||
|
|
||||||
private RecipientsEditor recipientsText;
|
|
||||||
private View panel;
|
|
||||||
|
|
||||||
private static final int RECIPIENTS_MAX_LENGTH = 312;
|
|
||||||
|
|
||||||
public SingleRecipientPanel(Context context) {
|
|
||||||
super(context);
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public SingleRecipientPanel(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public SingleRecipientPanel(Context context, AttributeSet attrs, int defStyle) {
|
|
||||||
super(context, attrs, defStyle);
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRecipient(String name, String number) {
|
|
||||||
Log.i(TAG, "addRecipient for " + name + "/" + number);
|
|
||||||
if (name != null) recipientsText.append(name + "< " + number + ">, ");
|
|
||||||
else recipientsText.append(number + ", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRecipients(Recipients recipients) {
|
|
||||||
List<Recipient> recipientList = recipients.getRecipientsList();
|
|
||||||
Iterator<Recipient> iterator = recipientList.iterator();
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Recipient recipient = iterator.next();
|
|
||||||
addRecipient(recipient.getName(), recipient.getNumber());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addContacts(List<ContactAccessor.ContactData> contacts) {
|
|
||||||
for (ContactAccessor.ContactData contact : contacts) {
|
|
||||||
for (ContactAccessor.NumberData number : contact.numbers) {
|
|
||||||
addRecipient(contact.name, number.number);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Recipients getRecipients() throws RecipientFormattingException {
|
|
||||||
String rawText = recipientsText.getText().toString();
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(getContext(), rawText, true);
|
|
||||||
|
|
||||||
if (recipients.isEmpty())
|
|
||||||
throw new RecipientFormattingException("Recipient List Is Empty!");
|
|
||||||
|
|
||||||
return recipients;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disable() {
|
|
||||||
clear();
|
|
||||||
panel.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
recipientsText.setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPanelChangeListener(RecipientsPanelChangedListener panelChangeListener) {
|
|
||||||
this.panelChangeListener = panelChangeListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialize() {
|
|
||||||
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
inflater.inflate(R.layout.single_recipient_panel, this, true);
|
|
||||||
|
|
||||||
panel = findViewById(R.id.recipients_panel);
|
|
||||||
initRecipientsEditor();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initRecipientsEditor() {
|
|
||||||
Recipients recipients;
|
|
||||||
recipientsText = (RecipientsEditor)findViewById(R.id.recipients_text);
|
|
||||||
|
|
||||||
try {
|
|
||||||
recipients = getRecipients();
|
|
||||||
} catch (RecipientFormattingException e) {
|
|
||||||
recipients = RecipientFactory.getRecipientsFor(getContext(), new LinkedList<Recipient>(), true);
|
|
||||||
}
|
|
||||||
recipients.addListener(this);
|
|
||||||
|
|
||||||
recipientsText.setAdapter(new RecipientsAdapter(this.getContext()));
|
|
||||||
recipientsText.populate(recipients);
|
|
||||||
|
|
||||||
recipientsText.setOnFocusChangeListener(new FocusChangedListener());
|
|
||||||
recipientsText.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
|
||||||
if (panelChangeListener != null) {
|
|
||||||
try {
|
|
||||||
panelChangeListener.onRecipientsPanelUpdate(getRecipients());
|
|
||||||
} catch (RecipientFormattingException rfe) {
|
|
||||||
panelChangeListener.onRecipientsPanelUpdate(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
recipientsText.setText("");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void onModified(Recipients recipients) {
|
|
||||||
recipientsText.populate(recipients);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class FocusChangedListener implements OnFocusChangeListener {
|
|
||||||
public void onFocusChange(View v, boolean hasFocus) {
|
|
||||||
if (!hasFocus && (panelChangeListener != null)) {
|
|
||||||
try {
|
|
||||||
panelChangeListener.onRecipientsPanelUpdate(getRecipients());
|
|
||||||
} catch (RecipientFormattingException rfe) {
|
|
||||||
panelChangeListener.onRecipientsPanelUpdate(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface RecipientsPanelChangedListener {
|
|
||||||
public void onRecipientsPanelUpdate(Recipients recipients);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -46,7 +46,7 @@ public class UntrustedSendDialog extends AlertDialog.Builder implements DialogIn
|
|||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
synchronized (SESSION_LOCK) {
|
synchronized (SESSION_LOCK) {
|
||||||
for (IdentityRecord identityRecord : untrustedRecords) {
|
for (IdentityRecord identityRecord : untrustedRecords) {
|
||||||
identityDatabase.setApproval(identityRecord.getRecipientId(), true);
|
identityDatabase.setApproval(identityRecord.getAddress(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ public class UnverifiedSendDialog extends AlertDialog.Builder implements DialogI
|
|||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
synchronized (SESSION_LOCK) {
|
synchronized (SESSION_LOCK) {
|
||||||
for (IdentityRecord identityRecord : untrustedRecords) {
|
for (IdentityRecord identityRecord : untrustedRecords) {
|
||||||
identityDatabase.setVerified(identityRecord.getRecipientId(),
|
identityDatabase.setVerified(identityRecord.getAddress(),
|
||||||
identityRecord.getIdentityKey(),
|
identityRecord.getIdentityKey(),
|
||||||
IdentityDatabase.VerifiedStatus.DEFAULT);
|
IdentityDatabase.VerifiedStatus.DEFAULT);
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient
|
|||||||
String introduction = String.format(getContext().getString(R.string.WebRtcCallScreen_new_safety_numbers), name, name);
|
String introduction = String.format(getContext().getString(R.string.WebRtcCallScreen_new_safety_numbers), name, name);
|
||||||
SpannableString spannableString = new SpannableString(introduction + " " + getContext().getString(R.string.WebRtcCallScreen_you_may_wish_to_verify_this_contact));
|
SpannableString spannableString = new SpannableString(introduction + " " + getContext().getString(R.string.WebRtcCallScreen_you_may_wish_to_verify_this_contact));
|
||||||
|
|
||||||
spannableString.setSpan(new VerifySpan(getContext(), personInfo.getRecipientId(), untrustedIdentity),
|
spannableString.setSpan(new VerifySpan(getContext(), personInfo.getAddress(), untrustedIdentity),
|
||||||
introduction.length()+1, spannableString.length(),
|
introduction.length()+1, spannableString.length(),
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
@ -302,7 +302,7 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient
|
|||||||
}.execute();
|
}.execute();
|
||||||
|
|
||||||
this.name.setText(recipient.getName());
|
this.name.setText(recipient.getName());
|
||||||
this.phoneNumber.setText(recipient.getNumber());
|
this.phoneNumber.setText(recipient.getAddress().serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCard(Recipient recipient, String status) {
|
private void setCard(Recipient recipient, String status) {
|
||||||
|
@ -10,9 +10,10 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
|
import org.thoughtcrime.securesms.recipients.RecipientsFormatter;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
|
||||||
public class ContactSelectionListItem extends LinearLayout implements Recipients.RecipientsModifiedListener {
|
public class ContactSelectionListItem extends LinearLayout implements Recipients.RecipientsModifiedListener {
|
||||||
@ -53,9 +54,10 @@ public class ContactSelectionListItem extends LinearLayout implements Recipients
|
|||||||
|
|
||||||
if (type == ContactsDatabase.NEW_TYPE) {
|
if (type == ContactsDatabase.NEW_TYPE) {
|
||||||
this.recipients = null;
|
this.recipients = null;
|
||||||
this.contactPhotoImage.setAvatar(Recipient.getUnknownRecipient(), false);
|
this.contactPhotoImage.setAvatar(RecipientFactory.getRecipientFor(getContext(), Address.UNKNOWN, true), false);
|
||||||
} else if (!TextUtils.isEmpty(number)) {
|
} else if (!TextUtils.isEmpty(number)) {
|
||||||
this.recipients = RecipientFactory.getRecipientsFromString(getContext(), number, true);
|
Address address = Address.fromExternal(getContext(), number);
|
||||||
|
this.recipients = RecipientFactory.getRecipientsFor(getContext(), new Address[] {address}, true);
|
||||||
|
|
||||||
if (this.recipients.getPrimaryRecipient() != null &&
|
if (this.recipients.getPrimaryRecipient() != null &&
|
||||||
this.recipients.getPrimaryRecipient().getName() != null)
|
this.recipients.getPrimaryRecipient().getName() != null)
|
||||||
|
@ -27,6 +27,7 @@ import android.text.TextUtils;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
@ -102,8 +103,8 @@ public class ContactsCursorLoader extends CursorLoader {
|
|||||||
ContactsDatabase.LABEL_COLUMN,
|
ContactsDatabase.LABEL_COLUMN,
|
||||||
ContactsDatabase.CONTACT_TYPE_COLUMN});
|
ContactsDatabase.CONTACT_TYPE_COLUMN});
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
final String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_COLUMN));
|
final String number = cursor.getString(cursor.getColumnIndexOrThrow(ContactsDatabase.NUMBER_COLUMN));
|
||||||
final Recipients recipients = RecipientFactory.getRecipientsFromString(getContext(), number, true);
|
final Recipients recipients = RecipientFactory.getRecipientsFor(getContext(), new Address[]{Address.fromExternal(getContext(), number)}, true);
|
||||||
|
|
||||||
if (DirectoryHelper.getUserCapabilities(getContext(), recipients)
|
if (DirectoryHelper.getUserCapabilities(getContext(), recipients)
|
||||||
.getTextCapability() != Capability.SUPPORTED)
|
.getTextCapability() != Capability.SUPPORTED)
|
||||||
|
@ -128,9 +128,9 @@ public class RecipientsEditor extends AppCompatMultiAutoCompleteTextView {
|
|||||||
return mTokenizer.getNumbers();
|
return mTokenizer.getNumbers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Recipients constructContactsFromInput() {
|
// public Recipients constructContactsFromInput() {
|
||||||
return RecipientFactory.getRecipientsFromString(mContext, mTokenizer.getRawString(), false);
|
// return RecipientFactory.getRecipientsFromString(mContext, mTokenizer.getRawString(), false);
|
||||||
}
|
// }
|
||||||
|
|
||||||
private boolean isValidAddress(String number, boolean isMms) {
|
private boolean isValidAddress(String number, boolean isMms) {
|
||||||
/*if (isMms) {
|
/*if (isMms) {
|
||||||
@ -191,7 +191,7 @@ public class RecipientsEditor extends AppCompatMultiAutoCompleteTextView {
|
|||||||
|
|
||||||
public static CharSequence contactToToken(Recipient c) {
|
public static CharSequence contactToToken(Recipient c) {
|
||||||
String name = c.getName();
|
String name = c.getName();
|
||||||
String number = c.getNumber();
|
String number = c.getAddress().serialize();
|
||||||
SpannableString s = new SpannableString(RecipientsFormatter.formatNameAndNumber(name, number));
|
SpannableString s = new SpannableString(RecipientsFormatter.formatNameAndNumber(name, number));
|
||||||
int len = s.length();
|
int len = s.length();
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ public class RecipientsEditor extends AppCompatMultiAutoCompleteTextView {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
s.setSpan(new Annotation("number", c.getNumber()), 0, len,
|
s.setSpan(new Annotation("number", c.getAddress().serialize()), 0, len,
|
||||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
@ -4,6 +4,7 @@ import android.content.Context;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||||
import org.whispersystems.libsignal.state.SessionRecord;
|
import org.whispersystems.libsignal.state.SessionRecord;
|
||||||
@ -15,12 +16,12 @@ import java.util.List;
|
|||||||
public class SessionUtil {
|
public class SessionUtil {
|
||||||
|
|
||||||
public static boolean hasSession(Context context, MasterSecret masterSecret, Recipient recipient) {
|
public static boolean hasSession(Context context, MasterSecret masterSecret, Recipient recipient) {
|
||||||
return hasSession(context, masterSecret, recipient.getNumber());
|
return hasSession(context, masterSecret, recipient.getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasSession(Context context, MasterSecret masterSecret, @NonNull String number) {
|
public static boolean hasSession(Context context, MasterSecret masterSecret, @NonNull Address address) {
|
||||||
SessionStore sessionStore = new TextSecureSessionStore(context, masterSecret);
|
SessionStore sessionStore = new TextSecureSessionStore(context, masterSecret);
|
||||||
SignalProtocolAddress axolotlAddress = new SignalProtocolAddress(number, SignalServiceAddress.DEFAULT_DEVICE_ID);
|
SignalProtocolAddress axolotlAddress = new SignalProtocolAddress(address.serialize(), SignalServiceAddress.DEFAULT_DEVICE_ID);
|
||||||
|
|
||||||
return sessionStore.containsSession(axolotlAddress);
|
return sessionStore.containsSession(axolotlAddress);
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@ import android.util.Log;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.SessionUtil;
|
import org.thoughtcrime.securesms.crypto.SessionUtil;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
|
||||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
@ -47,13 +47,12 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
|||||||
public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) {
|
public boolean saveIdentity(SignalProtocolAddress address, IdentityKey identityKey, boolean nonBlockingApproval) {
|
||||||
synchronized (LOCK) {
|
synchronized (LOCK) {
|
||||||
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
|
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, address.getName(), true);
|
Address signalAddress = Address.fromExternal(context, address.getName());
|
||||||
long recipientId = recipients.getPrimaryRecipient().getRecipientId();
|
Optional<IdentityRecord> identityRecord = identityDatabase.getIdentity(signalAddress);
|
||||||
Optional<IdentityRecord> identityRecord = identityDatabase.getIdentity(recipientId);
|
|
||||||
|
|
||||||
if (!identityRecord.isPresent()) {
|
if (!identityRecord.isPresent()) {
|
||||||
Log.w(TAG, "Saving new identity...");
|
Log.w(TAG, "Saving new identity...");
|
||||||
identityDatabase.saveIdentity(recipientId, identityKey, VerifiedStatus.DEFAULT, true, System.currentTimeMillis(), nonBlockingApproval);
|
identityDatabase.saveIdentity(signalAddress, identityKey, VerifiedStatus.DEFAULT, true, System.currentTimeMillis(), nonBlockingApproval);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,15 +68,15 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
|||||||
verifiedStatus = VerifiedStatus.DEFAULT;
|
verifiedStatus = VerifiedStatus.DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
identityDatabase.saveIdentity(recipientId, identityKey, verifiedStatus, false, System.currentTimeMillis(), nonBlockingApproval);
|
identityDatabase.saveIdentity(signalAddress, identityKey, verifiedStatus, false, System.currentTimeMillis(), nonBlockingApproval);
|
||||||
IdentityUtil.markIdentityUpdate(context, recipients.getPrimaryRecipient());
|
IdentityUtil.markIdentityUpdate(context, RecipientFactory.getRecipientFor(context, signalAddress, true));
|
||||||
SessionUtil.archiveSiblingSessions(context, address);
|
SessionUtil.archiveSiblingSessions(context, address);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNonBlockingApprovalRequired(identityRecord.get())) {
|
if (isNonBlockingApprovalRequired(identityRecord.get())) {
|
||||||
Log.w(TAG, "Setting approval status...");
|
Log.w(TAG, "Setting approval status...");
|
||||||
identityDatabase.setApproval(recipientId, nonBlockingApproval);
|
identityDatabase.setApproval(signalAddress, nonBlockingApproval);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,16 +93,15 @@ public class TextSecureIdentityKeyStore implements IdentityKeyStore {
|
|||||||
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
|
public boolean isTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction) {
|
||||||
synchronized (LOCK) {
|
synchronized (LOCK) {
|
||||||
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
|
IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(context);
|
||||||
long recipientId = RecipientFactory.getRecipientsFromString(context, address.getName(), true).getPrimaryRecipient().getRecipientId();
|
|
||||||
String ourNumber = TextSecurePreferences.getLocalNumber(context);
|
String ourNumber = TextSecurePreferences.getLocalNumber(context);
|
||||||
long ourRecipientId = RecipientFactory.getRecipientsFromString(context, ourNumber, true).getPrimaryRecipient().getRecipientId();
|
Address theirAddress = Address.fromExternal(context, address.getName());
|
||||||
|
|
||||||
if (ourRecipientId == recipientId || ourNumber.equals(address.getName())) {
|
if (ourNumber.equals(address.getName()) || Address.fromSerialized(ourNumber).equals(theirAddress)) {
|
||||||
return identityKey.equals(IdentityKeyUtil.getIdentityKey(context));
|
return identityKey.equals(IdentityKeyUtil.getIdentityKey(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case SENDING: return isTrustedForSending(identityKey, identityDatabase.getIdentity(recipientId));
|
case SENDING: return isTrustedForSending(identityKey, identityDatabase.getIdentity(theirAddress));
|
||||||
case RECEIVING: return true;
|
case RECEIVING: return true;
|
||||||
default: throw new AssertionError("Unknown direction: " + direction);
|
default: throw new AssertionError("Unknown direction: " + direction);
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,9 @@ import android.util.Log;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.util.Conversions;
|
import org.thoughtcrime.securesms.util.Conversions;
|
||||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||||
import org.whispersystems.libsignal.protocol.CiphertextMessage;
|
import org.whispersystems.libsignal.protocol.CiphertextMessage;
|
||||||
import org.whispersystems.libsignal.state.SessionRecord;
|
import org.whispersystems.libsignal.state.SessionRecord;
|
||||||
import org.whispersystems.libsignal.state.SessionState;
|
import org.whispersystems.libsignal.state.SessionState;
|
||||||
@ -135,7 +133,6 @@ public class TextSecureSessionStore implements SessionStore {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Integer> getSubDeviceSessions(String name) {
|
public List<Integer> getSubDeviceSessions(String name) {
|
||||||
long recipientId = RecipientFactory.getRecipientsFromString(context, name, true).getPrimaryRecipient().getRecipientId();
|
|
||||||
List<Integer> results = new LinkedList<>();
|
List<Integer> results = new LinkedList<>();
|
||||||
File parent = getSessionDirectory();
|
File parent = getSessionDirectory();
|
||||||
String[] children = parent.list();
|
String[] children = parent.list();
|
||||||
@ -144,10 +141,10 @@ public class TextSecureSessionStore implements SessionStore {
|
|||||||
|
|
||||||
for (String child : children) {
|
for (String child : children) {
|
||||||
try {
|
try {
|
||||||
String[] parts = child.split("[.]", 2);
|
String[] parts = child.split("[.]", 2);
|
||||||
long sessionRecipientId = Long.parseLong(parts[0]);
|
String sessionName = parts[0];
|
||||||
|
|
||||||
if (sessionRecipientId == recipientId && parts.length > 1) {
|
if (sessionName.equals(name) && parts.length > 1) {
|
||||||
results.add(Integer.parseInt(parts[1]));
|
results.add(Integer.parseInt(parts[1]));
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
@ -209,26 +206,21 @@ public class TextSecureSessionStore implements SessionStore {
|
|||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSessionName(SignalProtocolAddress axolotlAddress) {
|
private String getSessionName(SignalProtocolAddress address) {
|
||||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, axolotlAddress.getName(), true)
|
int deviceId = address.getDeviceId();
|
||||||
.getPrimaryRecipient();
|
return address.getName() + (deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID ? "" : "." + deviceId);
|
||||||
long recipientId = recipient.getRecipientId();
|
|
||||||
int deviceId = axolotlAddress.getDeviceId();
|
|
||||||
|
|
||||||
return recipientId + (deviceId == SignalServiceAddress.DEFAULT_DEVICE_ID ? "" : "." + deviceId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable SignalProtocolAddress getAddressName(File sessionFile) {
|
private @Nullable SignalProtocolAddress getAddressName(File sessionFile) {
|
||||||
try {
|
try {
|
||||||
String[] parts = sessionFile.getName().split("[.]");
|
String[] parts = sessionFile.getName().split("[.]");
|
||||||
Recipient recipient = RecipientFactory.getRecipientForId(context, Integer.valueOf(parts[0]), true);
|
|
||||||
|
|
||||||
int deviceId;
|
int deviceId;
|
||||||
|
|
||||||
if (parts.length > 1) deviceId = Integer.parseInt(parts[1]);
|
if (parts.length > 1) deviceId = Integer.parseInt(parts[1]);
|
||||||
else deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
|
else deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
|
||||||
|
|
||||||
return new SignalProtocolAddress(recipient.getNumber(), deviceId);
|
return new SignalProtocolAddress(parts[0], deviceId);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
return null;
|
return null;
|
||||||
|
156
src/org/thoughtcrime/securesms/database/Address.java
Normal file
156
src/org/thoughtcrime/securesms/database/Address.java
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package org.thoughtcrime.securesms.database;
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.NumberUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.ShortCodeUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||||
|
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Address implements Parcelable, Comparable<Address> {
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<Address> CREATOR = new Parcelable.Creator<Address>() {
|
||||||
|
public Address createFromParcel(Parcel in) {
|
||||||
|
return new Address(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address[] newArray(int size) {
|
||||||
|
return new Address[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final Address UNKNOWN = new Address("Unknown");
|
||||||
|
|
||||||
|
private static final String TAG = Address.class.getSimpleName();
|
||||||
|
|
||||||
|
private final String address;
|
||||||
|
|
||||||
|
private Address(@NonNull String address) {
|
||||||
|
if (address == null) throw new AssertionError(address);
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address(Parcel in) {
|
||||||
|
this(in.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Address fromSerialized(@NonNull String serialized) {
|
||||||
|
return new Address(serialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Address> fromSerializedList(@NonNull String serialized, @NonNull String delimiter) {
|
||||||
|
List<String> elements = Util.split(serialized, delimiter);
|
||||||
|
List<Address> addresses = new LinkedList<>();
|
||||||
|
|
||||||
|
for (String element : elements) {
|
||||||
|
addresses.add(Address.fromSerialized(element));
|
||||||
|
}
|
||||||
|
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Address fromExternal(@NonNull Context context, @Nullable String external)
|
||||||
|
{
|
||||||
|
if (external == null) return new Address("Unknown");
|
||||||
|
|
||||||
|
try {
|
||||||
|
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||||
|
|
||||||
|
if (GroupUtil.isEncodedGroup(external)) return new Address(external);
|
||||||
|
else if (NumberUtil.isValidEmail(external)) return new Address(external);
|
||||||
|
else if (ShortCodeUtil.isShortCode(localNumber, external)) return new Address(external.replaceAll("[^0-9+]", ""));
|
||||||
|
|
||||||
|
return new Address(PhoneNumberFormatter.formatNumber(external, localNumber));
|
||||||
|
} catch (InvalidNumberException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
if (TextUtils.isEmpty(external.trim())) return new Address("Unknown");
|
||||||
|
else return new Address(external.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Address[] fromParcelable(Parcelable[] parcelables) {
|
||||||
|
Address[] addresses = new Address[parcelables.length];
|
||||||
|
|
||||||
|
for (int i=0;i<parcelables.length;i++) {
|
||||||
|
addresses[i] = (Address)parcelables[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGroup() {
|
||||||
|
return GroupUtil.isEncodedGroup(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmail() {
|
||||||
|
return NumberUtil.isValidEmail(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPhone() {
|
||||||
|
return !isGroup() && !isEmail();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull String toGroupString() {
|
||||||
|
if (!isGroup()) throw new AssertionError("Not group: " + address);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull String toPhoneString() {
|
||||||
|
if (!isPhone()) throw new AssertionError("Not e164: " + address);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull String toEmailString() {
|
||||||
|
if (!isEmail()) throw new AssertionError("Not email: " + address);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String serialize() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (this == other) return true;
|
||||||
|
if (other == null || !(other instanceof Address)) return false;
|
||||||
|
return address.equals(((Address) other).address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return address.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NonNull Address other) {
|
||||||
|
return address.compareTo(other.address);
|
||||||
|
}
|
||||||
|
}
|
@ -1,261 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.database;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.VisibleForTesting;
|
|
||||||
import android.telephony.PhoneNumberUtils;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.LRUCache;
|
|
||||||
import org.thoughtcrime.securesms.util.ShortCodeUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class CanonicalAddressDatabase {
|
|
||||||
|
|
||||||
private static final String TAG = CanonicalAddressDatabase.class.getSimpleName();
|
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = 1;
|
|
||||||
private static final String DATABASE_NAME = "canonical_address.db";
|
|
||||||
private static final String TABLE = "canonical_addresses";
|
|
||||||
private static final String ID_COLUMN = "_id";
|
|
||||||
private static final String ADDRESS_COLUMN = "address";
|
|
||||||
|
|
||||||
private static final String DATABASE_CREATE = "CREATE TABLE " + TABLE + " (" + ID_COLUMN + " integer PRIMARY KEY, " + ADDRESS_COLUMN + " TEXT NOT NULL);";
|
|
||||||
private static final String SELECTION_NUMBER = "PHONE_NUMBERS_EQUAL(" + ADDRESS_COLUMN + ", ?)";
|
|
||||||
private static final String SELECTION_OTHER = ADDRESS_COLUMN + " = ? COLLATE NOCASE";
|
|
||||||
|
|
||||||
private static CanonicalAddressDatabase instance;
|
|
||||||
private DatabaseHelper databaseHelper;
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
private final Map<String, Long> addressCache = new ConcurrentHashMap<>();
|
|
||||||
private final Map<Long, String> idCache = new ConcurrentHashMap<>();
|
|
||||||
private final Map<String, String> formattedAddressCache = Collections.synchronizedMap(new LRUCache<String, String>(100));
|
|
||||||
|
|
||||||
public synchronized static CanonicalAddressDatabase getInstance(Context context) {
|
|
||||||
if (instance == null)
|
|
||||||
instance = new CanonicalAddressDatabase(context.getApplicationContext());
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CanonicalAddressDatabase(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
this.databaseHelper = new DatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
|
|
||||||
|
|
||||||
fillCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset(Context context) {
|
|
||||||
DatabaseHelper old = this.databaseHelper;
|
|
||||||
this.databaseHelper = new DatabaseHelper(context.getApplicationContext(), DATABASE_NAME, null, DATABASE_VERSION);
|
|
||||||
old.close();
|
|
||||||
fillCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fillCache() {
|
|
||||||
Cursor cursor = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
|
||||||
cursor = db.query(TABLE, null, null, null, null, null, null);
|
|
||||||
|
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
|
||||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID_COLUMN));
|
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS_COLUMN));
|
|
||||||
|
|
||||||
if (address == null || address.trim().length() == 0)
|
|
||||||
address = "Anonymous";
|
|
||||||
|
|
||||||
idCache.put(id, address);
|
|
||||||
addressCache.put(address, id);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null)
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull String getAddressFromId(long id) {
|
|
||||||
String cachedAddress = idCache.get(id);
|
|
||||||
|
|
||||||
if (cachedAddress != null)
|
|
||||||
return cachedAddress;
|
|
||||||
|
|
||||||
Cursor cursor = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Log.w(TAG, "Hitting DB on query [ID].");
|
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
|
||||||
cursor = db.query(TABLE, null, ID_COLUMN + " = ?", new String[] {id+""}, null, null, null);
|
|
||||||
|
|
||||||
if (!cursor.moveToFirst())
|
|
||||||
return "Anonymous";
|
|
||||||
|
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS_COLUMN));
|
|
||||||
|
|
||||||
if (address == null || address.trim().equals("")) {
|
|
||||||
return "Anonymous";
|
|
||||||
} else {
|
|
||||||
idCache.put(id, address);
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null)
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
databaseHelper.close();
|
|
||||||
instance = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCanonicalAddressId(@NonNull String address) {
|
|
||||||
try {
|
|
||||||
long canonicalAddressId;
|
|
||||||
String formattedAddress;
|
|
||||||
|
|
||||||
if ((formattedAddress = formattedAddressCache.get(address)) == null) {
|
|
||||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
|
||||||
|
|
||||||
if (!isNumberAddress(address) ||
|
|
||||||
!TextSecurePreferences.isPushRegistered(context) ||
|
|
||||||
ShortCodeUtil.isShortCode(localNumber, address))
|
|
||||||
{
|
|
||||||
formattedAddress = address;
|
|
||||||
} else {
|
|
||||||
formattedAddress = PhoneNumberFormatter.formatNumber(address, localNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
formattedAddressCache.put(address, formattedAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((canonicalAddressId = getCanonicalAddressFromCache(formattedAddress)) == -1) {
|
|
||||||
canonicalAddressId = getCanonicalAddressIdFromDatabase(formattedAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
idCache.put(canonicalAddressId, formattedAddress);
|
|
||||||
addressCache.put(formattedAddress, canonicalAddressId);
|
|
||||||
|
|
||||||
return canonicalAddressId;
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
throw new AssertionError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull List<Long> getCanonicalAddressIds(@NonNull List<String> addresses) {
|
|
||||||
List<Long> addressList = new LinkedList<>();
|
|
||||||
|
|
||||||
for (String address : addresses) {
|
|
||||||
addressList.add(getCanonicalAddressId(address));
|
|
||||||
}
|
|
||||||
|
|
||||||
return addressList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getCanonicalAddressFromCache(String address) {
|
|
||||||
Long cachedAddress = addressCache.get(address);
|
|
||||||
return cachedAddress == null ? -1L : cachedAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getCanonicalAddressIdFromDatabase(@NonNull String address) {
|
|
||||||
Log.w(TAG, "Hitting DB on query [ADDRESS]");
|
|
||||||
|
|
||||||
Cursor cursor = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
|
||||||
String[] selectionArguments = new String[]{address};
|
|
||||||
boolean isNumber = isNumberAddress(address);
|
|
||||||
|
|
||||||
cursor = db.query(TABLE, null, isNumber ? SELECTION_NUMBER : SELECTION_OTHER,
|
|
||||||
selectionArguments, null, null, null);
|
|
||||||
|
|
||||||
if (cursor.getCount() == 0 || !cursor.moveToFirst()) {
|
|
||||||
ContentValues contentValues = new ContentValues(1);
|
|
||||||
contentValues.put(ADDRESS_COLUMN, address);
|
|
||||||
return db.insert(TABLE, ADDRESS_COLUMN, contentValues);
|
|
||||||
} else {
|
|
||||||
long canonicalId = cursor.getLong(cursor.getColumnIndexOrThrow(ID_COLUMN));
|
|
||||||
String oldAddress = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS_COLUMN));
|
|
||||||
|
|
||||||
if (!address.equals(oldAddress)) {
|
|
||||||
ContentValues contentValues = new ContentValues(1);
|
|
||||||
contentValues.put(ADDRESS_COLUMN, address);
|
|
||||||
db.update(TABLE, contentValues, ID_COLUMN + " = ?", new String[]{canonicalId+""});
|
|
||||||
|
|
||||||
addressCache.remove(oldAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
return canonicalId;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (cursor != null) {
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static boolean isNumberAddress(@NonNull String number) {
|
|
||||||
if (number.contains("@")) return false;
|
|
||||||
if (GroupUtil.isEncodedGroup(number)) return false;
|
|
||||||
|
|
||||||
final String networkNumber = PhoneNumberUtils.extractNetworkPortion(number);
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(networkNumber)) return false;
|
|
||||||
if (networkNumber.length() < 3) return false;
|
|
||||||
|
|
||||||
return PhoneNumberUtils.isWellFormedSmsAddress(number);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DatabaseHelper extends SQLiteOpenHelper {
|
|
||||||
|
|
||||||
public DatabaseHelper(Context context, String name, CursorFactory factory, int version) {
|
|
||||||
super(context, name, factory, version);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(SQLiteDatabase db) {
|
|
||||||
db.execSQL(DATABASE_CREATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.thoughtcrime.securesms.database;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class CanonicalSessionMigrator {
|
|
||||||
|
|
||||||
private static void migrateSession(File sessionFile, File sessionsDirectory, long canonicalAddress) {
|
|
||||||
File canonicalSessionFile = new File(sessionsDirectory.getAbsolutePath() + File.separatorChar + canonicalAddress);
|
|
||||||
sessionFile.renameTo(canonicalSessionFile);
|
|
||||||
Log.w("CanonicalSessionMigrator", "Moving: " + sessionFile.toString() + " to " + canonicalSessionFile.toString());
|
|
||||||
|
|
||||||
File canonicalSessionFileLocal = new File(sessionsDirectory.getAbsolutePath() + File.separatorChar + canonicalAddress + "-local");
|
|
||||||
File localFile = new File(sessionFile.getAbsolutePath() + "-local");
|
|
||||||
if (localFile.exists())
|
|
||||||
localFile.renameTo(canonicalSessionFileLocal);
|
|
||||||
|
|
||||||
Log.w("CanonicalSessionMigrator", "Moving " + localFile + " to " + canonicalSessionFileLocal);
|
|
||||||
|
|
||||||
File canonicalSessionFileRemote = new File(sessionsDirectory.getAbsolutePath() + File.separatorChar + canonicalAddress + "-remote");
|
|
||||||
File remoteFile = new File(sessionFile.getAbsolutePath() + "-remote");
|
|
||||||
if (remoteFile.exists())
|
|
||||||
remoteFile.renameTo(canonicalSessionFileRemote);
|
|
||||||
|
|
||||||
Log.w("CanonicalSessionMigrator", "Moving " + remoteFile + " to " + canonicalSessionFileRemote);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void migrateSessions(Context context) {
|
|
||||||
if (context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).getBoolean("canonicalized", false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
CanonicalAddressDatabase canonicalDb = CanonicalAddressDatabase.getInstance(context);
|
|
||||||
File rootDirectory = context.getFilesDir();
|
|
||||||
File sessionsDirectory = new File(rootDirectory.getAbsolutePath() + File.separatorChar + "sessions");
|
|
||||||
sessionsDirectory.mkdir();
|
|
||||||
|
|
||||||
String[] files = rootDirectory.list();
|
|
||||||
|
|
||||||
for (int i=0;i<files.length;i++) {
|
|
||||||
File item = new File(rootDirectory.getAbsolutePath() + File.separatorChar + files[i]);
|
|
||||||
|
|
||||||
if (!item.isDirectory() && files[i].matches("[0-9]+")) {
|
|
||||||
long canonicalAddress = canonicalDb.getCanonicalAddressId(files[i]);
|
|
||||||
migrateSession(item, sessionsDirectory, canonicalAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).edit().putBoolean("canonicalized", true).apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -22,18 +22,30 @@ import android.database.Cursor;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.google.i18n.phonenumbers.NumberParseException;
|
||||||
|
import com.google.i18n.phonenumbers.PhoneNumberUtil;
|
||||||
|
import com.google.i18n.phonenumbers.Phonenumber;
|
||||||
|
import com.google.i18n.phonenumbers.ShortNumberInfo;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.DatabaseUpgradeActivity;
|
import org.thoughtcrime.securesms.DatabaseUpgradeActivity;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactsDatabase;
|
import org.thoughtcrime.securesms.contacts.ContactsDatabase;
|
||||||
import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
|
import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||||
|
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
@ -42,6 +54,12 @@ import java.io.File;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class DatabaseFactory {
|
public class DatabaseFactory {
|
||||||
|
|
||||||
@ -80,7 +98,8 @@ public class DatabaseFactory {
|
|||||||
private static final int INTRODUCED_VOICE_NOTES = 34;
|
private static final int INTRODUCED_VOICE_NOTES = 34;
|
||||||
private static final int INTRODUCED_IDENTITY_TIMESTAMP = 35;
|
private static final int INTRODUCED_IDENTITY_TIMESTAMP = 35;
|
||||||
private static final int SANIFY_ATTACHMENT_DOWNLOAD = 36;
|
private static final int SANIFY_ATTACHMENT_DOWNLOAD = 36;
|
||||||
private static final int DATABASE_VERSION = 36;
|
private static final int NO_MORE_CANONICAL_ADDRESS_DATABASE = 37;
|
||||||
|
private static final int DATABASE_VERSION = 37;
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "messages.db";
|
private static final String DATABASE_NAME = "messages.db";
|
||||||
private static final Object lock = new Object();
|
private static final Object lock = new Object();
|
||||||
@ -95,7 +114,6 @@ public class DatabaseFactory {
|
|||||||
private final AttachmentDatabase attachments;
|
private final AttachmentDatabase attachments;
|
||||||
private final MediaDatabase media;
|
private final MediaDatabase media;
|
||||||
private final ThreadDatabase thread;
|
private final ThreadDatabase thread;
|
||||||
private final CanonicalAddressDatabase address;
|
|
||||||
private final MmsAddressDatabase mmsAddress;
|
private final MmsAddressDatabase mmsAddress;
|
||||||
private final MmsSmsDatabase mmsSmsDatabase;
|
private final MmsSmsDatabase mmsSmsDatabase;
|
||||||
private final IdentityDatabase identityDatabase;
|
private final IdentityDatabase identityDatabase;
|
||||||
@ -130,10 +148,6 @@ public class DatabaseFactory {
|
|||||||
return getInstance(context).mms;
|
return getInstance(context).mms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CanonicalAddressDatabase getAddressDatabase(Context context) {
|
|
||||||
return getInstance(context).address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EncryptingSmsDatabase getEncryptingSmsDatabase(Context context) {
|
public static EncryptingSmsDatabase getEncryptingSmsDatabase(Context context) {
|
||||||
return getInstance(context).encryptingSms;
|
return getInstance(context).encryptingSms;
|
||||||
}
|
}
|
||||||
@ -182,7 +196,6 @@ public class DatabaseFactory {
|
|||||||
this.attachments = new AttachmentDatabase(context, databaseHelper);
|
this.attachments = new AttachmentDatabase(context, databaseHelper);
|
||||||
this.media = new MediaDatabase(context, databaseHelper);
|
this.media = new MediaDatabase(context, databaseHelper);
|
||||||
this.thread = new ThreadDatabase(context, databaseHelper);
|
this.thread = new ThreadDatabase(context, databaseHelper);
|
||||||
this.address = CanonicalAddressDatabase.getInstance(context);
|
|
||||||
this.mmsAddress = new MmsAddressDatabase(context, databaseHelper);
|
this.mmsAddress = new MmsAddressDatabase(context, databaseHelper);
|
||||||
this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper);
|
this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper);
|
||||||
this.identityDatabase = new IdentityDatabase(context, databaseHelper);
|
this.identityDatabase = new IdentityDatabase(context, databaseHelper);
|
||||||
@ -210,8 +223,6 @@ public class DatabaseFactory {
|
|||||||
this.groupDatabase.reset(databaseHelper);
|
this.groupDatabase.reset(databaseHelper);
|
||||||
this.recipientPreferenceDatabase.reset(databaseHelper);
|
this.recipientPreferenceDatabase.reset(databaseHelper);
|
||||||
old.close();
|
old.close();
|
||||||
|
|
||||||
this.address.reset(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onApplicationLevelUpgrade(Context context, MasterSecret masterSecret, int fromVersion,
|
public void onApplicationLevelUpgrade(Context context, MasterSecret masterSecret, int fromVersion,
|
||||||
@ -504,8 +515,13 @@ public class DatabaseFactory {
|
|||||||
|
|
||||||
private static class DatabaseHelper extends SQLiteOpenHelper {
|
private static class DatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
|
private static final String TAG = DatabaseHelper.class.getSimpleName();
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
public DatabaseHelper(Context context, String name, CursorFactory factory, int version) {
|
public DatabaseHelper(Context context, String name, CursorFactory factory, int version) {
|
||||||
super(context, name, factory, version);
|
super(context, name, factory, version);
|
||||||
|
this.context = context.getApplicationContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -883,6 +899,299 @@ public class DatabaseFactory {
|
|||||||
db.execSQL("UPDATE part SET pending_push = '2' WHERE pending_push = '1'");
|
db.execSQL("UPDATE part SET pending_push = '2' WHERE pending_push = '1'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < NO_MORE_CANONICAL_ADDRESS_DATABASE) {
|
||||||
|
DatabaseHelper canonicalAddressDatabaseHelper = new DatabaseHelper(context, "canonical_address.db", null, 1);
|
||||||
|
SQLiteDatabase canonicalAddressDatabase = canonicalAddressDatabaseHelper.getReadableDatabase();
|
||||||
|
NumberMigrator numberMigrator = new NumberMigrator(TextSecurePreferences.getLocalNumber(context));
|
||||||
|
|
||||||
|
// Migrate Thread Database
|
||||||
|
Cursor cursor = db.query("thread", new String[] {"_id", "recipient_ids"}, null, null, null, null, null);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
long threadId = cursor.getLong(0);
|
||||||
|
String recipientIdsList = cursor.getString(1);
|
||||||
|
String[] recipientIds = recipientIdsList.split(" ");
|
||||||
|
String[] numbers = new String[recipientIds.length];
|
||||||
|
|
||||||
|
for (int i=0;i<recipientIds.length;i++) {
|
||||||
|
Cursor resolved = canonicalAddressDatabase.query("canonical_addresses", new String[] {"address"}, "_id = ?", new String[] {recipientIds[i]}, null, null, null);
|
||||||
|
|
||||||
|
if (resolved != null && resolved.moveToFirst()) {
|
||||||
|
String address = resolved.getString(0);
|
||||||
|
numbers[i] = numberMigrator.migrate(address);
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Unable to resolve: " + recipientIds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved != null) resolved.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put("recipient_ids", Util.join(numbers, " "));
|
||||||
|
db.update("thread", values, "_id = ?", new String[] {String.valueOf(threadId)});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
|
||||||
|
// Migrate Identity database
|
||||||
|
db.execSQL("CREATE TABLE identities_migrated (_id INTEGER PRIMARY KEY, address TEXT UNIQUE, key TEXT, first_use INTEGER DEFAULT 0, timestamp INTEGER DEFAULT 0, verified INTEGER DEFAULT 0, nonblocking_approval INTEGER DEFAULT 0);");
|
||||||
|
|
||||||
|
cursor = db.query("identities", new String[] {"_id, recipient, key, first_use, timestamp, verified, nonblocking_approval"}, null, null, null, null, null);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
long id = cursor.getLong(0);
|
||||||
|
long recipientId = cursor.getLong(1);
|
||||||
|
String key = cursor.getString(2);
|
||||||
|
int firstUse = cursor.getInt(3);
|
||||||
|
long timestamp = cursor.getLong(4);
|
||||||
|
int verified = cursor.getInt(5);
|
||||||
|
int nonblockingApproval = cursor.getInt(6);
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues(6);
|
||||||
|
|
||||||
|
Cursor resolved = canonicalAddressDatabase.query("canonical_addresses", new String[] {"address"}, "_id = ?", new String[] {String.valueOf(recipientId)}, null, null, null);
|
||||||
|
|
||||||
|
if (resolved != null && resolved.moveToFirst()) {
|
||||||
|
String address = resolved.getString(0);
|
||||||
|
values.put("address", numberMigrator.migrate(address));
|
||||||
|
values.put("key", key);
|
||||||
|
values.put("first_use", firstUse);
|
||||||
|
values.put("timestamp", timestamp);
|
||||||
|
values.put("verified", verified);
|
||||||
|
values.put("nonblocking_approval", nonblockingApproval);
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Unable to resolve: " + recipientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved != null) resolved.close();
|
||||||
|
|
||||||
|
db.insert("identities_migrated", null, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
|
||||||
|
db.execSQL("DROP TABLE identities");
|
||||||
|
db.execSQL("ALTER TABLE identities_migrated RENAME TO identities");
|
||||||
|
|
||||||
|
// Migrate recipient preferences database
|
||||||
|
cursor = db.query("recipient_preferences", new String[] {"_id", "recipient_ids"}, null, null, null, null, null);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
long id = cursor.getLong(0);
|
||||||
|
String recipientIdsList = cursor.getString(1);
|
||||||
|
String[] recipientIds = recipientIdsList.split(" ");
|
||||||
|
String[] addresses = new String[recipientIds.length];
|
||||||
|
|
||||||
|
for (int i=0;i<recipientIds.length;i++) {
|
||||||
|
Cursor resolved = canonicalAddressDatabase.query("canonical_addresses", new String[] {"address"}, "_id = ?", new String[] {recipientIds[i]}, null, null, null);
|
||||||
|
|
||||||
|
if (resolved != null && resolved.moveToFirst()) {
|
||||||
|
String address = resolved.getString(0);
|
||||||
|
addresses[i] = numberMigrator.migrate(address);
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Unable to resolve: " + recipientIds[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved != null) resolved.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put("recipient_ids", Util.join(addresses, " "));
|
||||||
|
db.update("thread", values, "_id = ?", new String[] {String.valueOf(id)});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
|
||||||
|
// Migrate SMS database
|
||||||
|
cursor = db.query("sms", new String[] {"_id", "address"}, null, null, null, null, null);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
long id = cursor.getLong(0);
|
||||||
|
String address = cursor.getString(1);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(address)) {
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put("address", numberMigrator.migrate(address));
|
||||||
|
db.update("sms", values, "_id = ?", new String[] {String.valueOf(id)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
|
||||||
|
// Migrate MMS database
|
||||||
|
cursor = db.query("mms", new String[] {"_id", "address"}, null, null, null, null, null);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
long id = cursor.getLong(0);
|
||||||
|
String address = cursor.getString(1);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(address)) {
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put("address", numberMigrator.migrate(address));
|
||||||
|
db.update("mms", values, "_id = ?", new String[] {String.valueOf(id)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
|
||||||
|
// Migrate MmsAddressDatabase
|
||||||
|
cursor = db.query("mms_addresses", new String[] {"_id", "address"}, null, null, null, null, null);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
long id = cursor.getLong(0);
|
||||||
|
String address = cursor.getString(1);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(address) && !"insert-address-token".equals(address)) {
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put("address", numberMigrator.migrate(address));
|
||||||
|
db.update("mms_addresses", values, "_id = ?", new String[] {String.valueOf(id)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
|
||||||
|
// Migrate SMS mismatched identities
|
||||||
|
cursor = db.query("sms", new String[] {"_id", "mismatched_identities"}, "mismatched_identities IS NOT NULL", null, null, null, null);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
long id = cursor.getLong(0);
|
||||||
|
String document = cursor.getString(1);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(document)) {
|
||||||
|
try {
|
||||||
|
PreCanonicalAddressIdentityMismatchList oldDocumentList = JsonUtils.fromJson(document, PreCanonicalAddressIdentityMismatchList.class);
|
||||||
|
List<PostCanonicalAddressIdentityMismatchDocument> newDocumentList = new LinkedList<>();
|
||||||
|
|
||||||
|
for (PreCanonicalAddressIdentityMismatchDocument oldDocument : oldDocumentList.list) {
|
||||||
|
Cursor resolved = canonicalAddressDatabase.query("canonical_addresses", new String[] {"address"}, "_id = ?", new String[] {String.valueOf(oldDocument.recipientId)}, null, null, null);
|
||||||
|
|
||||||
|
if (resolved != null && resolved.moveToFirst()) {
|
||||||
|
String address = resolved.getString(0);
|
||||||
|
newDocumentList.add(new PostCanonicalAddressIdentityMismatchDocument(numberMigrator.migrate(address), oldDocument.identityKey));
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Unable to resolve: " + oldDocument.recipientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved != null) resolved.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put("mismatched_identities", JsonUtils.toJson(new PostCanonicalAddressIdentityMismatchList(newDocumentList)));
|
||||||
|
db.update("sms", values, "_id = ?", new String[] {String.valueOf(id)});
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
|
||||||
|
// Migrate MMS mismatched identities
|
||||||
|
cursor = db.query("mms", new String[] {"_id", "mismatched_identities"}, "mismatched_identities IS NOT NULL", null, null, null, null);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
long id = cursor.getLong(0);
|
||||||
|
String document = cursor.getString(1);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(document)) {
|
||||||
|
try {
|
||||||
|
PreCanonicalAddressIdentityMismatchList oldDocumentList = JsonUtils.fromJson(document, PreCanonicalAddressIdentityMismatchList.class);
|
||||||
|
List<PostCanonicalAddressIdentityMismatchDocument> newDocumentList = new LinkedList<>();
|
||||||
|
|
||||||
|
for (PreCanonicalAddressIdentityMismatchDocument oldDocument : oldDocumentList.list) {
|
||||||
|
Cursor resolved = canonicalAddressDatabase.query("canonical_addresses", new String[] {"address"}, "_id = ?", new String[] {String.valueOf(oldDocument.recipientId)}, null, null, null);
|
||||||
|
|
||||||
|
if (resolved != null && resolved.moveToFirst()) {
|
||||||
|
String address = resolved.getString(0);
|
||||||
|
newDocumentList.add(new PostCanonicalAddressIdentityMismatchDocument(numberMigrator.migrate(address), oldDocument.identityKey));
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Unable to resolve: " + oldDocument.recipientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved != null) resolved.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put("mismatched_identities", JsonUtils.toJson(new PostCanonicalAddressIdentityMismatchList(newDocumentList)));
|
||||||
|
db.update("mms", values, "_id = ?", new String[] {String.valueOf(id)});
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) cursor.close();
|
||||||
|
|
||||||
|
// Migrate MMS network failures
|
||||||
|
cursor = db.query("mms", new String[] {"_id", "network_failures"}, "network_failures IS NOT NULL", null, null, null, null);
|
||||||
|
|
||||||
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
|
long id = cursor.getLong(0);
|
||||||
|
String document = cursor.getString(1);
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(document)) {
|
||||||
|
try {
|
||||||
|
PreCanonicalAddressNetworkFailureList oldDocumentList = JsonUtils.fromJson(document, PreCanonicalAddressNetworkFailureList.class);
|
||||||
|
List<PostCanonicalAddressNetworkFailureDocument> newDocumentList = new LinkedList<>();
|
||||||
|
|
||||||
|
for (PreCanonicalAddressNetworkFailureDocument oldDocument : oldDocumentList.list) {
|
||||||
|
Cursor resolved = canonicalAddressDatabase.query("canonical_addresses", new String[] {"address"}, "_id = ?", new String[] {String.valueOf(oldDocument.recipientId)}, null, null, null);
|
||||||
|
|
||||||
|
if (resolved != null && resolved.moveToFirst()) {
|
||||||
|
String address = resolved.getString(0);
|
||||||
|
newDocumentList.add(new PostCanonicalAddressNetworkFailureDocument(numberMigrator.migrate(address)));
|
||||||
|
} else {
|
||||||
|
throw new AssertionError("Unable to resolve: " + oldDocument.recipientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved != null) resolved.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentValues values = new ContentValues(1);
|
||||||
|
values.put("network_failures", JsonUtils.toJson(new PostCanonicalAddressNetworkFailureList(newDocumentList)));
|
||||||
|
db.update("mms", values, "_id = ?", new String[] {String.valueOf(id)});
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate sessions
|
||||||
|
File sessionsDirectory = new File(context.getFilesDir(), "sessions-v2");
|
||||||
|
|
||||||
|
if (sessionsDirectory.exists() && sessionsDirectory.isDirectory()) {
|
||||||
|
File[] sessions = sessionsDirectory.listFiles();
|
||||||
|
|
||||||
|
for (File session : sessions) {
|
||||||
|
try {
|
||||||
|
String[] sessionParts = session.getName().split("[.]");
|
||||||
|
long recipientId = Long.parseLong(sessionParts[0]);
|
||||||
|
|
||||||
|
int deviceId;
|
||||||
|
|
||||||
|
if (sessionParts.length > 1) deviceId = Integer.parseInt(sessionParts[1]);
|
||||||
|
else deviceId = 1;
|
||||||
|
|
||||||
|
Cursor resolved = canonicalAddressDatabase.query("canonical_addresses", new String[] {"address"}, "_id = ?", new String[] {String.valueOf(recipientId)}, null, null, null);
|
||||||
|
|
||||||
|
if (resolved != null && resolved.moveToNext()) {
|
||||||
|
String address = resolved.getString(0);
|
||||||
|
File destination = new File(session.getParentFile(), address + (deviceId != 1 ? "." + deviceId : ""));
|
||||||
|
|
||||||
|
if (!session.renameTo(destination)) {
|
||||||
|
Log.w(TAG, "Session rename failed: " + destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved != null) resolved.close();
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
}
|
}
|
||||||
@ -893,4 +1202,153 @@ public class DatabaseFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class PreCanonicalAddressIdentityMismatchList {
|
||||||
|
@JsonProperty(value = "m")
|
||||||
|
private List<PreCanonicalAddressIdentityMismatchDocument> list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PostCanonicalAddressIdentityMismatchList {
|
||||||
|
@JsonProperty(value = "m")
|
||||||
|
private List<PostCanonicalAddressIdentityMismatchDocument> list;
|
||||||
|
|
||||||
|
public PostCanonicalAddressIdentityMismatchList(List<PostCanonicalAddressIdentityMismatchDocument> list) {
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PreCanonicalAddressIdentityMismatchDocument {
|
||||||
|
@JsonProperty(value = "r")
|
||||||
|
private long recipientId;
|
||||||
|
|
||||||
|
@JsonProperty(value = "k")
|
||||||
|
private String identityKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PostCanonicalAddressIdentityMismatchDocument {
|
||||||
|
@JsonProperty(value = "a")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@JsonProperty(value = "k")
|
||||||
|
private String identityKey;
|
||||||
|
|
||||||
|
public PostCanonicalAddressIdentityMismatchDocument() {}
|
||||||
|
|
||||||
|
public PostCanonicalAddressIdentityMismatchDocument(String address, String identityKey) {
|
||||||
|
this.address = address;
|
||||||
|
this.identityKey = identityKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PreCanonicalAddressNetworkFailureList {
|
||||||
|
@JsonProperty(value = "l")
|
||||||
|
private List<PreCanonicalAddressNetworkFailureDocument> list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PostCanonicalAddressNetworkFailureList {
|
||||||
|
@JsonProperty(value = "l")
|
||||||
|
private List<PostCanonicalAddressNetworkFailureDocument> list;
|
||||||
|
|
||||||
|
public PostCanonicalAddressNetworkFailureList(List<PostCanonicalAddressNetworkFailureDocument> list) {
|
||||||
|
this.list = list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PreCanonicalAddressNetworkFailureDocument {
|
||||||
|
@JsonProperty(value = "r")
|
||||||
|
private long recipientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PostCanonicalAddressNetworkFailureDocument {
|
||||||
|
@JsonProperty(value = "a")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
public PostCanonicalAddressNetworkFailureDocument() {}
|
||||||
|
|
||||||
|
public PostCanonicalAddressNetworkFailureDocument(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NumberMigrator {
|
||||||
|
|
||||||
|
private static final String TAG = NumberMigrator.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final Set<String> SHORT_COUNTRIES = new HashSet<String>() {{
|
||||||
|
add("NU");
|
||||||
|
add("TK");
|
||||||
|
add("NC");
|
||||||
|
add("AC");
|
||||||
|
}};
|
||||||
|
|
||||||
|
private final Phonenumber.PhoneNumber localNumber;
|
||||||
|
private final String localNumberString;
|
||||||
|
private final String localCountryCode;
|
||||||
|
|
||||||
|
private final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
|
||||||
|
|
||||||
|
public NumberMigrator(String localNumber) {
|
||||||
|
try {
|
||||||
|
this.localNumberString = localNumber;
|
||||||
|
this.localNumber = phoneNumberUtil.parse(localNumber, null);
|
||||||
|
this.localCountryCode = phoneNumberUtil.getRegionCodeForNumber(this.localNumber);
|
||||||
|
} catch (NumberParseException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String migrate(@Nullable String number) {
|
||||||
|
if (number == null) return "Unknown";
|
||||||
|
if (number.startsWith("__textsecure_group__!")) return number;
|
||||||
|
if (android.util.Patterns.EMAIL_ADDRESS.matcher(number).matches()) return number;
|
||||||
|
|
||||||
|
String bareNumber = number.replaceAll("[^0-9+]", "");
|
||||||
|
|
||||||
|
if (bareNumber.length() == 0) {
|
||||||
|
if (TextUtils.isEmpty(number.trim())) return "Unknown";
|
||||||
|
else return number.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// libphonenumber doesn't seem to be correct for Germany and Finland
|
||||||
|
if (bareNumber.length() <= 6 && ("DE".equals(localCountryCode) || "FI".equals(localCountryCode) || "SK".equals(localCountryCode))) {
|
||||||
|
return bareNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
// libphonenumber seems incorrect for Russia and a few other countries with 4 digit short codes.
|
||||||
|
if (bareNumber.length() <= 4 && !SHORT_COUNTRIES.contains(localCountryCode)) {
|
||||||
|
return bareNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Phonenumber.PhoneNumber parsedNumber = phoneNumberUtil.parse(bareNumber, localCountryCode);
|
||||||
|
|
||||||
|
if (ShortNumberInfo.getInstance().isPossibleShortNumberForRegion(parsedNumber, localCountryCode)) {
|
||||||
|
return bareNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
return phoneNumberUtil.format(parsedNumber, PhoneNumberUtil.PhoneNumberFormat.E164);
|
||||||
|
} catch (NumberParseException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
if (bareNumber.charAt(0) == '+')
|
||||||
|
return bareNumber;
|
||||||
|
|
||||||
|
String localNumberImprecise = localNumberString;
|
||||||
|
|
||||||
|
if (localNumberImprecise.charAt(0) == '+')
|
||||||
|
localNumberImprecise = localNumberImprecise.substring(1);
|
||||||
|
|
||||||
|
if (localNumberImprecise.length() == number.length() || number.length() > localNumberImprecise.length())
|
||||||
|
return "+" + number;
|
||||||
|
|
||||||
|
int difference = localNumberImprecise.length() - number.length();
|
||||||
|
|
||||||
|
return "+" + localNumberImprecise.substring(0, difference) + number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ public class EarlyReceiptCache {
|
|||||||
|
|
||||||
private final LRUCache<Placeholder, Long> cache = new LRUCache<>(100);
|
private final LRUCache<Placeholder, Long> cache = new LRUCache<>(100);
|
||||||
|
|
||||||
public synchronized void increment(long timestamp, String address) {
|
public synchronized void increment(long timestamp, Address address) {
|
||||||
Log.w(TAG, this+"");
|
Log.w(TAG, this+"");
|
||||||
Log.w(TAG, String.format("Early receipt: %d,%s", timestamp, address));
|
Log.w(TAG, String.format("Early receipt: %d,%s", timestamp, address));
|
||||||
Placeholder tuple = new Placeholder(timestamp, address);
|
Placeholder tuple = new Placeholder(timestamp, address);
|
||||||
@ -24,7 +24,7 @@ public class EarlyReceiptCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized long remove(long timestamp, String address) {
|
public synchronized long remove(long timestamp, Address address) {
|
||||||
Long count = cache.remove(new Placeholder(timestamp, address));
|
Long count = cache.remove(new Placeholder(timestamp, address));
|
||||||
Log.w(TAG, this+"");
|
Log.w(TAG, this+"");
|
||||||
Log.w(TAG, String.format("Checking early receipts (%d, %s): %d", timestamp, address, count));
|
Log.w(TAG, String.format("Checking early receipts (%d, %s): %d", timestamp, address, count));
|
||||||
@ -34,9 +34,9 @@ public class EarlyReceiptCache {
|
|||||||
private class Placeholder {
|
private class Placeholder {
|
||||||
|
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final @NonNull String address;
|
private final @NonNull Address address;
|
||||||
|
|
||||||
private Placeholder(long timestamp, @NonNull String address) {
|
private Placeholder(long timestamp, @NonNull Address address) {
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
@ -101,22 +101,20 @@ public class GroupDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Recipients getGroupMembers(byte[] groupId, boolean includeSelf) {
|
public @NonNull Recipients getGroupMembers(byte[] groupId, boolean includeSelf) {
|
||||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
List<Address> members = getCurrentMembers(groupId);
|
||||||
List<String> members = getCurrentMembers(groupId);
|
|
||||||
List<Recipient> recipients = new LinkedList<>();
|
List<Recipient> recipients = new LinkedList<>();
|
||||||
|
|
||||||
for (String member : members) {
|
for (Address member : members) {
|
||||||
if (!includeSelf && member.equals(localNumber))
|
if (!includeSelf && Util.isOwnNumber(context, member))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
recipients.addAll(RecipientFactory.getRecipientsFromString(context, member, false)
|
recipients.add(RecipientFactory.getRecipientFor(context, member, false));
|
||||||
.getRecipientsList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return RecipientFactory.getRecipientsFor(context, recipients, false);
|
return RecipientFactory.getRecipientsFor(context, recipients, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void create(byte[] groupId, String title, List<String> members,
|
public void create(byte[] groupId, String title, List<Address> members,
|
||||||
SignalServiceAttachmentPointer avatar, String relay)
|
SignalServiceAttachmentPointer avatar, String relay)
|
||||||
{
|
{
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
@ -185,7 +183,7 @@ public class GroupDatabase extends Database {
|
|||||||
notifyDatabaseListeners();
|
notifyDatabaseListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMembers(byte[] id, List<String> members) {
|
public void updateMembers(byte[] id, List<Address> members) {
|
||||||
ContentValues contents = new ContentValues();
|
ContentValues contents = new ContentValues();
|
||||||
contents.put(MEMBERS, Util.join(members, ","));
|
contents.put(MEMBERS, Util.join(members, ","));
|
||||||
contents.put(ACTIVE, 1);
|
contents.put(ACTIVE, 1);
|
||||||
@ -194,8 +192,8 @@ public class GroupDatabase extends Database {
|
|||||||
new String[] {GroupUtil.getEncodedId(id)});
|
new String[] {GroupUtil.getEncodedId(id)});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(byte[] id, String source) {
|
public void remove(byte[] id, Address source) {
|
||||||
List<String> currentMembers = getCurrentMembers(id);
|
List<Address> currentMembers = getCurrentMembers(id);
|
||||||
currentMembers.remove(source);
|
currentMembers.remove(source);
|
||||||
|
|
||||||
ContentValues contents = new ContentValues();
|
ContentValues contents = new ContentValues();
|
||||||
@ -205,7 +203,7 @@ public class GroupDatabase extends Database {
|
|||||||
new String[] {GroupUtil.getEncodedId(id)});
|
new String[] {GroupUtil.getEncodedId(id)});
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getCurrentMembers(byte[] id) {
|
private List<Address> getCurrentMembers(byte[] id) {
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -215,7 +213,13 @@ public class GroupDatabase extends Database {
|
|||||||
null, null, null);
|
null, null, null);
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
return Util.split(cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)), ",");
|
List<Address> results = new LinkedList<>();
|
||||||
|
|
||||||
|
for (String member : Util.split(cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)), ",")) {
|
||||||
|
results.add(Address.fromSerialized(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LinkedList<>();
|
return new LinkedList<>();
|
||||||
@ -286,16 +290,16 @@ public class GroupDatabase extends Database {
|
|||||||
|
|
||||||
public static class GroupRecord {
|
public static class GroupRecord {
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
private final String title;
|
private final String title;
|
||||||
private final List<String> members;
|
private final List<Address> members;
|
||||||
private final byte[] avatar;
|
private final byte[] avatar;
|
||||||
private final long avatarId;
|
private final long avatarId;
|
||||||
private final byte[] avatarKey;
|
private final byte[] avatarKey;
|
||||||
private final byte[] avatarDigest;
|
private final byte[] avatarDigest;
|
||||||
private final String avatarContentType;
|
private final String avatarContentType;
|
||||||
private final String relay;
|
private final String relay;
|
||||||
private final boolean active;
|
private final boolean active;
|
||||||
|
|
||||||
public GroupRecord(String id, String title, String members, byte[] avatar,
|
public GroupRecord(String id, String title, String members, byte[] avatar,
|
||||||
long avatarId, byte[] avatarKey, String avatarContentType,
|
long avatarId, byte[] avatarKey, String avatarContentType,
|
||||||
@ -303,7 +307,7 @@ public class GroupDatabase extends Database {
|
|||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.members = Util.split(members, ",");
|
this.members = Address.fromSerializedList(members, ",");
|
||||||
this.avatar = avatar;
|
this.avatar = avatar;
|
||||||
this.avatarId = avatarId;
|
this.avatarId = avatarId;
|
||||||
this.avatarKey = avatarKey;
|
this.avatarKey = avatarKey;
|
||||||
@ -329,7 +333,7 @@ public class GroupDatabase extends Database {
|
|||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getMembers() {
|
public List<Address> getMembers() {
|
||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ public class IdentityDatabase extends Database {
|
|||||||
|
|
||||||
private static final String TABLE_NAME = "identities";
|
private static final String TABLE_NAME = "identities";
|
||||||
private static final String ID = "_id";
|
private static final String ID = "_id";
|
||||||
private static final String RECIPIENT = "recipient";
|
private static final String ADDRESS = "address";
|
||||||
private static final String IDENTITY_KEY = "key";
|
private static final String IDENTITY_KEY = "key";
|
||||||
private static final String TIMESTAMP = "timestamp";
|
private static final String TIMESTAMP = "timestamp";
|
||||||
private static final String FIRST_USE = "first_use";
|
private static final String FIRST_USE = "first_use";
|
||||||
@ -47,7 +47,7 @@ public class IdentityDatabase extends Database {
|
|||||||
|
|
||||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME +
|
||||||
" (" + ID + " INTEGER PRIMARY KEY, " +
|
" (" + ID + " INTEGER PRIMARY KEY, " +
|
||||||
RECIPIENT + " INTEGER UNIQUE, " +
|
ADDRESS + " TEXT UNIQUE, " +
|
||||||
IDENTITY_KEY + " TEXT, " +
|
IDENTITY_KEY + " TEXT, " +
|
||||||
FIRST_USE + " INTEGER DEFAULT 0, " +
|
FIRST_USE + " INTEGER DEFAULT 0, " +
|
||||||
TIMESTAMP + " INTEGER DEFAULT 0, " +
|
TIMESTAMP + " INTEGER DEFAULT 0, " +
|
||||||
@ -65,8 +65,8 @@ public class IdentityDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static VerifiedStatus forState(int state) {
|
public static VerifiedStatus forState(int state) {
|
||||||
if (state == 0) return DEFAULT;
|
if (state == 0) return DEFAULT;
|
||||||
else if (state == 1) return VERIFIED;
|
else if (state == 1) return VERIFIED;
|
||||||
else if (state == 2) return UNVERIFIED;
|
else if (state == 2) return UNVERIFIED;
|
||||||
else throw new AssertionError("No such state: " + state);
|
else throw new AssertionError("No such state: " + state);
|
||||||
}
|
}
|
||||||
@ -86,13 +86,13 @@ public class IdentityDatabase extends Database {
|
|||||||
return new IdentityReader(cursor);
|
return new IdentityReader(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<IdentityRecord> getIdentity(long recipientId) {
|
public Optional<IdentityRecord> getIdentity(Address address) {
|
||||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = database.query(TABLE_NAME, null, RECIPIENT + " = ?",
|
cursor = database.query(TABLE_NAME, null, ADDRESS + " = ?",
|
||||||
new String[] {recipientId + ""}, null, null, null);
|
new String[] {address.serialize()}, null, null, null);
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
return Optional.of(getIdentityRecord(cursor));
|
return Optional.of(getIdentityRecord(cursor));
|
||||||
@ -106,14 +106,14 @@ public class IdentityDatabase extends Database {
|
|||||||
return Optional.absent();
|
return Optional.absent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveIdentity(long recipientId, IdentityKey identityKey, VerifiedStatus verifiedStatus,
|
public void saveIdentity(Address address, IdentityKey identityKey, VerifiedStatus verifiedStatus,
|
||||||
boolean firstUse, long timestamp, boolean nonBlockingApproval)
|
boolean firstUse, long timestamp, boolean nonBlockingApproval)
|
||||||
{
|
{
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
String identityKeyString = Base64.encodeBytes(identityKey.serialize());
|
String identityKeyString = Base64.encodeBytes(identityKey.serialize());
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(RECIPIENT, recipientId);
|
contentValues.put(ADDRESS, address.serialize());
|
||||||
contentValues.put(IDENTITY_KEY, identityKeyString);
|
contentValues.put(IDENTITY_KEY, identityKeyString);
|
||||||
contentValues.put(TIMESTAMP, timestamp);
|
contentValues.put(TIMESTAMP, timestamp);
|
||||||
contentValues.put(VERIFIED, verifiedStatus.toInt());
|
contentValues.put(VERIFIED, verifiedStatus.toInt());
|
||||||
@ -122,38 +122,36 @@ public class IdentityDatabase extends Database {
|
|||||||
|
|
||||||
database.replace(TABLE_NAME, null, contentValues);
|
database.replace(TABLE_NAME, null, contentValues);
|
||||||
|
|
||||||
EventBus.getDefault().post(new IdentityRecord(recipientId, identityKey, verifiedStatus,
|
EventBus.getDefault().post(new IdentityRecord(address, identityKey, verifiedStatus,
|
||||||
firstUse, timestamp, nonBlockingApproval));
|
firstUse, timestamp, nonBlockingApproval));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setApproval(long recipientId, boolean nonBlockingApproval) {
|
public void setApproval(Address address, boolean nonBlockingApproval) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues(2);
|
ContentValues contentValues = new ContentValues(2);
|
||||||
contentValues.put(NONBLOCKING_APPROVAL, nonBlockingApproval);
|
contentValues.put(NONBLOCKING_APPROVAL, nonBlockingApproval);
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, RECIPIENT + " = ?",
|
database.update(TABLE_NAME, contentValues, ADDRESS + " = ?", new String[] {address.serialize()});
|
||||||
new String[] {String.valueOf(recipientId)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVerified(long recipientId, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
|
public void setVerified(Address address, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues(1);
|
ContentValues contentValues = new ContentValues(1);
|
||||||
contentValues.put(VERIFIED, verifiedStatus.toInt());
|
contentValues.put(VERIFIED, verifiedStatus.toInt());
|
||||||
|
|
||||||
int updated = database.update(TABLE_NAME, contentValues, RECIPIENT + " = ? AND " + IDENTITY_KEY + " = ?",
|
int updated = database.update(TABLE_NAME, contentValues, ADDRESS + " = ? AND " + IDENTITY_KEY + " = ?",
|
||||||
new String[] {String.valueOf(recipientId),
|
new String[] {address.serialize(), Base64.encodeBytes(identityKey.serialize())});
|
||||||
Base64.encodeBytes(identityKey.serialize())});
|
|
||||||
|
|
||||||
if (updated > 0) {
|
if (updated > 0) {
|
||||||
Optional<IdentityRecord> record = getIdentity(recipientId);
|
Optional<IdentityRecord> record = getIdentity(address);
|
||||||
if (record.isPresent()) EventBus.getDefault().post(record.get());
|
if (record.isPresent()) EventBus.getDefault().post(record.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IdentityRecord getIdentityRecord(@NonNull Cursor cursor) throws IOException, InvalidKeyException {
|
private IdentityRecord getIdentityRecord(@NonNull Cursor cursor) throws IOException, InvalidKeyException {
|
||||||
long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT));
|
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
|
||||||
String serializedIdentity = cursor.getString(cursor.getColumnIndexOrThrow(IDENTITY_KEY));
|
String serializedIdentity = cursor.getString(cursor.getColumnIndexOrThrow(IDENTITY_KEY));
|
||||||
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP));
|
long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP));
|
||||||
int verifiedStatus = cursor.getInt(cursor.getColumnIndexOrThrow(VERIFIED));
|
int verifiedStatus = cursor.getInt(cursor.getColumnIndexOrThrow(VERIFIED));
|
||||||
@ -161,23 +159,23 @@ public class IdentityDatabase extends Database {
|
|||||||
boolean firstUse = cursor.getInt(cursor.getColumnIndexOrThrow(FIRST_USE)) == 1;
|
boolean firstUse = cursor.getInt(cursor.getColumnIndexOrThrow(FIRST_USE)) == 1;
|
||||||
IdentityKey identity = new IdentityKey(Base64.decode(serializedIdentity), 0);
|
IdentityKey identity = new IdentityKey(Base64.decode(serializedIdentity), 0);
|
||||||
|
|
||||||
return new IdentityRecord(recipientId, identity, VerifiedStatus.forState(verifiedStatus), firstUse, timestamp, nonblockingApproval);
|
return new IdentityRecord(Address.fromSerialized(address), identity, VerifiedStatus.forState(verifiedStatus), firstUse, timestamp, nonblockingApproval);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class IdentityRecord {
|
public static class IdentityRecord {
|
||||||
|
|
||||||
private final long recipientId;
|
private final Address address;
|
||||||
private final IdentityKey identitykey;
|
private final IdentityKey identitykey;
|
||||||
private final VerifiedStatus verifiedStatus;
|
private final VerifiedStatus verifiedStatus;
|
||||||
private final boolean firstUse;
|
private final boolean firstUse;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final boolean nonblockingApproval;
|
private final boolean nonblockingApproval;
|
||||||
|
|
||||||
private IdentityRecord(long recipientId,
|
private IdentityRecord(Address address,
|
||||||
IdentityKey identitykey, VerifiedStatus verifiedStatus,
|
IdentityKey identitykey, VerifiedStatus verifiedStatus,
|
||||||
boolean firstUse, long timestamp, boolean nonblockingApproval)
|
boolean firstUse, long timestamp, boolean nonblockingApproval)
|
||||||
{
|
{
|
||||||
this.recipientId = recipientId;
|
this.address = address;
|
||||||
this.identitykey = identitykey;
|
this.identitykey = identitykey;
|
||||||
this.verifiedStatus = verifiedStatus;
|
this.verifiedStatus = verifiedStatus;
|
||||||
this.firstUse = firstUse;
|
this.firstUse = firstUse;
|
||||||
@ -185,8 +183,8 @@ public class IdentityDatabase extends Database {
|
|||||||
this.nonblockingApproval = nonblockingApproval;
|
this.nonblockingApproval = nonblockingApproval;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRecipientId() {
|
public Address getAddress() {
|
||||||
return recipientId;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdentityKey getIdentityKey() {
|
public IdentityKey getIdentityKey() {
|
||||||
@ -211,7 +209,7 @@ public class IdentityDatabase extends Database {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "{recipientId: " + recipientId + ", identityKey: " + identitykey + ", verifiedStatus: " + verifiedStatus + ", firstUse: " + firstUse + "}";
|
return "{address: " + address + ", identityKey: " + identitykey + ", verifiedStatus: " + verifiedStatus + ", firstUse: " + firstUse + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ import android.database.Cursor;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
|
||||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
|
||||||
@ -57,10 +57,10 @@ public class MediaDatabase extends Database {
|
|||||||
public static class MediaRecord {
|
public static class MediaRecord {
|
||||||
|
|
||||||
private final DatabaseAttachment attachment;
|
private final DatabaseAttachment attachment;
|
||||||
private final String address;
|
private final Address address;
|
||||||
private final long date;
|
private final long date;
|
||||||
|
|
||||||
private MediaRecord(DatabaseAttachment attachment, String address, long date) {
|
private MediaRecord(DatabaseAttachment attachment, @Nullable Address address, long date) {
|
||||||
this.attachment = attachment;
|
this.attachment = attachment;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.date = date;
|
this.date = date;
|
||||||
@ -69,7 +69,12 @@ public class MediaDatabase extends Database {
|
|||||||
public static MediaRecord from(@NonNull Context context, @NonNull MasterSecret masterSecret, @NonNull Cursor cursor) {
|
public static MediaRecord from(@NonNull Context context, @NonNull MasterSecret masterSecret, @NonNull Cursor cursor) {
|
||||||
AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context);
|
AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context);
|
||||||
DatabaseAttachment attachment = attachmentDatabase.getAttachment(masterSecret, cursor);
|
DatabaseAttachment attachment = attachmentDatabase.getAttachment(masterSecret, cursor);
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
String serializedAddress = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
||||||
|
Address address = null;
|
||||||
|
|
||||||
|
if (serializedAddress != null) {
|
||||||
|
address = Address.fromSerialized(serializedAddress);
|
||||||
|
}
|
||||||
|
|
||||||
long date;
|
long date;
|
||||||
|
|
||||||
@ -90,7 +95,7 @@ public class MediaDatabase extends Database {
|
|||||||
return attachment.getContentType();
|
return attachment.getContentType();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAddress() {
|
public @Nullable Address getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import org.whispersystems.libsignal.IdentityKey;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class MessagingDatabase extends Database implements MmsSmsColumns {
|
public abstract class MessagingDatabase extends Database implements MmsSmsColumns {
|
||||||
@ -30,9 +29,9 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
|
|||||||
|
|
||||||
protected abstract String getTableName();
|
protected abstract String getTableName();
|
||||||
|
|
||||||
public void setMismatchedIdentity(long messageId, final long recipientId, final IdentityKey identityKey) {
|
public void setMismatchedIdentity(long messageId, final Address address, final IdentityKey identityKey) {
|
||||||
List<IdentityKeyMismatch> items = new ArrayList<IdentityKeyMismatch>() {{
|
List<IdentityKeyMismatch> items = new ArrayList<IdentityKeyMismatch>() {{
|
||||||
add(new IdentityKeyMismatch(recipientId, identityKey));
|
add(new IdentityKeyMismatch(address, identityKey));
|
||||||
}};
|
}};
|
||||||
|
|
||||||
IdentityKeyMismatchList document = new IdentityKeyMismatchList(items);
|
IdentityKeyMismatchList document = new IdentityKeyMismatchList(items);
|
||||||
@ -51,20 +50,20 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMismatchedIdentity(long messageId, long recipientId, IdentityKey identityKey) {
|
public void addMismatchedIdentity(long messageId, Address address, IdentityKey identityKey) {
|
||||||
try {
|
try {
|
||||||
addToDocument(messageId, MISMATCHED_IDENTITIES,
|
addToDocument(messageId, MISMATCHED_IDENTITIES,
|
||||||
new IdentityKeyMismatch(recipientId, identityKey),
|
new IdentityKeyMismatch(address, identityKey),
|
||||||
IdentityKeyMismatchList.class);
|
IdentityKeyMismatchList.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeMismatchedIdentity(long messageId, long recipientId, IdentityKey identityKey) {
|
public void removeMismatchedIdentity(long messageId, Address address, IdentityKey identityKey) {
|
||||||
try {
|
try {
|
||||||
removeFromDocument(messageId, MISMATCHED_IDENTITIES,
|
removeFromDocument(messageId, MISMATCHED_IDENTITIES,
|
||||||
new IdentityKeyMismatch(recipientId, identityKey),
|
new IdentityKeyMismatch(address, identityKey),
|
||||||
IdentityKeyMismatchList.class);
|
IdentityKeyMismatchList.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
@ -168,15 +167,15 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
|
|||||||
|
|
||||||
public static class SyncMessageId {
|
public static class SyncMessageId {
|
||||||
|
|
||||||
private final String address;
|
private final Address address;
|
||||||
private final long timetamp;
|
private final long timetamp;
|
||||||
|
|
||||||
public SyncMessageId(String address, long timetamp) {
|
public SyncMessageId(Address address, long timetamp) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.timetamp = timetamp;
|
this.timetamp = timetamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAddress() {
|
public Address getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,18 +55,18 @@ public class MmsAddressDatabase extends Database {
|
|||||||
super(context, databaseHelper);
|
super(context, databaseHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertAddress(long messageId, int type, @NonNull String value) {
|
private void insertAddress(long messageId, int type, @NonNull Address value) {
|
||||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(MMS_ID, messageId);
|
contentValues.put(MMS_ID, messageId);
|
||||||
contentValues.put(TYPE, type);
|
contentValues.put(TYPE, type);
|
||||||
contentValues.put(ADDRESS, value);
|
contentValues.put(ADDRESS, value.serialize());
|
||||||
contentValues.put(ADDRESS_CHARSET, "UTF-8");
|
contentValues.put(ADDRESS_CHARSET, "UTF-8");
|
||||||
database.insert(TABLE_NAME, null, contentValues);
|
database.insert(TABLE_NAME, null, contentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertAddress(long messageId, int type, @NonNull List<String> addresses) {
|
private void insertAddress(long messageId, int type, @NonNull List<Address> addresses) {
|
||||||
for (String address : addresses) {
|
for (Address address : addresses) {
|
||||||
insertAddress(messageId, type, address);
|
insertAddress(messageId, type, address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,17 +84,17 @@ public class MmsAddressDatabase extends Database {
|
|||||||
public MmsAddresses getAddressesForId(long messageId) {
|
public MmsAddresses getAddressesForId(long messageId) {
|
||||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
String from = null;
|
Address from = null;
|
||||||
List<String> to = new LinkedList<>();
|
List<Address> to = new LinkedList<>();
|
||||||
List<String> cc = new LinkedList<>();
|
List<Address> cc = new LinkedList<>();
|
||||||
List<String> bcc = new LinkedList<>();
|
List<Address> bcc = new LinkedList<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = database.query(TABLE_NAME, null, MMS_ID + " = ?", new String[] {messageId+""}, null, null, null);
|
cursor = database.query(TABLE_NAME, null, MMS_ID + " = ?", new String[] {messageId+""}, null, null, null);
|
||||||
|
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(TYPE));
|
long type = cursor.getLong(cursor.getColumnIndexOrThrow(TYPE));
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS));
|
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||||
|
|
||||||
if (type == PduHeaders.FROM) from = address;
|
if (type == PduHeaders.FROM) from = address;
|
||||||
if (type == PduHeaders.TO) to.add(address);
|
if (type == PduHeaders.TO) to.add(address);
|
||||||
@ -109,8 +109,8 @@ public class MmsAddressDatabase extends Database {
|
|||||||
return new MmsAddresses(from, to, cc, bcc);
|
return new MmsAddresses(from, to, cc, bcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getAddressesListForId(long messageId) {
|
public List<Address> getAddressesListForId(long messageId) {
|
||||||
List<String> results = new LinkedList<>();
|
List<Address> results = new LinkedList<>();
|
||||||
MmsAddresses addresses = getAddressesForId(messageId);
|
MmsAddresses addresses = getAddressesForId(messageId);
|
||||||
|
|
||||||
if (addresses.getFrom() != null) {
|
if (addresses.getFrom() != null) {
|
||||||
@ -125,13 +125,12 @@ public class MmsAddressDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Recipients getRecipientsForId(long messageId) {
|
public Recipients getRecipientsForId(long messageId) {
|
||||||
List<String> numbers = getAddressesListForId(messageId);
|
List<Address> addresses = getAddressesListForId(messageId);
|
||||||
List<Recipient> results = new LinkedList<>();
|
List<Recipient> results = new LinkedList<>();
|
||||||
|
|
||||||
for (String number : numbers) {
|
for (Address address : addresses) {
|
||||||
if (!PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR.equals(number)) {
|
if (!PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR.equals(address.serialize())) {
|
||||||
results.add(RecipientFactory.getRecipientsFromString(context, number, false)
|
results.add(RecipientFactory.getRecipientFor(context, address, false));
|
||||||
.getPrimaryRecipient());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,13 +8,13 @@ import java.util.List;
|
|||||||
|
|
||||||
public class MmsAddresses {
|
public class MmsAddresses {
|
||||||
|
|
||||||
private final @Nullable String from;
|
private final @Nullable Address from;
|
||||||
private final @NonNull List<String> to;
|
private final @NonNull List<Address> to;
|
||||||
private final @NonNull List<String> cc;
|
private final @NonNull List<Address> cc;
|
||||||
private final @NonNull List<String> bcc;
|
private final @NonNull List<Address> bcc;
|
||||||
|
|
||||||
public MmsAddresses(@Nullable String from, @NonNull List<String> to,
|
public MmsAddresses(@Nullable Address from, @NonNull List<Address> to,
|
||||||
@NonNull List<String> cc, @NonNull List<String> bcc)
|
@NonNull List<Address> cc, @NonNull List<Address> bcc)
|
||||||
{
|
{
|
||||||
this.from = from;
|
this.from = from;
|
||||||
this.to = to;
|
this.to = to;
|
||||||
@ -23,34 +23,34 @@ public class MmsAddresses {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<String> getTo() {
|
public List<Address> getTo() {
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<String> getCc() {
|
public List<Address> getCc() {
|
||||||
return cc;
|
return cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<String> getBcc() {
|
public List<Address> getBcc() {
|
||||||
return bcc;
|
return bcc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getFrom() {
|
public Address getFrom() {
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MmsAddresses forTo(@NonNull List<String> to) {
|
public static MmsAddresses forTo(@NonNull List<Address> to) {
|
||||||
return new MmsAddresses(null, to, new LinkedList<String>(), new LinkedList<String>());
|
return new MmsAddresses(null, to, new LinkedList<Address>(), new LinkedList<Address>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MmsAddresses forBcc(@NonNull List<String> bcc) {
|
public static MmsAddresses forBcc(@NonNull List<Address> bcc) {
|
||||||
return new MmsAddresses(null, new LinkedList<String>(), new LinkedList<String>(), bcc);
|
return new MmsAddresses(null, new LinkedList<Address>(), new LinkedList<Address>(), bcc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MmsAddresses forFrom(@NonNull String from) {
|
public static MmsAddresses forFrom(@NonNull Address from) {
|
||||||
return new MmsAddresses(from, new LinkedList<String>(), new LinkedList<String>(), new LinkedList<String>());
|
return new MmsAddresses(from, new LinkedList<Address>(), new LinkedList<Address>(), new LinkedList<Address>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,16 +51,15 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
|
|||||||
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||||
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
@ -68,7 +67,6 @@ import org.thoughtcrime.securesms.util.Util;
|
|||||||
import org.whispersystems.jobqueue.JobManager;
|
import org.whispersystems.jobqueue.JobManager;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
@ -78,11 +76,6 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.util.Util.canonicalizeNumber;
|
|
||||||
import static org.thoughtcrime.securesms.util.Util.canonicalizeNumberOrGroup;
|
|
||||||
|
|
||||||
public class MmsDatabase extends MessagingDatabase {
|
public class MmsDatabase extends MessagingDatabase {
|
||||||
|
|
||||||
private static final String TAG = MmsDatabase.class.getSimpleName();
|
private static final String TAG = MmsDatabase.class.getSimpleName();
|
||||||
@ -212,39 +205,30 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)))) {
|
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)))) {
|
||||||
List<String> addresses = addressDatabase.getAddressesListForId(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
List<Address> addresses = addressDatabase.getAddressesListForId(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
||||||
|
|
||||||
for (String storedAddress : addresses) {
|
for (Address theirAddress : addresses) {
|
||||||
try {
|
Address ourAddress = messageId.getAddress();
|
||||||
String ourAddress = canonicalizeNumber(context, messageId.getAddress());
|
|
||||||
String theirAddress = canonicalizeNumberOrGroup(context, storedAddress);
|
|
||||||
|
|
||||||
if (ourAddress.equals(theirAddress) || GroupUtil.isEncodedGroup(theirAddress)) {
|
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
|
database.execSQL("UPDATE " + TABLE_NAME + " SET " +
|
||||||
RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " + ID + " = ?",
|
RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " + ID + " = ?",
|
||||||
new String[] {String.valueOf(id)});
|
new String[] {String.valueOf(id)});
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
}
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w("MmsDatabase", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
try {
|
earlyReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||||
earlyReceiptCache.increment(messageId.getTimetamp(), canonicalizeNumber(context, messageId.getAddress()));
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
if (cursor != null)
|
||||||
@ -273,12 +257,12 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException, MmsException {
|
private long getThreadIdFor(IncomingMediaMessage retrieved) throws RecipientFormattingException, MmsException {
|
||||||
if (retrieved.getGroupId() != null) {
|
if (retrieved.getGroupId() != null) {
|
||||||
Recipients groupRecipients = RecipientFactory.getRecipientsFromString(context, retrieved.getGroupId(), true);
|
Recipients groupRecipients = RecipientFactory.getRecipientsFor(context, new Address[] {retrieved.getGroupId()}, true);
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
|
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
|
||||||
}
|
}
|
||||||
|
|
||||||
String localNumber;
|
String localNumber;
|
||||||
Set<String> group = new HashSet<>();
|
Set<Address> group = new HashSet<>();
|
||||||
|
|
||||||
if (retrieved.getAddresses().getFrom() == null) {
|
if (retrieved.getAddresses().getFrom() == null) {
|
||||||
throw new MmsException("FROM value in PduHeaders did not exist.");
|
throw new MmsException("FROM value in PduHeaders did not exist.");
|
||||||
@ -292,11 +276,11 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
localNumber = ServiceUtil.getTelephonyManager(context).getLine1Number();
|
localNumber = ServiceUtil.getTelephonyManager(context).getLine1Number();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String cc : retrieved.getAddresses().getCc()) {
|
for (Address cc : retrieved.getAddresses().getCc()) {
|
||||||
PhoneNumberUtil.MatchType match;
|
PhoneNumberUtil.MatchType match;
|
||||||
|
|
||||||
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
|
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
|
||||||
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, cc);
|
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, cc.toPhoneString());
|
||||||
|
|
||||||
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
|
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
|
||||||
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
|
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
|
||||||
@ -307,11 +291,11 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
|
|
||||||
if (retrieved.getAddresses().getTo().size() > 1) {
|
if (retrieved.getAddresses().getTo().size() > 1) {
|
||||||
for (String to : retrieved.getAddresses().getTo()) {
|
for (Address to : retrieved.getAddresses().getTo()) {
|
||||||
PhoneNumberUtil.MatchType match;
|
PhoneNumberUtil.MatchType match;
|
||||||
|
|
||||||
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
|
if (localNumber == null) match = PhoneNumberUtil.MatchType.NO_MATCH;
|
||||||
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, to);
|
else match = PhoneNumberUtil.getInstance().isNumberMatch(localNumber, to.toPhoneString());
|
||||||
|
|
||||||
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
|
if (match == PhoneNumberUtil.MatchType.NO_MATCH ||
|
||||||
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
|
match == PhoneNumberUtil.MatchType.NOT_A_NUMBER)
|
||||||
@ -322,8 +306,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String recipientsList = Util.join(group, ",");
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, group.toArray(new Address[0]), false);
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, recipientsList, false);
|
|
||||||
|
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||||
}
|
}
|
||||||
@ -332,8 +315,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
String fromString = notification.getFrom() != null && notification.getFrom().getTextString() != null
|
String fromString = notification.getFrom() != null && notification.getFrom().getTextString() != null
|
||||||
? Util.toIsoString(notification.getFrom().getTextString())
|
? Util.toIsoString(notification.getFrom().getTextString())
|
||||||
: "";
|
: "";
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, fromString, false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, fromString)}, false);
|
||||||
if (recipients.isEmpty()) recipients = RecipientFactory.getRecipientsFor(context, Recipient.getUnknownRecipient(), false);
|
|
||||||
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
return DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,7 +468,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
while(cursor != null && cursor.moveToNext()) {
|
while(cursor != null && cursor.moveToNext()) {
|
||||||
if (Types.isSecureType(cursor.getLong(3))) {
|
if (Types.isSecureType(cursor.getLong(3))) {
|
||||||
SyncMessageId syncMessageId = new SyncMessageId(cursor.getString(1), cursor.getLong(2));
|
SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(cursor.getString(1)), cursor.getLong(2));
|
||||||
ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), cursor.getLong(4), cursor.getLong(5), true);
|
ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), cursor.getLong(4), cursor.getLong(5), true);
|
||||||
|
|
||||||
result.add(new MarkedMessageInfo(syncMessageId, expirationInfo));
|
result.add(new MarkedMessageInfo(syncMessageId, expirationInfo));
|
||||||
@ -516,34 +498,29 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
List<String> addresses = addressDatabase.getAddressesListForId(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
List<Address> addresses = addressDatabase.getAddressesListForId(cursor.getLong(cursor.getColumnIndexOrThrow(ID)));
|
||||||
|
|
||||||
for (String storedAddress : addresses) {
|
for (Address theirAddress : addresses) {
|
||||||
try {
|
Address ourAddress = messageId.getAddress();
|
||||||
String ourAddress = canonicalizeNumber(context, messageId.getAddress());
|
|
||||||
String theirAddress = canonicalizeNumberOrGroup(context, storedAddress);
|
|
||||||
|
|
||||||
if (ourAddress.equals(theirAddress) || GroupUtil.isEncodedGroup(theirAddress)) {
|
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||||
|
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(READ, 1);
|
values.put(READ, 1);
|
||||||
|
|
||||||
if (expiresIn > 0) {
|
if (expiresIn > 0) {
|
||||||
values.put(EXPIRE_STARTED, expireStarted);
|
values.put(EXPIRE_STARTED, expireStarted);
|
||||||
expiring.add(new Pair<>(id, expiresIn));
|
expiring.add(new Pair<>(id, expiresIn));
|
||||||
}
|
|
||||||
|
|
||||||
database.update(TABLE_NAME, values, ID_WHERE, new String[]{String.valueOf(id)});
|
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
|
|
||||||
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
|
||||||
notifyConversationListeners(threadId);
|
|
||||||
}
|
}
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w("MmsDatabase", e);
|
database.update(TABLE_NAME, values, ID_WHERE, new String[]{String.valueOf(id)});
|
||||||
|
|
||||||
|
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
|
||||||
|
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
||||||
|
notifyConversationListeners(threadId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -630,14 +607,14 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||||
List<Attachment> attachments = new LinkedList<Attachment>(attachmentDatabase.getAttachmentsForMessage(masterSecret, messageId));
|
List<Attachment> attachments = new LinkedList<Attachment>(attachmentDatabase.getAttachmentsForMessage(masterSecret, messageId));
|
||||||
MmsAddresses addresses = addr.getAddressesForId(messageId);
|
MmsAddresses addresses = addr.getAddressesForId(messageId);
|
||||||
List<String> destinations = new LinkedList<>();
|
List<Address> destinations = new LinkedList<>();
|
||||||
String body = getDecryptedBody(masterSecret, messageText, outboxType);
|
String body = getDecryptedBody(masterSecret, messageText, outboxType);
|
||||||
|
|
||||||
destinations.addAll(addresses.getBcc());
|
destinations.addAll(addresses.getBcc());
|
||||||
destinations.addAll(addresses.getCc());
|
destinations.addAll(addresses.getCc());
|
||||||
destinations.addAll(addresses.getTo());
|
destinations.addAll(addresses.getTo());
|
||||||
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromStrings(context, destinations, false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, destinations.toArray(new Address[0]), false);
|
||||||
|
|
||||||
if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) {
|
if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) {
|
||||||
return new OutgoingGroupMediaMessage(recipients, body, attachments, timestamp, 0);
|
return new OutgoingGroupMediaMessage(recipients, body, attachments, timestamp, 0);
|
||||||
@ -668,7 +645,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
try {
|
try {
|
||||||
OutgoingMediaMessage request = getOutgoingMessage(masterSecret, messageId);
|
OutgoingMediaMessage request = getOutgoingMessage(masterSecret, messageId);
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(ADDRESS, request.getRecipients().getPrimaryRecipient().getNumber());
|
contentValues.put(ADDRESS, request.getRecipients().getPrimaryRecipient().getAddress().serialize());
|
||||||
contentValues.put(DATE_SENT, request.getSentTimeMillis());
|
contentValues.put(DATE_SENT, request.getSentTimeMillis());
|
||||||
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT | Types.ENCRYPTION_SYMMETRIC_BIT);
|
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT | Types.ENCRYPTION_SYMMETRIC_BIT);
|
||||||
contentValues.put(THREAD_ID, getThreadIdForMessage(messageId));
|
contentValues.put(THREAD_ID, getThreadIdForMessage(messageId));
|
||||||
@ -697,7 +674,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return insertMediaMessage(new MasterSecretUnion(masterSecret),
|
return insertMediaMessage(new MasterSecretUnion(masterSecret),
|
||||||
MmsAddresses.forTo(request.getRecipients().toNumberStringList(false)),
|
MmsAddresses.forTo(request.getRecipients().getAddressesList()),
|
||||||
request.getBody(),
|
request.getBody(),
|
||||||
attachments,
|
attachments,
|
||||||
contentValues,
|
contentValues,
|
||||||
@ -726,7 +703,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
|
|
||||||
contentValues.put(DATE_SENT, retrieved.getSentTimeMillis());
|
contentValues.put(DATE_SENT, retrieved.getSentTimeMillis());
|
||||||
contentValues.put(ADDRESS, retrieved.getAddresses().getFrom());
|
contentValues.put(ADDRESS, retrieved.getAddresses().getFrom().serialize());
|
||||||
|
|
||||||
contentValues.put(MESSAGE_BOX, mailbox);
|
contentValues.put(MESSAGE_BOX, mailbox);
|
||||||
contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF);
|
contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF);
|
||||||
@ -847,7 +824,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
||||||
|
|
||||||
if (notification.getFrom() != null) {
|
if (notification.getFrom() != null) {
|
||||||
addressDatabase.insertAddressesForId(messageId, MmsAddresses.forFrom(Util.toIsoString(notification.getFrom().getTextString())));
|
addressDatabase.insertAddressesForId(messageId, MmsAddresses.forFrom(Address.fromExternal(context, Util.toIsoString(notification.getFrom().getTextString()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Pair<>(messageId, threadId);
|
return new Pair<>(messageId, threadId);
|
||||||
@ -887,7 +864,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
|
type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> recipientNumbers = message.getRecipients().toNumberStringList(true);
|
List<Address> recipientNumbers = message.getRecipients().getAddressesList();
|
||||||
|
|
||||||
MmsAddresses addresses;
|
MmsAddresses addresses;
|
||||||
|
|
||||||
@ -911,12 +888,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
||||||
|
|
||||||
if (message.getRecipients().isSingleRecipient()) {
|
if (message.getRecipients().isSingleRecipient()) {
|
||||||
try {
|
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(message.getSentTimeMillis(), message.getRecipients().getPrimaryRecipient().getAddress()));
|
||||||
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(message.getSentTimeMillis(),
|
|
||||||
canonicalizeNumber(context, message.getRecipients().getPrimaryRecipient().getNumber())));
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
contentValues.remove(ADDRESS);
|
contentValues.remove(ADDRESS);
|
||||||
@ -1021,7 +993,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
private boolean isDuplicate(IncomingMediaMessage message, long threadId) {
|
private boolean isDuplicate(IncomingMediaMessage message, long threadId) {
|
||||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",
|
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",
|
||||||
new String[]{String.valueOf(message.getSentTimeMillis()), message.getAddresses().getFrom(), String.valueOf(threadId)},
|
new String[]{String.valueOf(message.getSentTimeMillis()), message.getAddresses().getFrom().serialize(), String.valueOf(threadId)},
|
||||||
null, null, null, "1");
|
null, null, null, "1");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1249,21 +1221,21 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
|
private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) {
|
||||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.ID));
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.ID));
|
||||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_SENT));
|
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_SENT));
|
||||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
|
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
|
||||||
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
|
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
String address = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS));
|
||||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS_DEVICE_ID));
|
||||||
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.RECEIPT_COUNT));
|
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.RECEIPT_COUNT));
|
||||||
DisplayRecord.Body body = getBody(cursor);
|
DisplayRecord.Body body = getBody(cursor);
|
||||||
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
|
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
|
||||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
||||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
|
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
|
||||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.SUBSCRIPTION_ID));
|
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.SUBSCRIPTION_ID));
|
||||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
|
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRES_IN));
|
||||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
|
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.EXPIRE_STARTED));
|
||||||
|
|
||||||
Recipients recipients = getRecipientsFor(address);
|
Recipients recipients = getRecipientsFor(address);
|
||||||
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
|
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
|
||||||
@ -1276,18 +1248,16 @@ public class MmsDatabase extends MessagingDatabase {
|
|||||||
networkFailures, subscriptionId, expiresIn, expireStarted);
|
networkFailures, subscriptionId, expiresIn, expireStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Recipients getRecipientsFor(String address) {
|
private Recipients getRecipientsFor(String serialized) {
|
||||||
if (TextUtils.isEmpty(address) || address.equals("insert-address-token")) {
|
Address address;
|
||||||
return RecipientFactory.getRecipientsFor(context, Recipient.getUnknownRecipient(), true);
|
|
||||||
|
if (TextUtils.isEmpty(serialized) || "insert-address-token".equals(serialized)) {
|
||||||
|
address = Address.UNKNOWN;
|
||||||
|
} else {
|
||||||
|
address = Address.fromSerialized(serialized);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return RecipientFactory.getRecipientsFor(context, new Address[] {address}, true);
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, address, true);
|
|
||||||
|
|
||||||
if (recipients == null || recipients.isEmpty()) {
|
|
||||||
return RecipientFactory.getRecipientsFor(context, Recipient.getUnknownRecipient(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return recipients;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<IdentityKeyMismatch> getMismatchedIdentities(String document) {
|
private List<IdentityKeyMismatch> getMismatchedIdentities(String document) {
|
||||||
|
@ -44,7 +44,7 @@ public class PlaintextBackupExporter {
|
|||||||
|
|
||||||
while ((record = reader.getNext()) != null) {
|
while ((record = reader.getNext()) != null) {
|
||||||
XmlBackup.XmlBackupItem item =
|
XmlBackup.XmlBackupItem item =
|
||||||
new XmlBackup.XmlBackupItem(0, record.getIndividualRecipient().getNumber(),
|
new XmlBackup.XmlBackupItem(0, record.getIndividualRecipient().getAddress().serialize(),
|
||||||
record.getIndividualRecipient().getName(),
|
record.getIndividualRecipient().getName(),
|
||||||
record.getDateReceived(),
|
record.getDateReceived(),
|
||||||
MmsSmsColumns.Types.translateToSystemBaseType(record.getType()),
|
MmsSmsColumns.Types.translateToSystemBaseType(record.getType()),
|
||||||
|
@ -34,7 +34,7 @@ public class PlaintextBackupImporter {
|
|||||||
XmlBackup.XmlBackupItem item;
|
XmlBackup.XmlBackupItem item;
|
||||||
|
|
||||||
while ((item = backup.getNext()) != null) {
|
while ((item = backup.getNext()) != null) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, item.getAddress(), false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, item.getAddress())}, false);
|
||||||
long threadId = threads.getThreadIdFor(recipients);
|
long threadId = threads.getThreadIdFor(recipients);
|
||||||
SQLiteStatement statement = db.createInsertStatement(transaction);
|
SQLiteStatement statement = db.createInsertStatement(transaction);
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
public class RecipientPreferenceDatabase extends Database {
|
public class RecipientPreferenceDatabase extends Database {
|
||||||
|
|
||||||
private static final String TAG = RecipientPreferenceDatabase.class.getSimpleName();
|
private static final String TAG = RecipientPreferenceDatabase.class.getSimpleName();
|
||||||
@ -27,7 +26,7 @@ public class RecipientPreferenceDatabase extends Database {
|
|||||||
|
|
||||||
private static final String TABLE_NAME = "recipient_preferences";
|
private static final String TABLE_NAME = "recipient_preferences";
|
||||||
private static final String ID = "_id";
|
private static final String ID = "_id";
|
||||||
private static final String RECIPIENT_IDS = "recipient_ids";
|
private static final String ADDRESSES = "recipient_ids";
|
||||||
private static final String BLOCK = "block";
|
private static final String BLOCK = "block";
|
||||||
private static final String NOTIFICATION = "notification";
|
private static final String NOTIFICATION = "notification";
|
||||||
private static final String VIBRATE = "vibrate";
|
private static final String VIBRATE = "vibrate";
|
||||||
@ -58,7 +57,7 @@ public class RecipientPreferenceDatabase extends Database {
|
|||||||
public static final String CREATE_TABLE =
|
public static final String CREATE_TABLE =
|
||||||
"CREATE TABLE " + TABLE_NAME +
|
"CREATE TABLE " + TABLE_NAME +
|
||||||
" (" + ID + " INTEGER PRIMARY KEY, " +
|
" (" + ID + " INTEGER PRIMARY KEY, " +
|
||||||
RECIPIENT_IDS + " TEXT UNIQUE, " +
|
ADDRESSES + " TEXT UNIQUE, " +
|
||||||
BLOCK + " INTEGER DEFAULT 0," +
|
BLOCK + " INTEGER DEFAULT 0," +
|
||||||
NOTIFICATION + " TEXT DEFAULT NULL, " +
|
NOTIFICATION + " TEXT DEFAULT NULL, " +
|
||||||
VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
|
VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
|
||||||
@ -75,7 +74,7 @@ public class RecipientPreferenceDatabase extends Database {
|
|||||||
public Cursor getBlocked() {
|
public Cursor getBlocked() {
|
||||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||||
|
|
||||||
Cursor cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_IDS}, BLOCK + " = 1",
|
Cursor cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESSES}, BLOCK + " = 1",
|
||||||
null, null, null, null, null);
|
null, null, null, null, null);
|
||||||
cursor.setNotificationUri(context.getContentResolver(), Uri.parse(RECIPIENT_PREFERENCES_URI));
|
cursor.setNotificationUri(context.getContentResolver(), Uri.parse(RECIPIENT_PREFERENCES_URI));
|
||||||
|
|
||||||
@ -86,15 +85,15 @@ public class RecipientPreferenceDatabase extends Database {
|
|||||||
return new BlockedReader(context, cursor);
|
return new BlockedReader(context, cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<RecipientsPreferences> getRecipientsPreferences(@NonNull long[] recipients) {
|
public Optional<RecipientsPreferences> getRecipientsPreferences(@NonNull Address[] addresses) {
|
||||||
Arrays.sort(recipients);
|
Arrays.sort(addresses);
|
||||||
|
|
||||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = database.query(TABLE_NAME, null, RECIPIENT_IDS + " = ?",
|
cursor = database.query(TABLE_NAME, null, ADDRESSES + " = ?",
|
||||||
new String[] {Util.join(recipients, " ")},
|
new String[] {Util.join(addresses, " ")},
|
||||||
null, null, null);
|
null, null, null);
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToNext()) {
|
if (cursor != null && cursor.moveToNext()) {
|
||||||
@ -188,11 +187,11 @@ public class RecipientPreferenceDatabase extends Database {
|
|||||||
|
|
||||||
database.beginTransaction();
|
database.beginTransaction();
|
||||||
|
|
||||||
int updated = database.update(TABLE_NAME, contentValues, RECIPIENT_IDS + " = ?",
|
int updated = database.update(TABLE_NAME, contentValues, ADDRESSES + " = ?",
|
||||||
new String[] {String.valueOf(recipients.getSortedIdsString())});
|
new String[] {Util.join(recipients.getAddresses(), " ")});
|
||||||
|
|
||||||
if (updated < 1) {
|
if (updated < 1) {
|
||||||
contentValues.put(RECIPIENT_IDS, recipients.getSortedIdsString());
|
contentValues.put(ADDRESSES, Util.join(recipients.getAddresses(), " "));
|
||||||
database.insert(TABLE_NAME, null, contentValues);
|
database.insert(TABLE_NAME, null, contentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,8 +273,15 @@ public class RecipientPreferenceDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Recipients getCurrent() {
|
public @NonNull Recipients getCurrent() {
|
||||||
String recipientIds = cursor.getString(cursor.getColumnIndexOrThrow(RECIPIENT_IDS));
|
String serialized = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESSES));
|
||||||
return RecipientFactory.getRecipientsForIds(context, recipientIds, false);
|
String[] addresses = serialized.split(" ");
|
||||||
|
Address[] addressList = new Address[addresses.length];
|
||||||
|
|
||||||
|
for (int i=0;i<addresses.length;i++) {
|
||||||
|
addressList[i] = Address.fromSerialized(addresses[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RecipientFactory.getRecipientsFor(context, addressList, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Recipients getNext() {
|
public @Nullable Recipients getNext() {
|
||||||
|
@ -23,7 +23,6 @@ import android.database.sqlite.SQLiteDatabase;
|
|||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.database.sqlite.SQLiteStatement;
|
import android.database.sqlite.SQLiteStatement;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.telephony.PhoneNumberUtils;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@ -35,7 +34,6 @@ import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
|||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||||
@ -44,7 +42,6 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
|||||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||||
import org.whispersystems.jobqueue.JobManager;
|
import org.whispersystems.jobqueue.JobManager;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
@ -53,14 +50,11 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.util.Util.canonicalizeNumber;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database for storage of SMS messages.
|
* Database for storage of SMS messages.
|
||||||
*
|
*
|
||||||
* @author Moxie Marlinspike
|
* @author Moxie Marlinspike
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class SmsDatabase extends MessagingDatabase {
|
public class SmsDatabase extends MessagingDatabase {
|
||||||
|
|
||||||
private static final String TAG = SmsDatabase.class.getSimpleName();
|
private static final String TAG = SmsDatabase.class.getSimpleName();
|
||||||
@ -296,34 +290,26 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(TYPE)))) {
|
if (Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(TYPE)))) {
|
||||||
try {
|
Address theirAddress = messageId.getAddress();
|
||||||
String theirAddress = canonicalizeNumber(context, messageId.getAddress());
|
Address ourAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||||
String ourAddress = canonicalizeNumber(context, cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
|
||||||
|
|
||||||
if (ourAddress.equals(theirAddress)) {
|
if (ourAddress.equals(theirAddress)) {
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||||
|
|
||||||
database.execSQL("UPDATE " + TABLE_NAME +
|
database.execSQL("UPDATE " + TABLE_NAME +
|
||||||
" SET " + RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " +
|
" SET " + RECEIPT_COUNT + " = " + RECEIPT_COUNT + " + 1 WHERE " +
|
||||||
ID + " = ?",
|
ID + " = ?",
|
||||||
new String[] {String.valueOf(cursor.getLong(cursor.getColumnIndexOrThrow(ID)))});
|
new String[] {String.valueOf(cursor.getLong(cursor.getColumnIndexOrThrow(ID)))});
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||||
notifyConversationListeners(threadId);
|
notifyConversationListeners(threadId);
|
||||||
foundMessage = true;
|
foundMessage = true;
|
||||||
}
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundMessage) {
|
if (!foundMessage) {
|
||||||
try {
|
earlyReceiptCache.increment(messageId.getTimetamp(), messageId.getAddress());
|
||||||
earlyReceiptCache.increment(messageId.getTimetamp(), canonicalizeNumber(context, messageId.getAddress()));
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
@ -345,7 +331,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
while (cursor != null && cursor.moveToNext()) {
|
while (cursor != null && cursor.moveToNext()) {
|
||||||
if (Types.isSecureType(cursor.getLong(3))) {
|
if (Types.isSecureType(cursor.getLong(3))) {
|
||||||
SyncMessageId syncMessageId = new SyncMessageId(cursor.getString(1), cursor.getLong(2));
|
SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(cursor.getString(1)), cursor.getLong(2));
|
||||||
ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), cursor.getLong(4), cursor.getLong(5), false);
|
ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), cursor.getLong(4), cursor.getLong(5), false);
|
||||||
|
|
||||||
results.add(new MarkedMessageInfo(syncMessageId, expirationInfo));
|
results.add(new MarkedMessageInfo(syncMessageId, expirationInfo));
|
||||||
@ -376,31 +362,27 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
null, null, null, null);
|
null, null, null, null);
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
try {
|
Address theirAddress = messageId.getAddress();
|
||||||
String theirAddress = canonicalizeNumber(context, messageId.getAddress());
|
Address ourAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||||
String ourAddress = canonicalizeNumber(context, cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
|
||||||
|
|
||||||
if (ourAddress.equals(theirAddress)) {
|
if (ourAddress.equals(theirAddress)) {
|
||||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(READ, 1);
|
contentValues.put(READ, 1);
|
||||||
|
|
||||||
if (expiresIn > 0) {
|
if (expiresIn > 0) {
|
||||||
contentValues.put(EXPIRE_STARTED, expireStarted);
|
contentValues.put(EXPIRE_STARTED, expireStarted);
|
||||||
expiring.add(new Pair<>(id, expiresIn));
|
expiring.add(new Pair<>(id, expiresIn));
|
||||||
}
|
|
||||||
|
|
||||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {cursor.getLong(cursor.getColumnIndexOrThrow(ID)) + ""});
|
|
||||||
|
|
||||||
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
|
|
||||||
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
|
||||||
notifyConversationListeners(threadId);
|
|
||||||
}
|
}
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {cursor.getLong(cursor.getColumnIndexOrThrow(ID)) + ""});
|
||||||
|
|
||||||
|
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
|
||||||
|
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
||||||
|
notifyConversationListeners(threadId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -440,7 +422,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
|
|
||||||
ContentValues contentValues = new ContentValues();
|
ContentValues contentValues = new ContentValues();
|
||||||
contentValues.put(TYPE, (record.getType() & ~Types.BASE_TYPE_MASK) | Types.BASE_INBOX_TYPE);
|
contentValues.put(TYPE, (record.getType() & ~Types.BASE_TYPE_MASK) | Types.BASE_INBOX_TYPE);
|
||||||
contentValues.put(ADDRESS, record.getIndividualRecipient().getNumber());
|
contentValues.put(ADDRESS, record.getIndividualRecipient().getAddress().serialize());
|
||||||
contentValues.put(ADDRESS_DEVICE_ID, record.getRecipientDeviceId());
|
contentValues.put(ADDRESS_DEVICE_ID, record.getRecipientDeviceId());
|
||||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||||
contentValues.put(DATE_SENT, record.getDateSent());
|
contentValues.put(DATE_SENT, record.getDateSent());
|
||||||
@ -462,24 +444,24 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
return new Pair<>(newMessageId, record.getThreadId());
|
return new Pair<>(newMessageId, record.getThreadId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Pair<Long, Long> insertReceivedCall(@NonNull String number) {
|
public @NonNull Pair<Long, Long> insertReceivedCall(@NonNull Address address) {
|
||||||
return insertCallLog(number, Types.INCOMING_CALL_TYPE, false);
|
return insertCallLog(address, Types.INCOMING_CALL_TYPE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Pair<Long, Long> insertOutgoingCall(@NonNull String number) {
|
public @NonNull Pair<Long, Long> insertOutgoingCall(@NonNull Address address) {
|
||||||
return insertCallLog(number, Types.OUTGOING_CALL_TYPE, false);
|
return insertCallLog(address, Types.OUTGOING_CALL_TYPE, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Pair<Long, Long> insertMissedCall(@NonNull String number) {
|
public @NonNull Pair<Long, Long> insertMissedCall(@NonNull Address address) {
|
||||||
return insertCallLog(number, Types.MISSED_CALL_TYPE, true);
|
return insertCallLog(address, Types.MISSED_CALL_TYPE, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull Pair<Long, Long> insertCallLog(@NonNull String number, long type, boolean unread) {
|
private @NonNull Pair<Long, Long> insertCallLog(@NonNull Address address, long type, boolean unread) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, number, true);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {address}, true);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||||
|
|
||||||
ContentValues values = new ContentValues(6);
|
ContentValues values = new ContentValues(6);
|
||||||
values.put(ADDRESS, number);
|
values.put(ADDRESS, address.serialize());
|
||||||
values.put(ADDRESS_DEVICE_ID, 1);
|
values.put(ADDRESS_DEVICE_ID, 1);
|
||||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||||
values.put(DATE_SENT, System.currentTimeMillis());
|
values.put(DATE_SENT, System.currentTimeMillis());
|
||||||
@ -524,21 +506,14 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT;
|
if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT;
|
||||||
else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT;
|
else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT;
|
||||||
|
|
||||||
Recipients recipients;
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {message.getSender()}, true);
|
||||||
|
|
||||||
if (message.getSender() != null) {
|
|
||||||
recipients = RecipientFactory.getRecipientsFromString(context, message.getSender(), true);
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Sender is null, returning unknown recipient");
|
|
||||||
recipients = RecipientFactory.getRecipientsFor(context, Recipient.getUnknownRecipient(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Recipients groupRecipients;
|
Recipients groupRecipients;
|
||||||
|
|
||||||
if (message.getGroupId() == null) {
|
if (message.getGroupId() == null) {
|
||||||
groupRecipients = null;
|
groupRecipients = null;
|
||||||
} else {
|
} else {
|
||||||
groupRecipients = RecipientFactory.getRecipientsFromString(context, message.getGroupId(), true);
|
groupRecipients = RecipientFactory.getRecipientsFor(context, new Address[] {message.getGroupId()}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean unread = (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context) ||
|
boolean unread = (org.thoughtcrime.securesms.util.Util.isDefaultSmsProvider(context) ||
|
||||||
@ -551,7 +526,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
else threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
|
else threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipients);
|
||||||
|
|
||||||
ContentValues values = new ContentValues(6);
|
ContentValues values = new ContentValues(6);
|
||||||
values.put(ADDRESS, message.getSender());
|
values.put(ADDRESS, message.getSender().serialize());
|
||||||
values.put(ADDRESS_DEVICE_ID, message.getSenderDeviceId());
|
values.put(ADDRESS_DEVICE_ID, message.getSenderDeviceId());
|
||||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||||
values.put(DATE_SENT, message.getSentTimestampMillis());
|
values.put(DATE_SENT, message.getSentTimestampMillis());
|
||||||
@ -614,10 +589,10 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT;
|
if (message.isIdentityVerified()) type |= Types.KEY_EXCHANGE_IDENTITY_VERIFIED_BIT;
|
||||||
else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT;
|
else if (message.isIdentityDefault()) type |= Types.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT;
|
||||||
|
|
||||||
String address = message.getRecipients().getPrimaryRecipient().getNumber();
|
Address address = message.getRecipients().getPrimaryRecipient().getAddress();
|
||||||
|
|
||||||
ContentValues contentValues = new ContentValues(6);
|
ContentValues contentValues = new ContentValues(6);
|
||||||
contentValues.put(ADDRESS, PhoneNumberUtils.formatNumber(address));
|
contentValues.put(ADDRESS, address.serialize());
|
||||||
contentValues.put(THREAD_ID, threadId);
|
contentValues.put(THREAD_ID, threadId);
|
||||||
contentValues.put(BODY, message.getMessageBody());
|
contentValues.put(BODY, message.getMessageBody());
|
||||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||||
@ -626,12 +601,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
contentValues.put(TYPE, type);
|
contentValues.put(TYPE, type);
|
||||||
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId());
|
||||||
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
contentValues.put(EXPIRES_IN, message.getExpiresIn());
|
||||||
|
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(date, address));
|
||||||
try {
|
|
||||||
contentValues.put(RECEIPT_COUNT, earlyReceiptCache.remove(date, canonicalizeNumber(context, address)));
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||||
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
|
long messageId = db.insert(TABLE_NAME, ADDRESS, contentValues);
|
||||||
@ -671,13 +641,13 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
return db.query(TABLE_NAME, MESSAGE_PROJECTION, where, null, null, null, null);
|
return db.query(TABLE_NAME, MESSAGE_PROJECTION, where, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cursor getEncryptedRogueMessages(Recipient recipient) {
|
// public Cursor getEncryptedRogueMessages(Recipient recipient) {
|
||||||
String selection = TYPE + " & " + Types.ENCRYPTION_REMOTE_NO_SESSION_BIT + " != 0" +
|
// String selection = TYPE + " & " + Types.ENCRYPTION_REMOTE_NO_SESSION_BIT + " != 0" +
|
||||||
" AND PHONE_NUMBERS_EQUAL(" + ADDRESS + ", ?)";
|
// " AND PHONE_NUMBERS_EQUAL(" + ADDRESS + ", ?)";
|
||||||
String[] args = {recipient.getNumber()};
|
// String[] args = {recipient.getNumber()};
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
// SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
return db.query(TABLE_NAME, MESSAGE_PROJECTION, selection, args, null, null, null);
|
// return db.query(TABLE_NAME, MESSAGE_PROJECTION, selection, args, null, null, null);
|
||||||
}
|
// }
|
||||||
|
|
||||||
public Cursor getExpirationStartedMessages() {
|
public Cursor getExpirationStartedMessages() {
|
||||||
String where = EXPIRE_STARTED + " > 0";
|
String where = EXPIRE_STARTED + " > 0";
|
||||||
@ -706,7 +676,7 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
private boolean isDuplicate(IncomingTextMessage message, long threadId) {
|
private boolean isDuplicate(IncomingTextMessage message, long threadId) {
|
||||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",
|
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",
|
||||||
new String[]{String.valueOf(message.getSentTimestampMillis()), message.getSender(), String.valueOf(threadId)},
|
new String[]{String.valueOf(message.getSentTimestampMillis()), message.getSender().serialize(), String.valueOf(threadId)},
|
||||||
null, null, null, "1");
|
null, null, null, "1");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -843,19 +813,19 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SmsMessageRecord getCurrent() {
|
public SmsMessageRecord getCurrent() {
|
||||||
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.ID));
|
long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.ID));
|
||||||
String address = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS));
|
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS)));
|
||||||
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS_DEVICE_ID));
|
int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS_DEVICE_ID));
|
||||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.TYPE));
|
long type = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.TYPE));
|
||||||
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_RECEIVED));
|
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_RECEIVED));
|
||||||
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_SENT));
|
long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.NORMALIZED_DATE_SENT));
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.THREAD_ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.THREAD_ID));
|
||||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.STATUS));
|
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.STATUS));
|
||||||
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.RECEIPT_COUNT));
|
int receiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.RECEIPT_COUNT));
|
||||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.MISMATCHED_IDENTITIES));
|
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.MISMATCHED_IDENTITIES));
|
||||||
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.SUBSCRIPTION_ID));
|
int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.SUBSCRIPTION_ID));
|
||||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRES_IN));
|
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRES_IN));
|
||||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
|
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.EXPIRE_STARTED));
|
||||||
|
|
||||||
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
List<IdentityKeyMismatch> mismatches = getMismatches(mismatchDocument);
|
||||||
Recipients recipients = getRecipientsFor(address);
|
Recipients recipients = getRecipientsFor(address);
|
||||||
@ -869,19 +839,8 @@ public class SmsDatabase extends MessagingDatabase {
|
|||||||
expiresIn, expireStarted);
|
expiresIn, expireStarted);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Recipients getRecipientsFor(String address) {
|
private Recipients getRecipientsFor(Address address) {
|
||||||
if (address != null) {
|
return RecipientFactory.getRecipientsFor(context, new Address[] {address}, true);
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, address, true);
|
|
||||||
|
|
||||||
if (recipients == null || recipients.isEmpty()) {
|
|
||||||
return RecipientFactory.getRecipientsFor(context, Recipient.getUnknownRecipient(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return recipients;
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "getRecipientsFor() address is null");
|
|
||||||
return RecipientFactory.getRecipientsFor(context, Recipient.getUnknownRecipient(), true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<IdentityKeyMismatch> getMismatches(String document) {
|
private List<IdentityKeyMismatch> getMismatches(String document) {
|
||||||
|
@ -27,9 +27,10 @@ import android.util.Log;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
public class SmsMigrator {
|
public class SmsMigrator {
|
||||||
@ -137,24 +138,20 @@ public class SmsMigrator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Recipients getOurRecipients(Context context, String theirRecipients) {
|
private static Recipients getOurRecipients(Context context, String theirRecipients) {
|
||||||
StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " ");
|
StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " ");
|
||||||
StringBuilder sb = new StringBuilder();
|
List<Address> addressList = new LinkedList<>();
|
||||||
|
|
||||||
while (tokenizer.hasMoreTokens()) {
|
while (tokenizer.hasMoreTokens()) {
|
||||||
String theirRecipientId = tokenizer.nextToken();
|
String theirRecipientId = tokenizer.nextToken();
|
||||||
String address = getTheirCanonicalAddress(context, theirRecipientId);
|
String address = getTheirCanonicalAddress(context, theirRecipientId);
|
||||||
|
|
||||||
if (address == null)
|
if (address != null) {
|
||||||
continue;
|
addressList.add(Address.fromExternal(context, address));
|
||||||
|
}
|
||||||
if (sb.length() != 0)
|
|
||||||
sb.append(',');
|
|
||||||
|
|
||||||
sb.append(address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sb.length() == 0) return null;
|
if (addressList.isEmpty()) return null;
|
||||||
else return RecipientFactory.getRecipientsFromString(context, sb.toString(), true);
|
else return RecipientFactory.getRecipientsFor(context, addressList.toArray(new Address[0]), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String encrypt(MasterSecret masterSecret, String body)
|
private static String encrypt(MasterSecret masterSecret, String body)
|
||||||
|
@ -7,7 +7,7 @@ import android.database.sqlite.SQLiteDatabase;
|
|||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||||
import android.text.TextUtils;
|
import android.support.annotation.NonNull;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.whispersystems.signalservice.api.push.ContactTokenDetails;
|
import org.whispersystems.signalservice.api.push.ContactTokenDetails;
|
||||||
@ -69,10 +69,9 @@ public class TextSecureDirectory {
|
|||||||
this.databaseHelper = new DatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
|
this.databaseHelper = new DatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSecureTextSupported(String e164number) throws NotInDirectoryException {
|
public boolean isSecureTextSupported(@NonNull Address address) throws NotInDirectoryException {
|
||||||
if (e164number == null || e164number.length() == 0) {
|
if (address.isEmail()) return false;
|
||||||
return false;
|
if (address.isGroup()) return true;
|
||||||
}
|
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
@ -80,7 +79,7 @@ public class TextSecureDirectory {
|
|||||||
try {
|
try {
|
||||||
cursor = db.query(TABLE_NAME,
|
cursor = db.query(TABLE_NAME,
|
||||||
new String[]{REGISTERED}, NUMBER + " = ?",
|
new String[]{REGISTERED}, NUMBER + " = ?",
|
||||||
new String[] {e164number}, null, null, null);
|
new String[] {address.serialize()}, null, null, null);
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
return cursor.getInt(0) == 1;
|
return cursor.getInt(0) == 1;
|
||||||
@ -94,55 +93,55 @@ public class TextSecureDirectory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSecureVoiceSupported(String e164number) throws NotInDirectoryException {
|
// public boolean isSecureVoiceSupported(String e164number) throws NotInDirectoryException {
|
||||||
if (TextUtils.isEmpty(e164number)) {
|
// if (TextUtils.isEmpty(e164number)) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
|
// Cursor cursor = null;
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// cursor = db.query(TABLE_NAME,
|
||||||
|
// new String[]{VOICE}, NUMBER + " = ?",
|
||||||
|
// new String[] {e164number}, null, null, null);
|
||||||
|
//
|
||||||
|
// if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
// return cursor.getInt(0) == 1;
|
||||||
|
// } else {
|
||||||
|
// throw new NotInDirectoryException();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// } finally {
|
||||||
|
// if (cursor != null)
|
||||||
|
// cursor.close();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
// public boolean isSecureVideoSupported(String e164number) throws NotInDirectoryException {
|
||||||
Cursor cursor = null;
|
// if (TextUtils.isEmpty(e164number)) {
|
||||||
|
// return false;
|
||||||
try {
|
// }
|
||||||
cursor = db.query(TABLE_NAME,
|
//
|
||||||
new String[]{VOICE}, NUMBER + " = ?",
|
// SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
new String[] {e164number}, null, null, null);
|
// Cursor cursor = null;
|
||||||
|
//
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
// try {
|
||||||
return cursor.getInt(0) == 1;
|
// cursor = db.query(TABLE_NAME,
|
||||||
} else {
|
// new String[]{VIDEO}, NUMBER + " = ?",
|
||||||
throw new NotInDirectoryException();
|
// new String[] {e164number}, null, null, null);
|
||||||
}
|
//
|
||||||
|
// if (cursor != null && cursor.moveToFirst()) {
|
||||||
} finally {
|
// return cursor.getInt(0) == 1;
|
||||||
if (cursor != null)
|
// } else {
|
||||||
cursor.close();
|
// throw new NotInDirectoryException();
|
||||||
}
|
// }
|
||||||
}
|
//
|
||||||
|
// } finally {
|
||||||
public boolean isSecureVideoSupported(String e164number) throws NotInDirectoryException {
|
// if (cursor != null)
|
||||||
if (TextUtils.isEmpty(e164number)) {
|
// cursor.close();
|
||||||
return false;
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
|
||||||
Cursor cursor = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
cursor = db.query(TABLE_NAME,
|
|
||||||
new String[]{VIDEO}, NUMBER + " = ?",
|
|
||||||
new String[] {e164number}, null, null, null);
|
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
|
||||||
return cursor.getInt(0) == 1;
|
|
||||||
} else {
|
|
||||||
throw new NotInDirectoryException();
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (cursor != null)
|
|
||||||
cursor.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRelay(String e164number) {
|
public String getRelay(String e164number) {
|
||||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||||
|
@ -23,6 +23,7 @@ import android.database.MergeCursor;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -30,21 +31,17 @@ import android.util.Log;
|
|||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
|
||||||
import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
import org.thoughtcrime.securesms.database.model.DisplayRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.InvalidMessageException;
|
import org.whispersystems.libsignal.InvalidMessageException;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -57,7 +54,7 @@ public class ThreadDatabase extends Database {
|
|||||||
public static final String ID = "_id";
|
public static final String ID = "_id";
|
||||||
public static final String DATE = "date";
|
public static final String DATE = "date";
|
||||||
public static final String MESSAGE_COUNT = "message_count";
|
public static final String MESSAGE_COUNT = "message_count";
|
||||||
public static final String RECIPIENT_IDS = "recipient_ids";
|
public static final String ADDRESSES = "recipient_ids";
|
||||||
public static final String SNIPPET = "snippet";
|
public static final String SNIPPET = "snippet";
|
||||||
private static final String SNIPPET_CHARSET = "snippet_cs";
|
private static final String SNIPPET_CHARSET = "snippet_cs";
|
||||||
public static final String READ = "read";
|
public static final String READ = "read";
|
||||||
@ -73,7 +70,7 @@ public class ThreadDatabase extends Database {
|
|||||||
|
|
||||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" +
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" +
|
||||||
ID + " INTEGER PRIMARY KEY, " + DATE + " INTEGER DEFAULT 0, " +
|
ID + " INTEGER PRIMARY KEY, " + DATE + " INTEGER DEFAULT 0, " +
|
||||||
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + RECIPIENT_IDS + " TEXT, " + SNIPPET + " TEXT, " +
|
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + ADDRESSES + " TEXT, " + SNIPPET + " TEXT, " +
|
||||||
SNIPPET_CHARSET + " INTEGER DEFAULT 0, " + READ + " INTEGER DEFAULT 1, " +
|
SNIPPET_CHARSET + " INTEGER DEFAULT 0, " + READ + " INTEGER DEFAULT 1, " +
|
||||||
TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
|
||||||
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL, " +
|
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL, " +
|
||||||
@ -82,7 +79,7 @@ public class ThreadDatabase extends Database {
|
|||||||
LAST_SEEN + " INTEGER DEFAULT 0);";
|
LAST_SEEN + " INTEGER DEFAULT 0);";
|
||||||
|
|
||||||
public static final String[] CREATE_INDEXS = {
|
public static final String[] CREATE_INDEXS = {
|
||||||
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + RECIPIENT_IDS + ");",
|
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + ADDRESSES + ");",
|
||||||
"CREATE INDEX IF NOT EXISTS archived_count_index ON " + TABLE_NAME + " (" + ARCHIVED + ", " + MESSAGE_COUNT + ");",
|
"CREATE INDEX IF NOT EXISTS archived_count_index ON " + TABLE_NAME + " (" + ARCHIVED + ", " + MESSAGE_COUNT + ");",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -90,42 +87,12 @@ public class ThreadDatabase extends Database {
|
|||||||
super(context, databaseHelper);
|
super(context, databaseHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long[] getRecipientIds(Recipients recipients) {
|
private long createThreadForRecipients(Address[] addresses, int recipientCount, int distributionType) {
|
||||||
Set<Long> recipientSet = new HashSet<>();
|
|
||||||
List<Recipient> recipientList = recipients.getRecipientsList();
|
|
||||||
|
|
||||||
for (Recipient recipient : recipientList) {
|
|
||||||
recipientSet.add(recipient.getRecipientId());
|
|
||||||
}
|
|
||||||
|
|
||||||
long[] recipientArray = new long[recipientSet.size()];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (Long recipientId : recipientSet) {
|
|
||||||
recipientArray[i++] = recipientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
Arrays.sort(recipientArray);
|
|
||||||
|
|
||||||
return recipientArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getRecipientsAsString(long[] recipientIds) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i=0;i<recipientIds.length;i++) {
|
|
||||||
if (i != 0) sb.append(' ');
|
|
||||||
sb.append(recipientIds[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private long createThreadForRecipients(String recipients, int recipientCount, int distributionType) {
|
|
||||||
ContentValues contentValues = new ContentValues(4);
|
ContentValues contentValues = new ContentValues(4);
|
||||||
long date = System.currentTimeMillis();
|
long date = System.currentTimeMillis();
|
||||||
|
|
||||||
contentValues.put(DATE, date - date % 1000);
|
contentValues.put(DATE, date - date % 1000);
|
||||||
contentValues.put(RECIPIENT_IDS, recipients);
|
contentValues.put(ADDRESSES, Util.join(addresses, " "));
|
||||||
|
|
||||||
if (recipientCount > 1)
|
if (recipientCount > 1)
|
||||||
contentValues.put(TYPE, distributionType);
|
contentValues.put(TYPE, distributionType);
|
||||||
@ -304,29 +271,24 @@ public class ThreadDatabase extends Database {
|
|||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cursor getFilteredConversationList(List<String> filter) {
|
public Cursor getFilteredConversationList(List<Address> filter) {
|
||||||
if (filter == null || filter.size() == 0)
|
if (filter == null || filter.size() == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
List<Long> rawRecipientIds = DatabaseFactory.getAddressDatabase(context).getCanonicalAddressIds(filter);
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
|
List<List<Address>> partitionedAddresses = Util.partition(filter, 900);
|
||||||
|
List<Cursor> cursors = new LinkedList<>();
|
||||||
|
|
||||||
if (rawRecipientIds == null || rawRecipientIds.size() == 0)
|
for (List<Address> addresses : partitionedAddresses) {
|
||||||
return null;
|
String selection = ADDRESSES + " = ?";
|
||||||
|
String[] selectionArgs = new String[addresses.size()];
|
||||||
|
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
for (int i=0;i<addresses.size()-1;i++)
|
||||||
List<List<Long>> partitionedRecipientIds = Util.partition(rawRecipientIds, 900);
|
selection += (" OR " + ADDRESSES + " = ?");
|
||||||
List<Cursor> cursors = new LinkedList<>();
|
|
||||||
|
|
||||||
for (List<Long> recipientIds : partitionedRecipientIds) {
|
|
||||||
String selection = RECIPIENT_IDS + " = ?";
|
|
||||||
String[] selectionArgs = new String[recipientIds.size()];
|
|
||||||
|
|
||||||
for (int i=0;i<recipientIds.size()-1;i++)
|
|
||||||
selection += (" OR " + RECIPIENT_IDS + " = ?");
|
|
||||||
|
|
||||||
int i= 0;
|
int i= 0;
|
||||||
for (long id : recipientIds) {
|
for (Address address : addresses) {
|
||||||
selectionArgs[i++] = String.valueOf(id);
|
selectionArgs[i++] = address.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
cursors.add(db.query(TABLE_NAME, null, selection, selectionArgs, null, null, DATE + " DESC"));
|
cursors.add(db.query(TABLE_NAME, null, selection, selectionArgs, null, null, DATE + " DESC"));
|
||||||
@ -448,11 +410,10 @@ public class ThreadDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getThreadIdIfExistsFor(Recipients recipients) {
|
public long getThreadIdIfExistsFor(Recipients recipients) {
|
||||||
long[] recipientIds = getRecipientIds(recipients);
|
Address[] addresses = recipients.getAddresses();
|
||||||
String recipientsList = getRecipientsAsString(recipientIds);
|
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
String where = RECIPIENT_IDS + " = ?";
|
String where = ADDRESSES + " = ?";
|
||||||
String[] recipientsArg = new String[] {recipientsList};
|
String[] recipientsArg = new String[] {Util.join(addresses, " ")};
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -473,20 +434,20 @@ public class ThreadDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getThreadIdFor(Recipients recipients, int distributionType) {
|
public long getThreadIdFor(Recipients recipients, int distributionType) {
|
||||||
long[] recipientIds = getRecipientIds(recipients);
|
Address[] addresses = recipients.getAddresses();
|
||||||
String recipientsList = getRecipientsAsString(recipientIds);
|
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
String where = ADDRESSES + " = ?";
|
||||||
String where = RECIPIENT_IDS + " = ?";
|
String[] recipientsArg = new String[]{Util.join(addresses, " ")};
|
||||||
String[] recipientsArg = new String[] {recipientsList};
|
Cursor cursor = null;
|
||||||
Cursor cursor = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cursor = db.query(TABLE_NAME, new String[]{ID}, where, recipientsArg, null, null, null);
|
cursor = db.query(TABLE_NAME, new String[]{ID}, where, recipientsArg, null, null, null);
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst())
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
return cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
return cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||||
else
|
} else {
|
||||||
return createThreadForRecipients(recipientsList, recipientIds.length, distributionType);
|
return createThreadForRecipients(addresses, recipients.getRecipientsList().size(), distributionType);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
if (cursor != null)
|
||||||
cursor.close();
|
cursor.close();
|
||||||
@ -501,8 +462,8 @@ public class ThreadDatabase extends Database {
|
|||||||
cursor = db.query(TABLE_NAME, null, ID + " = ?", new String[] {threadId+""}, null, null, null);
|
cursor = db.query(TABLE_NAME, null, ID + " = ?", new String[] {threadId+""}, null, null, null);
|
||||||
|
|
||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
String recipientIds = cursor.getString(cursor.getColumnIndexOrThrow(RECIPIENT_IDS));
|
Address[] addresses = getAddressesFromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESSES)));
|
||||||
return RecipientFactory.getRecipientsForIds(context, recipientIds, false);
|
return RecipientFactory.getRecipientsFor(context, addresses, false);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (cursor != null)
|
if (cursor != null)
|
||||||
@ -566,6 +527,17 @@ public class ThreadDatabase extends Database {
|
|||||||
return thumbnail != null ? thumbnail.getThumbnailUri() : null;
|
return thumbnail != null ? thumbnail.getThumbnailUri() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private @NonNull Address[] getAddressesFromSerialized(String serializedAddresses) {
|
||||||
|
String[] serializedAddressParts = serializedAddresses.split(" ");
|
||||||
|
Address[] addresses = new Address[serializedAddressParts.length];
|
||||||
|
|
||||||
|
for (int i=0;i<serializedAddressParts.length;i++) {
|
||||||
|
addresses[i] = Address.fromSerialized(serializedAddressParts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
public static interface ProgressListener {
|
public static interface ProgressListener {
|
||||||
public void onProgress(int complete, int total);
|
public void onProgress(int complete, int total);
|
||||||
}
|
}
|
||||||
@ -599,9 +571,9 @@ public class ThreadDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ThreadRecord getCurrent() {
|
public ThreadRecord getCurrent() {
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
|
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
|
||||||
String recipientId = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_IDS));
|
Address[] addresses = getAddressesFromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.ADDRESSES)));
|
||||||
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientId, true);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses, true);
|
||||||
|
|
||||||
DisplayRecord.Body body = getPlaintextBody(cursor);
|
DisplayRecord.Body body = getPlaintextBody(cursor);
|
||||||
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
|
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
|
||||||
|
@ -12,6 +12,7 @@ import com.fasterxml.jackson.databind.SerializerProvider;
|
|||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.InvalidKeyException;
|
import org.whispersystems.libsignal.InvalidKeyException;
|
||||||
@ -22,8 +23,8 @@ public class IdentityKeyMismatch {
|
|||||||
|
|
||||||
private static final String TAG = IdentityKeyMismatch.class.getSimpleName();
|
private static final String TAG = IdentityKeyMismatch.class.getSimpleName();
|
||||||
|
|
||||||
@JsonProperty(value = "r")
|
@JsonProperty(value = "a")
|
||||||
private long recipientId;
|
private String address;
|
||||||
|
|
||||||
@JsonProperty(value = "k")
|
@JsonProperty(value = "k")
|
||||||
@JsonSerialize(using = IdentityKeySerializer.class)
|
@JsonSerialize(using = IdentityKeySerializer.class)
|
||||||
@ -32,13 +33,13 @@ public class IdentityKeyMismatch {
|
|||||||
|
|
||||||
public IdentityKeyMismatch() {}
|
public IdentityKeyMismatch() {}
|
||||||
|
|
||||||
public IdentityKeyMismatch(long recipientId, IdentityKey identityKey) {
|
public IdentityKeyMismatch(Address address, IdentityKey identityKey) {
|
||||||
this.recipientId = recipientId;
|
this.address = address.serialize();
|
||||||
this.identityKey = identityKey;
|
this.identityKey = identityKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRecipientId() {
|
public Address getAddress() {
|
||||||
return recipientId;
|
return Address.fromSerialized(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdentityKey getIdentityKey() {
|
public IdentityKey getIdentityKey() {
|
||||||
@ -52,12 +53,12 @@ public class IdentityKeyMismatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IdentityKeyMismatch that = (IdentityKeyMismatch)other;
|
IdentityKeyMismatch that = (IdentityKeyMismatch)other;
|
||||||
return that.recipientId == this.recipientId && that.identityKey.equals(this.identityKey);
|
return that.address.equals(this.address) && that.identityKey.equals(this.identityKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return (int)recipientId ^ identityKey.hashCode();
|
return address.hashCode() ^ identityKey.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class IdentityKeySerializer extends JsonSerializer<IdentityKey> {
|
private static class IdentityKeySerializer extends JsonSerializer<IdentityKey> {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.thoughtcrime.securesms.database.documents;
|
package org.thoughtcrime.securesms.database.documents;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -25,6 +26,7 @@ public class IdentityKeyMismatchList implements Document<IdentityKeyMismatch> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@JsonIgnore
|
||||||
public List<IdentityKeyMismatch> getList() {
|
public List<IdentityKeyMismatch> getList() {
|
||||||
return mismatches;
|
return mismatches;
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,21 @@ package org.thoughtcrime.securesms.database.documents;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
|
|
||||||
public class NetworkFailure {
|
public class NetworkFailure {
|
||||||
|
|
||||||
@JsonProperty(value = "r")
|
@JsonProperty(value = "a")
|
||||||
private long recipientId;
|
private String address;
|
||||||
|
|
||||||
public NetworkFailure(long recipientId) {
|
public NetworkFailure(Address address) {
|
||||||
this.recipientId = recipientId;
|
this.address = address.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public NetworkFailure() {}
|
public NetworkFailure() {}
|
||||||
|
|
||||||
public long getRecipientId() {
|
public Address getAddress() {
|
||||||
return recipientId;
|
return Address.fromSerialized(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -22,11 +24,11 @@ public class NetworkFailure {
|
|||||||
if (other == null || !(other instanceof NetworkFailure)) return false;
|
if (other == null || !(other instanceof NetworkFailure)) return false;
|
||||||
|
|
||||||
NetworkFailure that = (NetworkFailure)other;
|
NetworkFailure that = (NetworkFailure)other;
|
||||||
return this.recipientId == that.recipientId;
|
return this.address.equals(that.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return (int)recipientId;
|
return address.hashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ public class IdentityRecordList {
|
|||||||
|
|
||||||
for (IdentityRecord identityRecord : identityRecords) {
|
for (IdentityRecord identityRecord : identityRecords) {
|
||||||
if (isUntrusted(identityRecord)) {
|
if (isUntrusted(identityRecord)) {
|
||||||
untrusted.add(RecipientFactory.getRecipientForId(context, identityRecord.getRecipientId(), false));
|
untrusted.add(RecipientFactory.getRecipientFor(context, identityRecord.getAddress(), false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ public class IdentityRecordList {
|
|||||||
|
|
||||||
for (IdentityRecord identityRecord : identityRecords) {
|
for (IdentityRecord identityRecord : identityRecords) {
|
||||||
if (identityRecord.getVerifiedStatus() == VerifiedStatus.UNVERIFIED) {
|
if (identityRecord.getVerifiedStatus() == VerifiedStatus.UNVERIFIED) {
|
||||||
unverified.add(RecipientFactory.getRecipientForId(context, identityRecord.getRecipientId(), false));
|
unverified.add(RecipientFactory.getRecipientFor(context, identityRecord.getAddress(), false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import android.database.MatrixCursor;
|
|||||||
import android.database.MergeCursor;
|
import android.database.MergeCursor;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
|
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
|
||||||
@ -41,7 +42,7 @@ public class ConversationListLoader extends AbstractCursorLoader {
|
|||||||
if (archivedCount > 0) {
|
if (archivedCount > 0) {
|
||||||
MatrixCursor switchToArchiveCursor = new MatrixCursor(new String[] {
|
MatrixCursor switchToArchiveCursor = new MatrixCursor(new String[] {
|
||||||
ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
|
ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
|
||||||
ThreadDatabase.RECIPIENT_IDS, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
|
ThreadDatabase.ADDRESSES, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
|
||||||
ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
|
ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
|
||||||
ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.RECEIPT_COUNT,
|
ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.RECEIPT_COUNT,
|
||||||
ThreadDatabase.EXPIRES_IN, ThreadDatabase.LAST_SEEN}, 1);
|
ThreadDatabase.EXPIRES_IN, ThreadDatabase.LAST_SEEN}, 1);
|
||||||
@ -62,6 +63,12 @@ public class ConversationListLoader extends AbstractCursorLoader {
|
|||||||
|
|
||||||
private Cursor getFilteredConversationList(String filter) {
|
private Cursor getFilteredConversationList(String filter) {
|
||||||
List<String> numbers = ContactAccessor.getInstance().getNumbersForThreadSearchFilter(context, filter);
|
List<String> numbers = ContactAccessor.getInstance().getNumbersForThreadSearchFilter(context, filter);
|
||||||
return DatabaseFactory.getThreadDatabase(context).getFilteredConversationList(numbers);
|
List<Address> addresses = new LinkedList<>();
|
||||||
|
|
||||||
|
for (String number : numbers) {
|
||||||
|
addresses.add(Address.fromExternal(context, number));
|
||||||
|
}
|
||||||
|
|
||||||
|
return DatabaseFactory.getThreadDatabase(context).getFilteredConversationList(addresses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,6 @@ public class WebRtcViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[State: " + state + ", recipient: " + recipient.getNumber() + ", identity: " + identityKey + ", remoteVideo: " + remoteVideoEnabled + ", localVideo: " + localVideoEnabled + "]";
|
return "[State: " + state + ", recipient: " + recipient.getAddress() + ", identity: " + identityKey + ", remoteVideo: " + remoteVideoEnabled + ", localVideo: " + localVideoEnabled + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import com.google.protobuf.ByteString;
|
|||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
import org.thoughtcrime.securesms.attachments.UriAttachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
@ -24,16 +25,17 @@ import org.thoughtcrime.securesms.util.BitmapUtil;
|
|||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class GroupManager {
|
public class GroupManager {
|
||||||
|
|
||||||
public static @NonNull GroupActionResult createGroup(@NonNull Context context,
|
public static @NonNull GroupActionResult createGroup(@NonNull Context context,
|
||||||
@NonNull MasterSecret masterSecret,
|
@NonNull MasterSecret masterSecret,
|
||||||
@NonNull Set<Recipient> members,
|
@NonNull Set<Recipient> members,
|
||||||
@ -41,23 +43,23 @@ public class GroupManager {
|
|||||||
@Nullable String name)
|
@Nullable String name)
|
||||||
throws InvalidNumberException
|
throws InvalidNumberException
|
||||||
{
|
{
|
||||||
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
|
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
|
||||||
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
final byte[] groupId = groupDatabase.allocateGroupId();
|
final byte[] groupId = groupDatabase.allocateGroupId();
|
||||||
final Set<String> memberE164Numbers = getE164Numbers(context, members);
|
final Set<Address> memberAddresses = getMemberAddresses(context, members);
|
||||||
|
|
||||||
memberE164Numbers.add(TextSecurePreferences.getLocalNumber(context));
|
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
|
||||||
groupDatabase.create(groupId, name, new LinkedList<>(memberE164Numbers), null, null);
|
groupDatabase.create(groupId, name, new LinkedList<>(memberAddresses), null, null);
|
||||||
groupDatabase.updateAvatar(groupId, avatarBytes);
|
groupDatabase.updateAvatar(groupId, avatarBytes);
|
||||||
return sendGroupUpdate(context, masterSecret, groupId, memberE164Numbers, name, avatarBytes);
|
return sendGroupUpdate(context, masterSecret, groupId, memberAddresses, name, avatarBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> getE164Numbers(Context context, Collection<Recipient> recipients)
|
private static Set<Address> getMemberAddresses(Context context, Collection<Recipient> recipients)
|
||||||
throws InvalidNumberException
|
throws InvalidNumberException
|
||||||
{
|
{
|
||||||
final Set<String> results = new HashSet<>();
|
final Set<Address> results = new HashSet<>();
|
||||||
for (Recipient recipient : recipients) {
|
for (Recipient recipient : recipients) {
|
||||||
results.add(Util.canonicalizeNumber(context, recipient.getNumber()));
|
results.add(recipient.getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
@ -71,33 +73,39 @@ public class GroupManager {
|
|||||||
@Nullable String name)
|
@Nullable String name)
|
||||||
throws InvalidNumberException
|
throws InvalidNumberException
|
||||||
{
|
{
|
||||||
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
final Set<String> memberE164Numbers = getE164Numbers(context, members);
|
final Set<Address> memberAddresses = getMemberAddresses(context, members);
|
||||||
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
|
final byte[] avatarBytes = BitmapUtil.toByteArray(avatar);
|
||||||
|
|
||||||
memberE164Numbers.add(TextSecurePreferences.getLocalNumber(context));
|
memberAddresses.add(Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)));
|
||||||
groupDatabase.updateMembers(groupId, new LinkedList<>(memberE164Numbers));
|
groupDatabase.updateMembers(groupId, new LinkedList<>(memberAddresses));
|
||||||
groupDatabase.updateTitle(groupId, name);
|
groupDatabase.updateTitle(groupId, name);
|
||||||
groupDatabase.updateAvatar(groupId, avatarBytes);
|
groupDatabase.updateAvatar(groupId, avatarBytes);
|
||||||
|
|
||||||
return sendGroupUpdate(context, masterSecret, groupId, memberE164Numbers, name, avatarBytes);
|
return sendGroupUpdate(context, masterSecret, groupId, memberAddresses, name, avatarBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
|
private static GroupActionResult sendGroupUpdate(@NonNull Context context,
|
||||||
@NonNull MasterSecret masterSecret,
|
@NonNull MasterSecret masterSecret,
|
||||||
@NonNull byte[] groupId,
|
@NonNull byte[] groupId,
|
||||||
@NonNull Set<String> e164numbers,
|
@NonNull Set<Address> members,
|
||||||
@Nullable String groupName,
|
@Nullable String groupName,
|
||||||
@Nullable byte[] avatar)
|
@Nullable byte[] avatar)
|
||||||
{
|
{
|
||||||
Attachment avatarAttachment = null;
|
Attachment avatarAttachment = null;
|
||||||
String groupRecipientId = GroupUtil.getEncodedId(groupId);
|
Address groupAddress = Address.fromSerialized(GroupUtil.getEncodedId(groupId));
|
||||||
Recipients groupRecipient = RecipientFactory.getRecipientsFromString(context, groupRecipientId, false);
|
Recipients groupRecipient = RecipientFactory.getRecipientsFor(context, new Address[]{groupAddress}, false);
|
||||||
|
|
||||||
|
List<String> numbers = new LinkedList<>();
|
||||||
|
|
||||||
|
for (Address member : members) {
|
||||||
|
numbers.add(member.serialize());
|
||||||
|
}
|
||||||
|
|
||||||
GroupContext.Builder groupContextBuilder = GroupContext.newBuilder()
|
GroupContext.Builder groupContextBuilder = GroupContext.newBuilder()
|
||||||
.setId(ByteString.copyFrom(groupId))
|
.setId(ByteString.copyFrom(groupId))
|
||||||
.setType(GroupContext.Type.UPDATE)
|
.setType(GroupContext.Type.UPDATE)
|
||||||
.addAllMembers(e164numbers);
|
.addAllMembers(numbers);
|
||||||
if (groupName != null) groupContextBuilder.setName(groupName);
|
if (groupName != null) groupContextBuilder.setName(groupName);
|
||||||
GroupContext groupContext = groupContextBuilder.build();
|
GroupContext groupContext = groupContextBuilder.build();
|
||||||
|
|
||||||
|
@ -10,13 +10,15 @@ import com.google.protobuf.ByteString;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
||||||
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
|
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
|
||||||
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
@ -37,8 +39,6 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer;
|
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.AttachmentPointer;
|
||||||
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||||
@ -88,9 +88,16 @@ public class GroupMessageProcessor {
|
|||||||
GroupContext.Builder builder = createGroupContext(group);
|
GroupContext.Builder builder = createGroupContext(group);
|
||||||
builder.setType(GroupContext.Type.UPDATE);
|
builder.setType(GroupContext.Type.UPDATE);
|
||||||
|
|
||||||
SignalServiceAttachment avatar = group.getAvatar().orNull();
|
SignalServiceAttachment avatar = group.getAvatar().orNull();
|
||||||
|
List<Address> members = group.getMembers().isPresent() ? new LinkedList<Address>() : null;
|
||||||
|
|
||||||
database.create(id, group.getName().orNull(), group.getMembers().orNull(),
|
if (group.getMembers().isPresent()) {
|
||||||
|
for (String member : group.getMembers().get()) {
|
||||||
|
members.add(Address.fromExternal(context, member));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
database.create(id, group.getName().orNull(), members,
|
||||||
avatar != null && avatar.isPointer() ? avatar.asPointer() : null,
|
avatar != null && avatar.isPointer() ? avatar.asPointer() : null,
|
||||||
envelope.getRelay());
|
envelope.getRelay());
|
||||||
|
|
||||||
@ -108,24 +115,32 @@ public class GroupMessageProcessor {
|
|||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
byte[] id = group.getGroupId();
|
byte[] id = group.getGroupId();
|
||||||
|
|
||||||
Set<String> recordMembers = new HashSet<>(groupRecord.getMembers());
|
Set<Address> recordMembers = new HashSet<>(groupRecord.getMembers());
|
||||||
Set<String> messageMembers = new HashSet<>(group.getMembers().get());
|
Set<Address> messageMembers = new HashSet<>();
|
||||||
|
|
||||||
Set<String> addedMembers = new HashSet<>(messageMembers);
|
for (String messageMember : group.getMembers().get()) {
|
||||||
|
messageMembers.add(Address.fromExternal(context, messageMember));
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Address> addedMembers = new HashSet<>(messageMembers);
|
||||||
addedMembers.removeAll(recordMembers);
|
addedMembers.removeAll(recordMembers);
|
||||||
|
|
||||||
Set<String> missingMembers = new HashSet<>(recordMembers);
|
Set<Address> missingMembers = new HashSet<>(recordMembers);
|
||||||
missingMembers.removeAll(messageMembers);
|
missingMembers.removeAll(messageMembers);
|
||||||
|
|
||||||
GroupContext.Builder builder = createGroupContext(group);
|
GroupContext.Builder builder = createGroupContext(group);
|
||||||
builder.setType(GroupContext.Type.UPDATE);
|
builder.setType(GroupContext.Type.UPDATE);
|
||||||
|
|
||||||
if (addedMembers.size() > 0) {
|
if (addedMembers.size() > 0) {
|
||||||
Set<String> unionMembers = new HashSet<>(recordMembers);
|
Set<Address> unionMembers = new HashSet<>(recordMembers);
|
||||||
unionMembers.addAll(messageMembers);
|
unionMembers.addAll(messageMembers);
|
||||||
database.updateMembers(id, new LinkedList<>(unionMembers));
|
database.updateMembers(id, new LinkedList<>(unionMembers));
|
||||||
|
|
||||||
builder.clearMembers().addAllMembers(addedMembers);
|
builder.clearMembers();
|
||||||
|
|
||||||
|
for (Address addedMember : addedMembers) {
|
||||||
|
builder.addMembers(addedMember.serialize());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
builder.clearMembers();
|
builder.clearMembers();
|
||||||
}
|
}
|
||||||
@ -171,13 +186,13 @@ public class GroupMessageProcessor {
|
|||||||
{
|
{
|
||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
byte[] id = group.getGroupId();
|
byte[] id = group.getGroupId();
|
||||||
List<String> members = record.getMembers();
|
List<Address> members = record.getMembers();
|
||||||
|
|
||||||
GroupContext.Builder builder = createGroupContext(group);
|
GroupContext.Builder builder = createGroupContext(group);
|
||||||
builder.setType(GroupContext.Type.QUIT);
|
builder.setType(GroupContext.Type.QUIT);
|
||||||
|
|
||||||
if (members.contains(envelope.getSource())) {
|
if (members.contains(Address.fromExternal(context, envelope.getSource()))) {
|
||||||
database.remove(id, envelope.getSource());
|
database.remove(id, Address.fromExternal(context, envelope.getSource()));
|
||||||
if (outgoing) database.setActive(id, false);
|
if (outgoing) database.setActive(id, false);
|
||||||
|
|
||||||
return storeMessage(context, masterSecret, envelope, group, builder.build(), outgoing);
|
return storeMessage(context, masterSecret, envelope, group, builder.build(), outgoing);
|
||||||
@ -202,7 +217,8 @@ public class GroupMessageProcessor {
|
|||||||
try {
|
try {
|
||||||
if (outgoing) {
|
if (outgoing) {
|
||||||
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(group.getGroupId()), false);
|
Address addres = Address.fromExternal(context, GroupUtil.getEncodedId(group.getGroupId()));
|
||||||
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {addres}, false);
|
||||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipients, storage, null, envelope.getTimestamp(), 0);
|
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipients, storage, null, envelope.getTimestamp(), 0);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||||
long messageId = mmsDatabase.insertMessageOutbox(masterSecret, outgoingMessage, threadId, false, null);
|
long messageId = mmsDatabase.insertMessageOutbox(masterSecret, outgoingMessage, threadId, false, null);
|
||||||
@ -213,7 +229,7 @@ public class GroupMessageProcessor {
|
|||||||
} else {
|
} else {
|
||||||
EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context);
|
EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||||
String body = Base64.encodeBytes(storage.toByteArray());
|
String body = Base64.encodeBytes(storage.toByteArray());
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(), envelope.getTimestamp(), body, Optional.of(group), 0);
|
IncomingTextMessage incoming = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()), envelope.getSourceDevice(), envelope.getTimestamp(), body, Optional.of(group), 0);
|
||||||
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
|
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
|
||||||
|
|
||||||
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(masterSecret, groupMessage);
|
Optional<InsertResult> insertResult = smsDatabase.insertMessageInbox(masterSecret, groupMessage);
|
||||||
|
@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
|||||||
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
import org.thoughtcrime.securesms.mms.ApnUnavailableException;
|
||||||
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
|
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
|
||||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||||
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
import org.thoughtcrime.securesms.mms.MmsRadioException;
|
||||||
import org.thoughtcrime.securesms.mms.PartParser;
|
import org.thoughtcrime.securesms.mms.PartParser;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
@ -42,8 +43,6 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
|
||||||
|
|
||||||
public class MmsDownloadJob extends MasterSecretJob {
|
public class MmsDownloadJob extends MasterSecretJob {
|
||||||
|
|
||||||
private static final String TAG = MmsDownloadJob.class.getSimpleName();
|
private static final String TAG = MmsDownloadJob.class.getSimpleName();
|
||||||
@ -206,7 +205,7 @@ public class MmsDownloadJob extends MasterSecretJob {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
IncomingMediaMessage message = new IncomingMediaMessage(from, to, cc, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false);
|
IncomingMediaMessage message = new IncomingMediaMessage(context, from, to, cc, body, retrieved.getDate() * 1000L, attachments, subscriptionId, 0, false);
|
||||||
Optional<InsertResult> insertResult = database.insertMessageInbox(new MasterSecretUnion(masterSecret),
|
Optional<InsertResult> insertResult = database.insertMessageInbox(new MasterSecretUnion(masterSecret),
|
||||||
message, contentLocation, threadId);
|
message, contentLocation, threadId);
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import com.google.android.mms.pdu_alt.PduHeaders;
|
|||||||
import com.google.android.mms.pdu_alt.PduParser;
|
import com.google.android.mms.pdu_alt.PduParser;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
@ -85,7 +86,7 @@ public class MmsReceiveJob extends ContextJob {
|
|||||||
|
|
||||||
private boolean isBlocked(GenericPdu pdu) {
|
private boolean isBlocked(GenericPdu pdu) {
|
||||||
if (pdu.getFrom() != null && pdu.getFrom().getTextString() != null) {
|
if (pdu.getFrom() != null && pdu.getFrom().getTextString() != null) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, Util.toIsoString(pdu.getFrom().getTextString()), false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, Util.toIsoString(pdu.getFrom().getTextString()))}, false);
|
||||||
return recipients.isBlocked();
|
return recipients.isBlocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,12 +21,14 @@ import com.klinker.android.send_message.Utils;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||||
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
|
import org.thoughtcrime.securesms.mms.CompatMmsConnection;
|
||||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||||
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.MmsSendResult;
|
import org.thoughtcrime.securesms.mms.MmsSendResult;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||||
@ -45,8 +47,6 @@ import java.io.IOException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
|
||||||
|
|
||||||
public class MmsSendJob extends SendJob {
|
public class MmsSendJob extends SendJob {
|
||||||
|
|
||||||
private static final long serialVersionUID = 0L;
|
private static final long serialVersionUID = 0L;
|
||||||
@ -171,16 +171,16 @@ public class MmsSendJob extends SendJob {
|
|||||||
{
|
{
|
||||||
SendReq req = new SendReq();
|
SendReq req = new SendReq();
|
||||||
String lineNumber = Utils.getMyPhoneNumber(context);
|
String lineNumber = Utils.getMyPhoneNumber(context);
|
||||||
List<String> numbers = message.getRecipients().toNumberStringList(true);
|
Address[] numbers = message.getRecipients().getAddresses();
|
||||||
MediaConstraints mediaConstraints = MediaConstraints.getMmsMediaConstraints(message.getSubscriptionId());
|
MediaConstraints mediaConstraints = MediaConstraints.getMmsMediaConstraints(message.getSubscriptionId());
|
||||||
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
|
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(lineNumber)) {
|
if (!TextUtils.isEmpty(lineNumber)) {
|
||||||
req.setFrom(new EncodedStringValue(lineNumber));
|
req.setFrom(new EncodedStringValue(lineNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String recipient : numbers) {
|
for (Address recipient : numbers) {
|
||||||
req.addTo(new EncodedStringValue(recipient));
|
req.addTo(new EncodedStringValue(recipient.serialize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
req.setDate(System.currentTimeMillis() / 1000);
|
req.setDate(System.currentTimeMillis() / 1000);
|
||||||
|
@ -10,16 +10,13 @@ import org.thoughtcrime.securesms.dependencies.InjectableType;
|
|||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||||
import org.whispersystems.libsignal.logging.Log;
|
|
||||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.BlockedListMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.BlockedListMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -57,11 +54,7 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
|||||||
|
|
||||||
while ((recipients = reader.getNext()) != null) {
|
while ((recipients = reader.getNext()) != null) {
|
||||||
if (recipients.isSingleRecipient()) {
|
if (recipients.isSingleRecipient()) {
|
||||||
try {
|
blocked.add(recipients.getPrimaryRecipient().getAddress().toPhoneString());
|
||||||
blocked.add(Util.canonicalizeNumber(context, recipients.getPrimaryRecipient().getNumber()));
|
|
||||||
} catch (InvalidNumberException e) {
|
|
||||||
Log.w(TAG, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,13 +6,14 @@ import android.database.Cursor;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.provider.ContactsContract;
|
import android.provider.ContactsContract;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
||||||
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
|
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
@ -20,9 +21,7 @@ import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalM
|
|||||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
@ -50,19 +49,19 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
public class MultiDeviceContactUpdateJob extends MasterSecretJob implements InjectableType {
|
public class MultiDeviceContactUpdateJob extends MasterSecretJob implements InjectableType {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 2L;
|
||||||
|
|
||||||
private static final String TAG = MultiDeviceContactUpdateJob.class.getSimpleName();
|
private static final String TAG = MultiDeviceContactUpdateJob.class.getSimpleName();
|
||||||
|
|
||||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||||
|
|
||||||
private final long recipientId;
|
private final @Nullable String address;
|
||||||
|
|
||||||
public MultiDeviceContactUpdateJob(Context context) {
|
public MultiDeviceContactUpdateJob(Context context) {
|
||||||
this(context, -1);
|
this(context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MultiDeviceContactUpdateJob(Context context, long recipientId) {
|
public MultiDeviceContactUpdateJob(Context context, Address address) {
|
||||||
super(context, JobParameters.newBuilder()
|
super(context, JobParameters.newBuilder()
|
||||||
.withRequirement(new NetworkRequirement(context))
|
.withRequirement(new NetworkRequirement(context))
|
||||||
.withRequirement(new MasterSecretRequirement(context))
|
.withRequirement(new MasterSecretRequirement(context))
|
||||||
@ -70,7 +69,7 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
|||||||
.withPersistence()
|
.withPersistence()
|
||||||
.create());
|
.create());
|
||||||
|
|
||||||
this.recipientId = recipientId;
|
this.address = address.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,11 +81,11 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recipientId <= 0) generateFullContactUpdate();
|
if (address == null) generateFullContactUpdate();
|
||||||
else generateSingleContactUpdate(recipientId);
|
else generateSingleContactUpdate(Address.fromSerialized(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateSingleContactUpdate(long recipientId)
|
private void generateSingleContactUpdate(@NonNull Address address)
|
||||||
throws IOException, UntrustedIdentityException, NetworkException
|
throws IOException, UntrustedIdentityException, NetworkException
|
||||||
{
|
{
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||||
@ -94,11 +93,11 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile));
|
DeviceContactsOutputStream out = new DeviceContactsOutputStream(new FileOutputStream(contactDataFile));
|
||||||
Recipient recipient = RecipientFactory.getRecipientForId(context, recipientId, false);
|
Recipient recipient = RecipientFactory.getRecipientFor(context, address, false);
|
||||||
Optional<IdentityDatabase.IdentityRecord> identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipientId);
|
Optional<IdentityDatabase.IdentityRecord> identityRecord = DatabaseFactory.getIdentityDatabase(context).getIdentity(address);
|
||||||
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
|
Optional<VerifiedMessage> verifiedMessage = getVerifiedMessage(recipient, identityRecord);
|
||||||
|
|
||||||
out.write(new DeviceContact(Util.canonicalizeNumber(context, recipient.getNumber()),
|
out.write(new DeviceContact(address.toPhoneString(),
|
||||||
Optional.fromNullable(recipient.getName()),
|
Optional.fromNullable(recipient.getName()),
|
||||||
getAvatar(recipient.getContactUri()),
|
getAvatar(recipient.getContactUri()),
|
||||||
Optional.fromNullable(recipient.getColor().serialize()),
|
Optional.fromNullable(recipient.getColor().serialize()),
|
||||||
@ -126,14 +125,14 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
|||||||
|
|
||||||
for (ContactData contactData : contacts) {
|
for (ContactData contactData : contacts) {
|
||||||
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactData.id));
|
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(contactData.id));
|
||||||
String number = Util.canonicalizeNumber(context, contactData.numbers.get(0).number);
|
Address address = Address.fromExternal(context, contactData.numbers.get(0).number);
|
||||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, number, true).getPrimaryRecipient();
|
Recipient recipient = RecipientFactory.getRecipientFor(context, address, false);
|
||||||
Optional<IdentityDatabase.IdentityRecord> identity = DatabaseFactory.getIdentityDatabase(context).getIdentity(recipient.getRecipientId());
|
Optional<IdentityDatabase.IdentityRecord> identity = DatabaseFactory.getIdentityDatabase(context).getIdentity(address);
|
||||||
Optional<VerifiedMessage> verified = getVerifiedMessage(recipient, identity);
|
Optional<VerifiedMessage> verified = getVerifiedMessage(recipient, identity);
|
||||||
Optional<String> name = Optional.fromNullable(contactData.name);
|
Optional<String> name = Optional.fromNullable(contactData.name);
|
||||||
Optional<String> color = getColor(number);
|
Optional<String> color = Optional.of(recipient.getColor().serialize());
|
||||||
|
|
||||||
out.write(new DeviceContact(number, name, getAvatar(contactUri), color, verified));
|
out.write(new DeviceContact(address.toPhoneString(), name, getAvatar(contactUri), color, verified));
|
||||||
}
|
}
|
||||||
|
|
||||||
out.close();
|
out.close();
|
||||||
@ -161,15 +160,6 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<String> getColor(String number) {
|
|
||||||
if (!TextUtils.isEmpty(number)) {
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, number, false);
|
|
||||||
return Optional.of(recipients.getColor().serialize());
|
|
||||||
} else {
|
|
||||||
return Optional.absent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendUpdate(SignalServiceMessageSender messageSender, File contactsFile, boolean complete)
|
private void sendUpdate(SignalServiceMessageSender messageSender, File contactsFile, boolean complete)
|
||||||
throws IOException, UntrustedIdentityException, NetworkException
|
throws IOException, UntrustedIdentityException, NetworkException
|
||||||
{
|
{
|
||||||
@ -245,7 +235,7 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
|||||||
private Optional<VerifiedMessage> getVerifiedMessage(Recipient recipient, Optional<IdentityDatabase.IdentityRecord> identity) throws InvalidNumberException {
|
private Optional<VerifiedMessage> getVerifiedMessage(Recipient recipient, Optional<IdentityDatabase.IdentityRecord> identity) throws InvalidNumberException {
|
||||||
if (!identity.isPresent()) return Optional.absent();
|
if (!identity.isPresent()) return Optional.absent();
|
||||||
|
|
||||||
String destination = Util.canonicalizeNumber(context, recipient.getNumber());
|
String destination = recipient.getAddress().toPhoneString();
|
||||||
IdentityKey identityKey = identity.get().getIdentityKey();
|
IdentityKey identityKey = identity.get().getIdentityKey();
|
||||||
|
|
||||||
VerifiedMessage.VerifiedState state;
|
VerifiedMessage.VerifiedState state;
|
||||||
|
@ -5,6 +5,7 @@ import android.support.annotation.Nullable;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
@ -27,6 +28,8 @@ import java.io.File;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@ -61,8 +64,14 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject
|
|||||||
reader = DatabaseFactory.getGroupDatabase(context).getGroups();
|
reader = DatabaseFactory.getGroupDatabase(context).getGroups();
|
||||||
|
|
||||||
while ((record = reader.getNext()) != null) {
|
while ((record = reader.getNext()) != null) {
|
||||||
|
List<String> members = new LinkedList<>();
|
||||||
|
|
||||||
|
for (Address member : record.getMembers()) {
|
||||||
|
members.add(member.serialize());
|
||||||
|
}
|
||||||
|
|
||||||
out.write(new DeviceGroup(record.getId(), Optional.fromNullable(record.getTitle()),
|
out.write(new DeviceGroup(record.getId(), Optional.fromNullable(record.getTitle()),
|
||||||
record.getMembers(), getAvatar(record.getAvatar()),
|
members, getAvatar(record.getAvatar()),
|
||||||
record.isActive()));
|
record.isActive()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
|||||||
this.messageIds = new LinkedList<>();
|
this.messageIds = new LinkedList<>();
|
||||||
|
|
||||||
for (SyncMessageId messageId : messageIds) {
|
for (SyncMessageId messageId : messageIds) {
|
||||||
this.messageIds.add(new SerializableSyncMessageId(messageId.getAddress(), messageId.getTimetamp()));
|
this.messageIds.add(new SerializableSyncMessageId(messageId.getAddress().toPhoneString(), messageId.getTimetamp()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,11 +4,11 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
@ -18,7 +18,6 @@ import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
|||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -38,14 +37,14 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab
|
|||||||
private final VerifiedStatus verifiedStatus;
|
private final VerifiedStatus verifiedStatus;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
|
|
||||||
public MultiDeviceVerifiedUpdateJob(Context context, String destination, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
|
public MultiDeviceVerifiedUpdateJob(Context context, Address destination, IdentityKey identityKey, VerifiedStatus verifiedStatus) {
|
||||||
super(context, JobParameters.newBuilder()
|
super(context, JobParameters.newBuilder()
|
||||||
.withRequirement(new NetworkRequirement(context))
|
.withRequirement(new NetworkRequirement(context))
|
||||||
.withPersistence()
|
.withPersistence()
|
||||||
.withGroupId("__MULTI_DEVICE_VERIFIED_UPDATE__")
|
.withGroupId("__MULTI_DEVICE_VERIFIED_UPDATE__")
|
||||||
.create());
|
.create());
|
||||||
|
|
||||||
this.destination = destination;
|
this.destination = destination.serialize();
|
||||||
this.identityKey = identityKey.serialize();
|
this.identityKey = identityKey.serialize();
|
||||||
this.verifiedStatus = verifiedStatus;
|
this.verifiedStatus = verifiedStatus;
|
||||||
this.timestamp = System.currentTimeMillis();
|
this.timestamp = System.currentTimeMillis();
|
||||||
@ -64,13 +63,13 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String canonicalDestination = Util.canonicalizeNumber(context, destination);
|
Address canonicalDestination = Address.fromSerialized(destination);
|
||||||
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
|
VerifiedMessage.VerifiedState verifiedState = getVerifiedState(verifiedStatus);
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||||
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination, new IdentityKey(identityKey, 0), verifiedState, timestamp);
|
VerifiedMessage verifiedMessage = new VerifiedMessage(canonicalDestination.toPhoneString(), new IdentityKey(identityKey, 0), verifiedState, timestamp);
|
||||||
|
|
||||||
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
|
messageSender.sendMessage(SignalServiceSyncMessage.forVerified(verifiedMessage));
|
||||||
} catch (InvalidNumberException | InvalidKeyException e) {
|
} catch (InvalidKeyException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
|||||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
import org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl;
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
@ -79,6 +80,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptM
|
|||||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||||
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -92,11 +94,11 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
private final long messageId;
|
private final long messageId;
|
||||||
private final long smsMessageId;
|
private final long smsMessageId;
|
||||||
|
|
||||||
public PushDecryptJob(Context context, long pushMessageId, String sender) {
|
public PushDecryptJob(Context context, long pushMessageId) {
|
||||||
this(context, pushMessageId, -1, sender);
|
this(context, pushMessageId, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PushDecryptJob(Context context, long pushMessageId, long smsMessageId, String sender) {
|
public PushDecryptJob(Context context, long pushMessageId, long smsMessageId) {
|
||||||
super(context, JobParameters.newBuilder()
|
super(context, JobParameters.newBuilder()
|
||||||
.withPersistence()
|
.withPersistence()
|
||||||
.withGroupId("__PUSH_DECRYPT_JOB__")
|
.withGroupId("__PUSH_DECRYPT_JOB__")
|
||||||
@ -221,7 +223,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||||
intent.setAction(WebRtcCallService.ACTION_INCOMING_CALL);
|
intent.setAction(WebRtcCallService.ACTION_INCOMING_CALL);
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_NUMBER, envelope.getSource());
|
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription());
|
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription());
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_TIMESTAMP, envelope.getTimestamp());
|
intent.putExtra(WebRtcCallService.EXTRA_TIMESTAMP, envelope.getTimestamp());
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
@ -235,7 +237,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||||
intent.setAction(WebRtcCallService.ACTION_RESPONSE_MESSAGE);
|
intent.setAction(WebRtcCallService.ACTION_RESPONSE_MESSAGE);
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_NUMBER, envelope.getSource());
|
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription());
|
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_DESCRIPTION, message.getDescription());
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
@ -248,7 +250,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||||
intent.setAction(WebRtcCallService.ACTION_ICE_MESSAGE);
|
intent.setAction(WebRtcCallService.ACTION_ICE_MESSAGE);
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_NUMBER, envelope.getSource());
|
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP, message.getSdp());
|
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP, message.getSdp());
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_MID, message.getSdpMid());
|
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_MID, message.getSdpMid());
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_LINE_INDEX, message.getSdpMLineIndex());
|
intent.putExtra(WebRtcCallService.EXTRA_ICE_SDP_LINE_INDEX, message.getSdpMLineIndex());
|
||||||
@ -267,7 +269,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||||
intent.setAction(WebRtcCallService.ACTION_REMOTE_HANGUP);
|
intent.setAction(WebRtcCallService.ACTION_REMOTE_HANGUP);
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_NUMBER, envelope.getSource());
|
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -278,7 +280,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
Intent intent = new Intent(context, WebRtcCallService.class);
|
Intent intent = new Intent(context, WebRtcCallService.class);
|
||||||
intent.setAction(WebRtcCallService.ACTION_REMOTE_BUSY);
|
intent.setAction(WebRtcCallService.ACTION_REMOTE_BUSY);
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
intent.putExtra(WebRtcCallService.EXTRA_CALL_ID, message.getId());
|
||||||
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_NUMBER, envelope.getSource());
|
intent.putExtra(WebRtcCallService.EXTRA_REMOTE_ADDRESS, Address.fromExternal(context, envelope.getSource()));
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +290,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
@NonNull Optional<Long> smsMessageId)
|
@NonNull Optional<Long> smsMessageId)
|
||||||
{
|
{
|
||||||
EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context);
|
EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||||
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(envelope.getSource(),
|
IncomingTextMessage incomingTextMessage = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()),
|
||||||
envelope.getSourceDevice(),
|
envelope.getSourceDevice(),
|
||||||
message.getTimestamp(),
|
message.getTimestamp(),
|
||||||
"", Optional.<SignalServiceGroup>absent(), 0);
|
"", Optional.<SignalServiceGroup>absent(), 0);
|
||||||
@ -328,7 +330,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
|
|
||||||
if (recipients.isSingleRecipient() && !recipients.isGroupRecipient()) {
|
if (recipients.isSingleRecipient() && !recipients.isGroupRecipient()) {
|
||||||
SessionStore sessionStore = new TextSecureSessionStore(context);
|
SessionStore sessionStore = new TextSecureSessionStore(context);
|
||||||
sessionStore.deleteAllSessions(recipients.getPrimaryRecipient().getNumber());
|
sessionStore.deleteAllSessions(recipients.getPrimaryRecipient().getAddress().toPhoneString());
|
||||||
|
|
||||||
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
||||||
|
|
||||||
@ -373,8 +375,10 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||||
Recipients recipients = getMessageDestination(envelope, message);
|
Recipients recipients = getMessageDestination(envelope, message);
|
||||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret, envelope.getSource(),
|
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret,
|
||||||
localNumber, message.getTimestamp(), -1,
|
Address.fromExternal(context, envelope.getSource()),
|
||||||
|
Address.fromSerialized(localNumber),
|
||||||
|
message.getTimestamp(), -1,
|
||||||
message.getExpiresInSeconds() * 1000, true,
|
message.getExpiresInSeconds() * 1000, true,
|
||||||
Optional.fromNullable(envelope.getRelay()),
|
Optional.fromNullable(envelope.getRelay()),
|
||||||
Optional.<String>absent(), message.getGroupInfo(),
|
Optional.<String>absent(), message.getGroupInfo(),
|
||||||
@ -458,8 +462,8 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
long envelopeTimestamp)
|
long envelopeTimestamp)
|
||||||
{
|
{
|
||||||
for (ReadMessage readMessage : readMessages) {
|
for (ReadMessage readMessage : readMessages) {
|
||||||
List<Pair<Long, Long>> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(readMessage.getSender(), readMessage.getTimestamp()), envelopeTimestamp);
|
List<Pair<Long, Long>> expiringText = DatabaseFactory.getSmsDatabase(context).setTimestampRead(new SyncMessageId(Address.fromExternal(context, readMessage.getSender()), readMessage.getTimestamp()), envelopeTimestamp);
|
||||||
List<Pair<Long, Long>> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(readMessage.getSender(), readMessage.getTimestamp()), envelopeTimestamp);
|
List<Pair<Long, Long>> expiringMedia = DatabaseFactory.getMmsDatabase(context).setTimestampRead(new SyncMessageId(Address.fromExternal(context, readMessage.getSender()), readMessage.getTimestamp()), envelopeTimestamp);
|
||||||
|
|
||||||
for (Pair<Long, Long> expiringMessage : expiringText) {
|
for (Pair<Long, Long> expiringMessage : expiringText) {
|
||||||
ApplicationContext.getInstance(context)
|
ApplicationContext.getInstance(context)
|
||||||
@ -488,8 +492,10 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||||
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
String localNumber = TextSecurePreferences.getLocalNumber(context);
|
||||||
Recipients recipients = getMessageDestination(envelope, message);
|
Recipients recipients = getMessageDestination(envelope, message);
|
||||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret, envelope.getSource(),
|
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret,
|
||||||
localNumber, message.getTimestamp(), -1,
|
Address.fromExternal(context, envelope.getSource()),
|
||||||
|
Address.fromSerialized(localNumber),
|
||||||
|
message.getTimestamp(), -1,
|
||||||
message.getExpiresInSeconds() * 1000, false,
|
message.getExpiresInSeconds() * 1000, false,
|
||||||
Optional.fromNullable(envelope.getRelay()),
|
Optional.fromNullable(envelope.getRelay()),
|
||||||
message.getBody(),
|
message.getBody(),
|
||||||
@ -616,7 +622,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
if (smsMessageId.isPresent() && !message.getGroupInfo().isPresent()) {
|
if (smsMessageId.isPresent() && !message.getGroupInfo().isPresent()) {
|
||||||
threadId = database.updateBundleMessageBody(masterSecret, smsMessageId.get(), body).second;
|
threadId = database.updateBundleMessageBody(masterSecret, smsMessageId.get(), body).second;
|
||||||
} else {
|
} else {
|
||||||
IncomingTextMessage textMessage = new IncomingTextMessage(envelope.getSource(),
|
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()),
|
||||||
envelope.getSourceDevice(),
|
envelope.getSourceDevice(),
|
||||||
message.getTimestamp(), body,
|
message.getTimestamp(), body,
|
||||||
message.getGroupInfo(),
|
message.getGroupInfo(),
|
||||||
@ -764,14 +770,14 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, envelope.getSource(), false);
|
Address sourceAddress = Address.fromExternal(context, envelope.getSource());
|
||||||
long recipientId = recipients.getPrimaryRecipient().getRecipientId();
|
|
||||||
byte[] serialized = envelope.hasLegacyMessage() ? envelope.getLegacyMessage() : envelope.getContent();
|
byte[] serialized = envelope.hasLegacyMessage() ? envelope.getLegacyMessage() : envelope.getContent();
|
||||||
PreKeySignalMessage whisperMessage = new PreKeySignalMessage(serialized);
|
PreKeySignalMessage whisperMessage = new PreKeySignalMessage(serialized);
|
||||||
IdentityKey identityKey = whisperMessage.getIdentityKey();
|
IdentityKey identityKey = whisperMessage.getIdentityKey();
|
||||||
String encoded = Base64.encodeBytes(serialized);
|
String encoded = Base64.encodeBytes(serialized);
|
||||||
|
|
||||||
IncomingTextMessage textMessage = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(),
|
IncomingTextMessage textMessage = new IncomingTextMessage(sourceAddress,
|
||||||
|
envelope.getSourceDevice(),
|
||||||
envelope.getTimestamp(), encoded,
|
envelope.getTimestamp(), encoded,
|
||||||
Optional.<SignalServiceGroup>absent(), 0);
|
Optional.<SignalServiceGroup>absent(), 0);
|
||||||
|
|
||||||
@ -780,13 +786,13 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
Optional<InsertResult> insertResult = database.insertMessageInbox(masterSecret, bundleMessage);
|
Optional<InsertResult> insertResult = database.insertMessageInbox(masterSecret, bundleMessage);
|
||||||
|
|
||||||
if (insertResult.isPresent()) {
|
if (insertResult.isPresent()) {
|
||||||
database.setMismatchedIdentity(insertResult.get().getMessageId(), recipientId, identityKey);
|
database.setMismatchedIdentity(insertResult.get().getMessageId(), sourceAddress, identityKey);
|
||||||
MessageNotifier.updateNotification(context, masterSecret.getMasterSecret().orNull(), insertResult.get().getThreadId());
|
MessageNotifier.updateNotification(context, masterSecret.getMasterSecret().orNull(), insertResult.get().getThreadId());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
database.updateMessageBody(masterSecret, smsMessageId.get(), encoded);
|
database.updateMessageBody(masterSecret, smsMessageId.get(), encoded);
|
||||||
database.markAsPreKeyBundle(smsMessageId.get());
|
database.markAsPreKeyBundle(smsMessageId.get());
|
||||||
database.setMismatchedIdentity(smsMessageId.get(), recipientId, identityKey);
|
database.setMismatchedIdentity(smsMessageId.get(), sourceAddress, identityKey);
|
||||||
}
|
}
|
||||||
} catch (InvalidMessageException | InvalidVersionException e) {
|
} catch (InvalidMessageException | InvalidVersionException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
@ -795,7 +801,8 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
|
|
||||||
private Optional<InsertResult> insertPlaceholder(@NonNull SignalServiceEnvelope envelope) {
|
private Optional<InsertResult> insertPlaceholder(@NonNull SignalServiceEnvelope envelope) {
|
||||||
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||||
IncomingTextMessage textMessage = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(),
|
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, envelope.getSource()),
|
||||||
|
envelope.getSourceDevice(),
|
||||||
envelope.getTimestamp(), "",
|
envelope.getTimestamp(), "",
|
||||||
Optional.<SignalServiceGroup>absent(), 0);
|
Optional.<SignalServiceGroup>absent(), 0);
|
||||||
|
|
||||||
@ -805,17 +812,17 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
|
|
||||||
private Recipients getSyncMessageDestination(SentTranscriptMessage message) {
|
private Recipients getSyncMessageDestination(SentTranscriptMessage message) {
|
||||||
if (message.getMessage().getGroupInfo().isPresent()) {
|
if (message.getMessage().getGroupInfo().isPresent()) {
|
||||||
return RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId()), false);
|
return RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, GroupUtil.getEncodedId(message.getMessage().getGroupInfo().get().getGroupId()))}, false);
|
||||||
} else {
|
} else {
|
||||||
return RecipientFactory.getRecipientsFromString(context, message.getDestination().get(), false);
|
return RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, message.getDestination().get())}, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Recipients getMessageDestination(SignalServiceEnvelope envelope, SignalServiceDataMessage message) {
|
private Recipients getMessageDestination(SignalServiceEnvelope envelope, SignalServiceDataMessage message) {
|
||||||
if (message.getGroupInfo().isPresent()) {
|
if (message.getGroupInfo().isPresent()) {
|
||||||
return RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId()), false);
|
return RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId()))}, false);
|
||||||
} else {
|
} else {
|
||||||
return RecipientFactory.getRecipientsFromString(context, envelope.getSource(), false);
|
return RecipientFactory.getRecipientsFor(context, new Address[] {Address.fromExternal(context, envelope.getSource())}, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package org.thoughtcrime.securesms.jobs;
|
package org.thoughtcrime.securesms.jobs;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
@ -17,7 +20,6 @@ import org.thoughtcrime.securesms.mms.MmsException;
|
|||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||||
@ -51,20 +53,22 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
|
|
||||||
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
@Inject transient SignalMessageSenderFactory messageSenderFactory;
|
||||||
|
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
private final long filterRecipientId;
|
private final long filterRecipientId; // Deprecated
|
||||||
|
private final String filterAddress;
|
||||||
|
|
||||||
public PushGroupSendJob(Context context, long messageId, String destination, long filterRecipientId) {
|
public PushGroupSendJob(Context context, long messageId, @NonNull Address destination, @Nullable Address filterAddress) {
|
||||||
super(context, JobParameters.newBuilder()
|
super(context, JobParameters.newBuilder()
|
||||||
.withPersistence()
|
.withPersistence()
|
||||||
.withGroupId(destination)
|
.withGroupId(destination.toGroupString())
|
||||||
.withRequirement(new MasterSecretRequirement(context))
|
.withRequirement(new MasterSecretRequirement(context))
|
||||||
.withRequirement(new NetworkRequirement(context))
|
.withRequirement(new NetworkRequirement(context))
|
||||||
.withRetryCount(5)
|
.withRetryCount(5)
|
||||||
.create());
|
.create());
|
||||||
|
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
this.filterRecipientId = filterRecipientId;
|
this.filterAddress = filterAddress == null ? null :filterAddress.toPhoneString();
|
||||||
|
this.filterRecipientId = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -79,7 +83,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
OutgoingMediaMessage message = database.getOutgoingMessage(masterSecret, messageId);
|
OutgoingMediaMessage message = database.getOutgoingMessage(masterSecret, messageId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
deliver(masterSecret, message, filterRecipientId);
|
deliver(masterSecret, message, filterAddress == null ? null : Address.fromSerialized(filterAddress));
|
||||||
|
|
||||||
database.markAsSent(messageId, true);
|
database.markAsSent(messageId, true);
|
||||||
markAttachmentsUploaded(messageId, message.getAttachments());
|
markAttachmentsUploaded(messageId, message.getAttachments());
|
||||||
@ -99,13 +103,11 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
List<NetworkFailure> failures = new LinkedList<>();
|
List<NetworkFailure> failures = new LinkedList<>();
|
||||||
|
|
||||||
for (NetworkFailureException nfe : e.getNetworkExceptions()) {
|
for (NetworkFailureException nfe : e.getNetworkExceptions()) {
|
||||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, nfe.getE164number(), false).getPrimaryRecipient();
|
failures.add(new NetworkFailure(Address.fromSerialized(nfe.getE164number())));
|
||||||
failures.add(new NetworkFailure(recipient.getRecipientId()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (UntrustedIdentityException uie : e.getUntrustedIdentityExceptions()) {
|
for (UntrustedIdentityException uie : e.getUntrustedIdentityExceptions()) {
|
||||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, uie.getE164Number(), false).getPrimaryRecipient();
|
database.addMismatchedIdentity(messageId, Address.fromSerialized(uie.getE164Number()), uie.getIdentityKey());
|
||||||
database.addMismatchedIdentity(messageId, recipient.getRecipientId(), uie.getIdentityKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
database.addFailures(messageId, failures);
|
database.addFailures(messageId, failures);
|
||||||
@ -131,20 +133,21 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
DatabaseFactory.getMmsDatabase(context).markAsSentFailed(messageId);
|
DatabaseFactory.getMmsDatabase(context).markAsSentFailed(messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deliver(MasterSecret masterSecret, OutgoingMediaMessage message, long filterRecipientId)
|
private void deliver(MasterSecret masterSecret, OutgoingMediaMessage message, @Nullable Address filterAddress)
|
||||||
throws IOException, RecipientFormattingException, InvalidNumberException,
|
throws IOException, RecipientFormattingException, InvalidNumberException,
|
||||||
EncapsulatedExceptions, UndeliverableMessageException
|
EncapsulatedExceptions, UndeliverableMessageException
|
||||||
{
|
{
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||||
byte[] groupId = GroupUtil.getDecodedId(message.getRecipients().getPrimaryRecipient().getNumber());
|
byte[] groupId = GroupUtil.getDecodedId(message.getRecipients().getPrimaryRecipient().getAddress().toGroupString());
|
||||||
Recipients recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
|
Recipients recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
|
||||||
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
||||||
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
|
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
|
||||||
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(masterSecret, scaledAttachments);
|
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(masterSecret, scaledAttachments);
|
||||||
|
|
||||||
List<SignalServiceAddress> addresses;
|
List<SignalServiceAddress> addresses;
|
||||||
|
|
||||||
if (filterRecipientId >= 0) addresses = getPushAddresses(filterRecipientId);
|
if (filterAddress != null) addresses = getPushAddresses(filterAddress);
|
||||||
else addresses = getPushAddresses(recipients);
|
else addresses = getPushAddresses(recipients);
|
||||||
|
|
||||||
if (message.isGroup()) {
|
if (message.isGroup()) {
|
||||||
OutgoingGroupMediaMessage groupMessage = (OutgoingGroupMediaMessage) message;
|
OutgoingGroupMediaMessage groupMessage = (OutgoingGroupMediaMessage) message;
|
||||||
@ -166,20 +169,19 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SignalServiceAddress> getPushAddresses(Recipients recipients) throws InvalidNumberException {
|
private List<SignalServiceAddress> getPushAddresses(Address address) {
|
||||||
|
List<SignalServiceAddress> addresses = new LinkedList<>();
|
||||||
|
addresses.add(getPushAddress(address));
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SignalServiceAddress> getPushAddresses(Recipients recipients) {
|
||||||
List<SignalServiceAddress> addresses = new LinkedList<>();
|
List<SignalServiceAddress> addresses = new LinkedList<>();
|
||||||
|
|
||||||
for (Recipient recipient : recipients.getRecipientsList()) {
|
for (Recipient recipient : recipients.getRecipientsList()) {
|
||||||
addresses.add(getPushAddress(recipient.getNumber()));
|
addresses.add(getPushAddress(recipient.getAddress()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return addresses;
|
return addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SignalServiceAddress> getPushAddresses(long filterRecipientId) throws InvalidNumberException {
|
|
||||||
List<SignalServiceAddress> addresses = new LinkedList<>();
|
|
||||||
addresses.add(getPushAddress(RecipientFactory.getRecipientForId(context, filterRecipientId, false).getNumber()));
|
|
||||||
return addresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
@ -23,6 +24,8 @@ import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@ -72,11 +75,16 @@ public class PushGroupUpdateJob extends ContextJob implements InjectableType {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> members = new LinkedList<>();
|
||||||
|
|
||||||
|
for (Address member : record.getMembers()) {
|
||||||
|
members.add(member.serialize());
|
||||||
|
}
|
||||||
|
|
||||||
SignalServiceGroup groupContext = SignalServiceGroup.newBuilder(Type.UPDATE)
|
SignalServiceGroup groupContext = SignalServiceGroup.newBuilder(Type.UPDATE)
|
||||||
.withAvatar(avatar)
|
.withAvatar(avatar)
|
||||||
.withId(groupId)
|
.withId(groupId)
|
||||||
.withMembers(record.getMembers())
|
.withMembers(members)
|
||||||
.withName(record.getTitle())
|
.withName(record.getTitle())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -6,14 +6,14 @@ import android.util.Log;
|
|||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||||
|
import org.thoughtcrime.securesms.mms.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
|
||||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||||
@ -24,7 +24,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
|||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -32,8 +31,6 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.mms.MmsException;
|
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
import static org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
|
||||||
|
|
||||||
public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||||
@ -46,7 +43,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
|
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
|
|
||||||
public PushMediaSendJob(Context context, long messageId, String destination) {
|
public PushMediaSendJob(Context context, long messageId, Address destination) {
|
||||||
super(context, constructParameters(context, destination));
|
super(context, constructParameters(context, destination));
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
}
|
}
|
||||||
@ -82,10 +79,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context));
|
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context));
|
||||||
} catch (UntrustedIdentityException uie) {
|
} catch (UntrustedIdentityException uie) {
|
||||||
Log.w(TAG, uie);
|
Log.w(TAG, uie);
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, uie.getE164Number(), false);
|
database.addMismatchedIdentity(messageId, Address.fromSerialized(uie.getE164Number()), uie.getIdentityKey());
|
||||||
long recipientId = recipients.getPrimaryRecipient().getRecipientId();
|
|
||||||
|
|
||||||
database.addMismatchedIdentity(messageId, recipientId, uie.getIdentityKey());
|
|
||||||
database.markAsSentFailed(messageId);
|
database.markAsSentFailed(messageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,17 +102,14 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
throws RetryLaterException, InsecureFallbackApprovalException, UntrustedIdentityException,
|
throws RetryLaterException, InsecureFallbackApprovalException, UntrustedIdentityException,
|
||||||
UndeliverableMessageException
|
UndeliverableMessageException
|
||||||
{
|
{
|
||||||
if (message.getRecipients() == null ||
|
if (message.getRecipients() == null || message.getRecipients().getPrimaryRecipient() == null) {
|
||||||
message.getRecipients().getPrimaryRecipient() == null ||
|
|
||||||
message.getRecipients().getPrimaryRecipient().getNumber() == null)
|
|
||||||
{
|
|
||||||
throw new UndeliverableMessageException("No destination address.");
|
throw new UndeliverableMessageException("No destination address.");
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SignalServiceAddress address = getPushAddress(message.getRecipients().getPrimaryRecipient().getNumber());
|
SignalServiceAddress address = getPushAddress(message.getRecipients().getPrimaryRecipient().getAddress());
|
||||||
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
||||||
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
|
List<Attachment> scaledAttachments = scaleAttachments(masterSecret, mediaConstraints, message.getAttachments());
|
||||||
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(masterSecret, scaledAttachments);
|
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(masterSecret, scaledAttachments);
|
||||||
@ -131,7 +122,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
messageSender.sendMessage(address, mediaMessage);
|
messageSender.sendMessage(address, mediaMessage);
|
||||||
} catch (InvalidNumberException | UnregisteredUserException e) {
|
} catch (UnregisteredUserException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
throw new InsecureFallbackApprovalException(e);
|
throw new InsecureFallbackApprovalException(e);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
|
@ -4,8 +4,8 @@ import android.content.Context;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||||
import org.thoughtcrime.securesms.database.NotInDirectoryException;
|
import org.thoughtcrime.securesms.database.NotInDirectoryException;
|
||||||
import org.thoughtcrime.securesms.database.TextSecureDirectory;
|
import org.thoughtcrime.securesms.database.TextSecureDirectory;
|
||||||
@ -26,33 +26,35 @@ public abstract class PushReceivedJob extends ContextJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void handle(SignalServiceEnvelope envelope, boolean sendExplicitReceipt) {
|
public void handle(SignalServiceEnvelope envelope, boolean sendExplicitReceipt) {
|
||||||
if (!isActiveNumber(context, envelope.getSource())) {
|
Address source = Address.fromExternal(context, envelope.getSource());
|
||||||
|
|
||||||
|
if (!isActiveNumber(context, source)) {
|
||||||
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
|
TextSecureDirectory directory = TextSecureDirectory.getInstance(context);
|
||||||
ContactTokenDetails contactTokenDetails = new ContactTokenDetails();
|
ContactTokenDetails contactTokenDetails = new ContactTokenDetails();
|
||||||
contactTokenDetails.setNumber(envelope.getSource());
|
contactTokenDetails.setNumber(envelope.getSource());
|
||||||
|
|
||||||
directory.setNumber(contactTokenDetails, true);
|
directory.setNumber(contactTokenDetails, true);
|
||||||
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, envelope.getSource(), false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {source}, false);
|
||||||
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context, KeyCachingService.getMasterSecret(context), recipients));
|
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context, KeyCachingService.getMasterSecret(context), recipients));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (envelope.isReceipt()) {
|
if (envelope.isReceipt()) {
|
||||||
handleReceipt(envelope);
|
handleReceipt(envelope);
|
||||||
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage()) {
|
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage()) {
|
||||||
handleMessage(envelope, sendExplicitReceipt);
|
handleMessage(envelope, source, sendExplicitReceipt);
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
|
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleMessage(SignalServiceEnvelope envelope, boolean sendExplicitReceipt) {
|
private void handleMessage(SignalServiceEnvelope envelope, Address source, boolean sendExplicitReceipt) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, envelope.getSource(), false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {source}, false);
|
||||||
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
|
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
|
||||||
|
|
||||||
if (!recipients.isBlocked()) {
|
if (!recipients.isBlocked()) {
|
||||||
long messageId = DatabaseFactory.getPushDatabase(context).insert(envelope);
|
long messageId = DatabaseFactory.getPushDatabase(context).insert(envelope);
|
||||||
jobManager.add(new PushDecryptJob(context, messageId, envelope.getSource()));
|
jobManager.add(new PushDecryptJob(context, messageId));
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "*** Received blocked push message, ignoring...");
|
Log.w(TAG, "*** Received blocked push message, ignoring...");
|
||||||
}
|
}
|
||||||
@ -66,15 +68,15 @@ public abstract class PushReceivedJob extends ContextJob {
|
|||||||
|
|
||||||
private void handleReceipt(SignalServiceEnvelope envelope) {
|
private void handleReceipt(SignalServiceEnvelope envelope) {
|
||||||
Log.w(TAG, String.format("Received receipt: (XXXXX, %d)", envelope.getTimestamp()));
|
Log.w(TAG, String.format("Received receipt: (XXXXX, %d)", envelope.getTimestamp()));
|
||||||
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(new SyncMessageId(envelope.getSource(),
|
DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(new SyncMessageId(Address.fromExternal(context, envelope.getSource()),
|
||||||
envelope.getTimestamp()));
|
envelope.getTimestamp()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isActiveNumber(Context context, String e164number) {
|
private boolean isActiveNumber(Context context, Address address) {
|
||||||
boolean isActiveNumber;
|
boolean isActiveNumber;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isActiveNumber = TextSecureDirectory.getInstance(context).isSecureTextSupported(e164number);
|
isActiveNumber = TextSecureDirectory.getInstance(context).isSecureTextSupported(address);
|
||||||
} catch (NotInDirectoryException e) {
|
} catch (NotInDirectoryException e) {
|
||||||
isActiveNumber = false;
|
isActiveNumber = false;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.ApplicationContext;
|
|||||||
import org.thoughtcrime.securesms.TextSecureExpiredException;
|
import org.thoughtcrime.securesms.TextSecureExpiredException;
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.TextSecureDirectory;
|
import org.thoughtcrime.securesms.database.TextSecureDirectory;
|
||||||
import org.thoughtcrime.securesms.events.PartProgressEvent;
|
import org.thoughtcrime.securesms.events.PartProgressEvent;
|
||||||
@ -16,14 +17,12 @@ import org.thoughtcrime.securesms.mms.PartAuthority;
|
|||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment.ProgressListener;
|
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment.ProgressListener;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -38,10 +37,10 @@ public abstract class PushSendJob extends SendJob {
|
|||||||
super(context, parameters);
|
super(context, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static JobParameters constructParameters(Context context, String destination) {
|
protected static JobParameters constructParameters(Context context, Address destination) {
|
||||||
JobParameters.Builder builder = JobParameters.newBuilder();
|
JobParameters.Builder builder = JobParameters.newBuilder();
|
||||||
builder.withPersistence();
|
builder.withPersistence();
|
||||||
builder.withGroupId(destination);
|
builder.withGroupId(destination.serialize());
|
||||||
builder.withRequirement(new MasterSecretRequirement(context));
|
builder.withRequirement(new MasterSecretRequirement(context));
|
||||||
builder.withRequirement(new NetworkRequirement(context));
|
builder.withRequirement(new NetworkRequirement(context));
|
||||||
builder.withRetryCount(5);
|
builder.withRetryCount(5);
|
||||||
@ -62,10 +61,9 @@ public abstract class PushSendJob extends SendJob {
|
|||||||
onPushSend(masterSecret);
|
onPushSend(masterSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SignalServiceAddress getPushAddress(String number) throws InvalidNumberException {
|
protected SignalServiceAddress getPushAddress(Address address) {
|
||||||
String e164number = Util.canonicalizeNumber(context, number);
|
String relay = TextSecureDirectory.getInstance(context).getRelay(address.toPhoneString());
|
||||||
String relay = TextSecureDirectory.getInstance(context).getRelay(e164number);
|
return new SignalServiceAddress(address.toPhoneString(), Optional.fromNullable(relay));
|
||||||
return new SignalServiceAddress(e164number, Optional.fromNullable(relay));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<SignalServiceAttachment> getAttachmentsFor(MasterSecret masterSecret, List<Attachment> parts) {
|
protected List<SignalServiceAttachment> getAttachmentsFor(MasterSecret masterSecret, List<Attachment> parts) {
|
||||||
|
@ -5,14 +5,13 @@ import android.util.Log;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||||
@ -22,7 +21,6 @@ import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
|||||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -40,7 +38,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
|
|
||||||
private final long messageId;
|
private final long messageId;
|
||||||
|
|
||||||
public PushTextSendJob(Context context, long messageId, String destination) {
|
public PushTextSendJob(Context context, long messageId, Address destination) {
|
||||||
super(context, constructParameters(context, destination));
|
super(context, constructParameters(context, destination));
|
||||||
this.messageId = messageId;
|
this.messageId = messageId;
|
||||||
}
|
}
|
||||||
@ -72,10 +70,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context));
|
ApplicationContext.getInstance(context).getJobManager().add(new DirectoryRefreshJob(context));
|
||||||
} catch (UntrustedIdentityException e) {
|
} catch (UntrustedIdentityException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, e.getE164Number(), false);
|
database.addMismatchedIdentity(record.getId(), Address.fromSerialized(e.getE164Number()), e.getIdentityKey());
|
||||||
long recipientId = recipients.getPrimaryRecipient().getRecipientId();
|
|
||||||
|
|
||||||
database.addMismatchedIdentity(record.getId(), recipientId, e.getIdentityKey());
|
|
||||||
database.markAsSentFailed(record.getId());
|
database.markAsSentFailed(record.getId());
|
||||||
database.markAsPush(record.getId());
|
database.markAsPush(record.getId());
|
||||||
}
|
}
|
||||||
@ -104,7 +99,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
throws UntrustedIdentityException, InsecureFallbackApprovalException, RetryLaterException
|
throws UntrustedIdentityException, InsecureFallbackApprovalException, RetryLaterException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
SignalServiceAddress address = getPushAddress(message.getIndividualRecipient().getNumber());
|
SignalServiceAddress address = getPushAddress(message.getIndividualRecipient().getAddress());
|
||||||
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
SignalServiceMessageSender messageSender = messageSenderFactory.create();
|
||||||
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder()
|
||||||
.withTimestamp(message.getDateSent())
|
.withTimestamp(message.getDateSent())
|
||||||
@ -115,7 +110,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||||||
|
|
||||||
|
|
||||||
messageSender.sendMessage(address, textSecureMessage);
|
messageSender.sendMessage(address, textSecureMessage);
|
||||||
} catch (InvalidNumberException | UnregisteredUserException e) {
|
} catch (UnregisteredUserException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
throw new InsecureFallbackApprovalException(e);
|
throw new InsecureFallbackApprovalException(e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -9,13 +9,11 @@ import android.util.Log;
|
|||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.service.MessageRetrievalService;
|
import org.thoughtcrime.securesms.service.MessageRetrievalService;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.libsignal.IdentityKey;
|
import org.whispersystems.libsignal.IdentityKey;
|
||||||
import org.whispersystems.libsignal.InvalidKeyException;
|
import org.whispersystems.libsignal.InvalidKeyException;
|
||||||
@ -35,14 +33,14 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|||||||
|
|
||||||
@Inject transient SignalServiceMessageReceiver receiver;
|
@Inject transient SignalServiceMessageReceiver receiver;
|
||||||
|
|
||||||
private final long[] recipientIds;
|
private final Recipients recipients;
|
||||||
|
|
||||||
public RetrieveProfileJob(Context context, Recipients recipients) {
|
public RetrieveProfileJob(Context context, Recipients recipients) {
|
||||||
super(context, JobParameters.newBuilder()
|
super(context, JobParameters.newBuilder()
|
||||||
.withRetryCount(3)
|
.withRetryCount(3)
|
||||||
.create());
|
.create());
|
||||||
|
|
||||||
this.recipientIds = recipients.getIds();
|
this.recipients = recipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -51,8 +49,6 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|||||||
@Override
|
@Override
|
||||||
public void onRun() throws IOException, InvalidKeyException {
|
public void onRun() throws IOException, InvalidKeyException {
|
||||||
try {
|
try {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientIds, true);
|
|
||||||
|
|
||||||
for (Recipient recipient : recipients) {
|
for (Recipient recipient : recipients) {
|
||||||
if (recipient.isGroupRecipient()) handleGroupRecipient(recipient);
|
if (recipient.isGroupRecipient()) handleGroupRecipient(recipient);
|
||||||
else handleIndividualRecipient(recipient);
|
else handleIndividualRecipient(recipient);
|
||||||
@ -73,7 +69,7 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|||||||
private void handleIndividualRecipient(Recipient recipient)
|
private void handleIndividualRecipient(Recipient recipient)
|
||||||
throws IOException, InvalidKeyException, InvalidNumberException
|
throws IOException, InvalidKeyException, InvalidNumberException
|
||||||
{
|
{
|
||||||
String number = Util.canonicalizeNumber(context, recipient.getNumber());
|
String number = recipient.getAddress().toPhoneString();
|
||||||
SignalServiceProfile profile = retrieveProfile(number);
|
SignalServiceProfile profile = retrieveProfile(number);
|
||||||
|
|
||||||
if (TextUtils.isEmpty(profile.getIdentityKey())) {
|
if (TextUtils.isEmpty(profile.getIdentityKey())) {
|
||||||
@ -84,7 +80,7 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|||||||
IdentityKey identityKey = new IdentityKey(Base64.decode(profile.getIdentityKey()), 0);
|
IdentityKey identityKey = new IdentityKey(Base64.decode(profile.getIdentityKey()), 0);
|
||||||
|
|
||||||
if (!DatabaseFactory.getIdentityDatabase(context)
|
if (!DatabaseFactory.getIdentityDatabase(context)
|
||||||
.getIdentity(recipient.getRecipientId())
|
.getIdentity(recipient.getAddress())
|
||||||
.isPresent())
|
.isPresent())
|
||||||
{
|
{
|
||||||
Log.w(TAG, "Still first use...");
|
Log.w(TAG, "Still first use...");
|
||||||
@ -97,7 +93,7 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|||||||
private void handleGroupRecipient(Recipient group)
|
private void handleGroupRecipient(Recipient group)
|
||||||
throws IOException, InvalidKeyException, InvalidNumberException
|
throws IOException, InvalidKeyException, InvalidNumberException
|
||||||
{
|
{
|
||||||
byte[] groupId = GroupUtil.getDecodedId(group.getNumber());
|
byte[] groupId = GroupUtil.getDecodedId(group.getAddress().toGroupString());
|
||||||
Recipients recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
|
Recipients recipients = DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
|
||||||
|
|
||||||
for (Recipient recipient : recipients) {
|
for (Recipient recipient : recipients) {
|
||||||
|
@ -9,6 +9,7 @@ import android.util.Log;
|
|||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
||||||
@ -85,7 +86,7 @@ public class SmsReceiveJob extends ContextJob {
|
|||||||
|
|
||||||
private boolean isBlocked(IncomingTextMessage message) {
|
private boolean isBlocked(IncomingTextMessage message) {
|
||||||
if (message.getSender() != null) {
|
if (message.getSender() != null) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(context, message.getSender(), false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, new Address[] {message.getSender()}, false);
|
||||||
return recipients.isBlocked();
|
return recipients.isBlocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +115,7 @@ public class SmsReceiveJob extends ContextJob {
|
|||||||
List<IncomingTextMessage> messages = new LinkedList<>();
|
List<IncomingTextMessage> messages = new LinkedList<>();
|
||||||
|
|
||||||
for (Object pdu : pdus) {
|
for (Object pdu : pdus) {
|
||||||
messages.add(new IncomingTextMessage(SmsMessage.createFromPdu((byte[])pdu), subscriptionId));
|
messages.add(new IncomingTextMessage(context, SmsMessage.createFromPdu((byte[])pdu), subscriptionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messages.isEmpty()) {
|
if (messages.isEmpty()) {
|
||||||
|
@ -80,7 +80,7 @@ public class SmsSendJob extends SendJob {
|
|||||||
throw new UndeliverableMessageException("Trying to send a secure SMS?");
|
throw new UndeliverableMessageException("Trying to send a secure SMS?");
|
||||||
}
|
}
|
||||||
|
|
||||||
String recipient = message.getIndividualRecipient().getNumber();
|
String recipient = message.getIndividualRecipient().getAddress().serialize();
|
||||||
|
|
||||||
// See issue #1516 for bug report, and discussion on commits related to #4833 for problems
|
// 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
|
// related to the original fix to #1516. This still may not be a correct fix if networks allow
|
||||||
|
@ -7,8 +7,6 @@ import android.util.Log;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
|
||||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||||
@ -17,7 +15,6 @@ import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
|||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.service.SmsDeliveryListener;
|
import org.thoughtcrime.securesms.service.SmsDeliveryListener;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.libsignal.state.SessionStore;
|
|
||||||
|
|
||||||
public class SmsSentJob extends MasterSecretJob {
|
public class SmsSentJob extends MasterSecretJob {
|
||||||
|
|
||||||
@ -85,7 +82,7 @@ public class SmsSentJob extends MasterSecretJob {
|
|||||||
Log.w(TAG, "Service connectivity problem, requeuing...");
|
Log.w(TAG, "Service connectivity problem, requeuing...");
|
||||||
ApplicationContext.getInstance(context)
|
ApplicationContext.getInstance(context)
|
||||||
.getJobManager()
|
.getJobManager()
|
||||||
.add(new SmsSendJob(context, messageId, record.getIndividualRecipient().getNumber()));
|
.add(new SmsSendJob(context, messageId, record.getIndividualRecipient().getAddress().serialize()));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
database.markAsSentFailed(messageId);
|
database.markAsSentFailed(messageId);
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package org.thoughtcrime.securesms.mms;
|
package org.thoughtcrime.securesms.mms;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.attachments.PointerAttachment;
|
import org.thoughtcrime.securesms.attachments.PointerAttachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.MmsAddresses;
|
import org.thoughtcrime.securesms.database.MmsAddresses;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
@ -14,25 +17,25 @@ import java.util.List;
|
|||||||
|
|
||||||
public class IncomingMediaMessage {
|
public class IncomingMediaMessage {
|
||||||
|
|
||||||
private final String from;
|
private final Address from;
|
||||||
private final String body;
|
private final String body;
|
||||||
private final String groupId;
|
private final Address groupId;
|
||||||
private final boolean push;
|
private final boolean push;
|
||||||
private final long sentTimeMillis;
|
private final long sentTimeMillis;
|
||||||
private final int subscriptionId;
|
private final int subscriptionId;
|
||||||
private final long expiresIn;
|
private final long expiresIn;
|
||||||
private final boolean expirationUpdate;
|
private final boolean expirationUpdate;
|
||||||
|
|
||||||
private final List<String> to = new LinkedList<>();
|
private final List<Address> to = new LinkedList<>();
|
||||||
private final List<String> cc = new LinkedList<>();
|
private final List<Address> cc = new LinkedList<>();
|
||||||
private final List<Attachment> attachments = new LinkedList<>();
|
private final List<Attachment> attachments = new LinkedList<>();
|
||||||
|
|
||||||
public IncomingMediaMessage(String from, List<String> to, List<String> cc,
|
public IncomingMediaMessage(Context context, String from, List<String> to, List<String> cc,
|
||||||
String body, long sentTimeMillis,
|
String body, long sentTimeMillis,
|
||||||
List<Attachment> attachments, int subscriptionId,
|
List<Attachment> attachments, int subscriptionId,
|
||||||
long expiresIn, boolean expirationUpdate)
|
long expiresIn, boolean expirationUpdate)
|
||||||
{
|
{
|
||||||
this.from = from;
|
this.from = Address.fromExternal(context, from);
|
||||||
this.sentTimeMillis = sentTimeMillis;
|
this.sentTimeMillis = sentTimeMillis;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
this.groupId = null;
|
this.groupId = null;
|
||||||
@ -41,14 +44,20 @@ public class IncomingMediaMessage {
|
|||||||
this.expiresIn = expiresIn;
|
this.expiresIn = expiresIn;
|
||||||
this.expirationUpdate = expirationUpdate;
|
this.expirationUpdate = expirationUpdate;
|
||||||
|
|
||||||
this.to.addAll(to);
|
for (String destination : to) {
|
||||||
this.cc.addAll(cc);
|
this.to.add(Address.fromExternal(context, destination));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String destination : cc) {
|
||||||
|
this.cc.add(Address.fromExternal(context, destination));
|
||||||
|
}
|
||||||
|
|
||||||
this.attachments.addAll(attachments);
|
this.attachments.addAll(attachments);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncomingMediaMessage(MasterSecretUnion masterSecret,
|
public IncomingMediaMessage(MasterSecretUnion masterSecret,
|
||||||
String from,
|
Address from,
|
||||||
String to,
|
Address to,
|
||||||
long sentTimeMillis,
|
long sentTimeMillis,
|
||||||
int subscriptionId,
|
int subscriptionId,
|
||||||
long expiresIn,
|
long expiresIn,
|
||||||
@ -66,7 +75,7 @@ public class IncomingMediaMessage {
|
|||||||
this.expiresIn = expiresIn;
|
this.expiresIn = expiresIn;
|
||||||
this.expirationUpdate = expirationUpdate;
|
this.expirationUpdate = expirationUpdate;
|
||||||
|
|
||||||
if (group.isPresent()) this.groupId = GroupUtil.getEncodedId(group.get().getGroupId());
|
if (group.isPresent()) this.groupId = Address.fromSerialized(GroupUtil.getEncodedId(group.get().getGroupId()));
|
||||||
else this.groupId = null;
|
else this.groupId = null;
|
||||||
|
|
||||||
this.to.add(to);
|
this.to.add(to);
|
||||||
@ -82,14 +91,14 @@ public class IncomingMediaMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MmsAddresses getAddresses() {
|
public MmsAddresses getAddresses() {
|
||||||
return new MmsAddresses(from, to, cc, new LinkedList<String>());
|
return new MmsAddresses(from, to, cc, new LinkedList<Address>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Attachment> getAttachments() {
|
public List<Attachment> getAttachments() {
|
||||||
return attachments;
|
return attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGroupId() {
|
public Address getGroupId() {
|
||||||
return groupId;
|
return groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
package org.thoughtcrime.securesms.notifications;
|
package org.thoughtcrime.securesms.notifications;
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
@ -27,10 +26,9 @@ import android.support.v4.app.RemoteInput;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
|
||||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
@ -48,11 +46,11 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver {
|
public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver {
|
||||||
|
|
||||||
public static final String TAG = AndroidAutoReplyReceiver.class.getSimpleName();
|
public static final String TAG = AndroidAutoReplyReceiver.class.getSimpleName();
|
||||||
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.ANDROID_AUTO_REPLY";
|
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.ANDROID_AUTO_REPLY";
|
||||||
public static final String RECIPIENT_IDS_EXTRA = "car_recipient_ids";
|
public static final String ADDRESSES_EXTRA = "car_addresses";
|
||||||
public static final String VOICE_REPLY_KEY = "car_voice_reply_key";
|
public static final String VOICE_REPLY_KEY = "car_voice_reply_key";
|
||||||
public static final String THREAD_ID_EXTRA = "car_reply_thread_id";
|
public static final String THREAD_ID_EXTRA = "car_reply_thread_id";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onReceive(final Context context, Intent intent,
|
protected void onReceive(final Context context, Intent intent,
|
||||||
@ -64,10 +62,10 @@ public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver {
|
|||||||
|
|
||||||
if (remoteInput == null) return;
|
if (remoteInput == null) return;
|
||||||
|
|
||||||
final long[] recipientIds = intent.getLongArrayExtra(RECIPIENT_IDS_EXTRA);
|
final Address[] addresses = Address.fromParcelable(intent.getParcelableArrayExtra(ADDRESSES_EXTRA));
|
||||||
final long threadId = intent.getLongExtra(THREAD_ID_EXTRA, -1);
|
final long threadId = intent.getLongExtra(THREAD_ID_EXTRA, -1);
|
||||||
final CharSequence responseText = getMessageText(intent);
|
final CharSequence responseText = getMessageText(intent);
|
||||||
final Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientIds, false);
|
final Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses, false);
|
||||||
|
|
||||||
if (responseText != null) {
|
if (responseText != null) {
|
||||||
new AsyncTask<Void, Void, Void>() {
|
new AsyncTask<Void, Void, Void>() {
|
||||||
@ -76,7 +74,7 @@ public class AndroidAutoReplyReceiver extends MasterSecretBroadcastReceiver {
|
|||||||
|
|
||||||
long replyThreadId;
|
long replyThreadId;
|
||||||
|
|
||||||
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipientIds);
|
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(addresses);
|
||||||
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
||||||
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
|
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ public class MessageNotifier {
|
|||||||
sendInThreadNotification(context, recipients);
|
sendInThreadNotification(context, recipients);
|
||||||
} else {
|
} else {
|
||||||
Intent intent = new Intent(context, ConversationActivity.class);
|
Intent intent = new Intent(context, ConversationActivity.class);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId);
|
||||||
intent.setData((Uri.parse("custom://" + System.currentTimeMillis())));
|
intent.setData((Uri.parse("custom://" + System.currentTimeMillis())));
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ public class NotificationItem {
|
|||||||
public PendingIntent getPendingIntent(Context context) {
|
public PendingIntent getPendingIntent(Context context) {
|
||||||
Intent intent = new Intent(context, ConversationActivity.class);
|
Intent intent = new Intent(context, ConversationActivity.class);
|
||||||
Recipients notifyRecipients = threadRecipients != null ? threadRecipients : recipients;
|
Recipients notifyRecipients = threadRecipients != null ? threadRecipients : recipients;
|
||||||
if (notifyRecipients != null) intent.putExtra("recipients", notifyRecipients.getIds());
|
if (notifyRecipients != null) intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, notifyRecipients.getAddresses());
|
||||||
|
|
||||||
intent.putExtra("thread_id", threadId);
|
intent.putExtra("thread_id", threadId);
|
||||||
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||||
|
@ -121,7 +121,7 @@ public class NotificationState {
|
|||||||
Intent intent = new Intent(RemoteReplyReceiver.REPLY_ACTION);
|
Intent intent = new Intent(RemoteReplyReceiver.REPLY_ACTION);
|
||||||
intent.setClass(context, RemoteReplyReceiver.class);
|
intent.setClass(context, RemoteReplyReceiver.class);
|
||||||
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||||
intent.putExtra(RemoteReplyReceiver.RECIPIENT_IDS_EXTRA, recipients.getIds());
|
intent.putExtra(RemoteReplyReceiver.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
intent.setPackage(context.getPackageName());
|
intent.setPackage(context.getPackageName());
|
||||||
|
|
||||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
@ -134,7 +134,7 @@ public class NotificationState {
|
|||||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||||
intent.setClass(context, AndroidAutoReplyReceiver.class);
|
intent.setClass(context, AndroidAutoReplyReceiver.class);
|
||||||
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||||
intent.putExtra(AndroidAutoReplyReceiver.RECIPIENT_IDS_EXTRA, recipients.getIds());
|
intent.putExtra(AndroidAutoReplyReceiver.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
intent.putExtra(AndroidAutoReplyReceiver.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
|
intent.putExtra(AndroidAutoReplyReceiver.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
|
||||||
intent.setPackage(context.getPackageName());
|
intent.setPackage(context.getPackageName());
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ public class NotificationState {
|
|||||||
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications! " + threads.size());
|
if (threads.size() != 1) throw new AssertionError("We only support replies to single thread notifications! " + threads.size());
|
||||||
|
|
||||||
Intent intent = new Intent(context, ConversationPopupActivity.class);
|
Intent intent = new Intent(context, ConversationPopupActivity.class);
|
||||||
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, recipients.getIds());
|
intent.putExtra(ConversationActivity.ADDRESSES_EXTRA, recipients.getAddresses());
|
||||||
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
|
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, (long)threads.toArray()[0]);
|
||||||
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
intent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ import android.support.v4.app.RemoteInput;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||||
@ -44,9 +45,9 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class RemoteReplyReceiver extends MasterSecretBroadcastReceiver {
|
public class RemoteReplyReceiver extends MasterSecretBroadcastReceiver {
|
||||||
|
|
||||||
public static final String TAG = RemoteReplyReceiver.class.getSimpleName();
|
public static final String TAG = RemoteReplyReceiver.class.getSimpleName();
|
||||||
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.WEAR_REPLY";
|
public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.WEAR_REPLY";
|
||||||
public static final String RECIPIENT_IDS_EXTRA = "recipient_ids";
|
public static final String ADDRESSES_EXTRA = "addresses";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onReceive(final Context context, Intent intent,
|
protected void onReceive(final Context context, Intent intent,
|
||||||
@ -58,7 +59,7 @@ public class RemoteReplyReceiver extends MasterSecretBroadcastReceiver {
|
|||||||
|
|
||||||
if (remoteInput == null) return;
|
if (remoteInput == null) return;
|
||||||
|
|
||||||
final long[] recipientIds = intent.getLongArrayExtra(RECIPIENT_IDS_EXTRA);
|
final Address[] addresses = Address.fromParcelable(intent.getParcelableArrayExtra(ADDRESSES_EXTRA));
|
||||||
final CharSequence responseText = remoteInput.getCharSequence(MessageNotifier.EXTRA_REMOTE_REPLY);
|
final CharSequence responseText = remoteInput.getCharSequence(MessageNotifier.EXTRA_REMOTE_REPLY);
|
||||||
|
|
||||||
if (masterSecret != null && responseText != null) {
|
if (masterSecret != null && responseText != null) {
|
||||||
@ -67,11 +68,11 @@ public class RemoteReplyReceiver extends MasterSecretBroadcastReceiver {
|
|||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
long threadId;
|
long threadId;
|
||||||
|
|
||||||
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(recipientIds);
|
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(addresses);
|
||||||
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
||||||
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
|
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
|
||||||
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientIds, false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(context, addresses, false);
|
||||||
if (recipients.isGroupRecipient()) {
|
if (recipients.isGroupRecipient()) {
|
||||||
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipients, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0);
|
OutgoingMediaMessage reply = new OutgoingMediaMessage(recipients, responseText.toString(), new LinkedList<Attachment>(), System.currentTimeMillis(), subscriptionId, expiresIn, 0);
|
||||||
threadId = MessageSender.send(context, masterSecret, reply, -1, false, null);
|
threadId = MessageSender.send(context, masterSecret, reply, -1, false, null);
|
||||||
|
@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.notifications;
|
|||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -19,6 +18,8 @@ import com.bumptech.glide.Glide;
|
|||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||||
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
||||||
import org.thoughtcrime.securesms.mms.Slide;
|
import org.thoughtcrime.securesms.mms.Slide;
|
||||||
@ -69,11 +70,8 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
|
|||||||
.toConversationColor(context)));
|
.toConversationColor(context)));
|
||||||
} else {
|
} else {
|
||||||
setContentTitle(context.getString(R.string.SingleRecipientNotificationBuilder_signal));
|
setContentTitle(context.getString(R.string.SingleRecipientNotificationBuilder_signal));
|
||||||
setLargeIcon(Recipient.getUnknownRecipient()
|
setLargeIcon(ContactPhotoFactory.getDefaultContactPhoto("Unknown")
|
||||||
.getContactPhoto()
|
.asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context)));
|
||||||
.asDrawable(context, Recipient.getUnknownRecipient()
|
|
||||||
.getColor()
|
|
||||||
.toConversationColor(context)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ import org.thoughtcrime.securesms.color.MaterialColor;
|
|||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
|
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
|
||||||
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -42,9 +42,8 @@ public class Recipient {
|
|||||||
|
|
||||||
private final Set<RecipientModifiedListener> listeners = Collections.newSetFromMap(new WeakHashMap<RecipientModifiedListener, Boolean>());
|
private final Set<RecipientModifiedListener> listeners = Collections.newSetFromMap(new WeakHashMap<RecipientModifiedListener, Boolean>());
|
||||||
|
|
||||||
private final long recipientId;
|
private final @NonNull Address address;
|
||||||
|
|
||||||
private @NonNull String number;
|
|
||||||
private @Nullable String name;
|
private @Nullable String name;
|
||||||
private @Nullable String customLabel;
|
private @Nullable String customLabel;
|
||||||
private boolean stale;
|
private boolean stale;
|
||||||
@ -55,13 +54,11 @@ public class Recipient {
|
|||||||
|
|
||||||
@Nullable private MaterialColor color;
|
@Nullable private MaterialColor color;
|
||||||
|
|
||||||
Recipient(long recipientId,
|
Recipient(@NonNull Address address,
|
||||||
@NonNull String number,
|
|
||||||
@Nullable Recipient stale,
|
@Nullable Recipient stale,
|
||||||
@NonNull ListenableFutureTask<RecipientDetails> future)
|
@NonNull ListenableFutureTask<RecipientDetails> future)
|
||||||
{
|
{
|
||||||
this.recipientId = recipientId;
|
this.address = address;
|
||||||
this.number = number;
|
|
||||||
this.contactPhoto = ContactPhotoFactory.getLoadingPhoto();
|
this.contactPhoto = ContactPhotoFactory.getLoadingPhoto();
|
||||||
this.color = null;
|
this.color = null;
|
||||||
this.resolving = true;
|
this.resolving = true;
|
||||||
@ -80,7 +77,6 @@ public class Recipient {
|
|||||||
if (result != null) {
|
if (result != null) {
|
||||||
synchronized (Recipient.this) {
|
synchronized (Recipient.this) {
|
||||||
Recipient.this.name = result.name;
|
Recipient.this.name = result.name;
|
||||||
Recipient.this.number = result.number;
|
|
||||||
Recipient.this.contactUri = result.contactUri;
|
Recipient.this.contactUri = result.contactUri;
|
||||||
Recipient.this.contactPhoto = result.avatar;
|
Recipient.this.contactPhoto = result.avatar;
|
||||||
Recipient.this.color = result.color;
|
Recipient.this.color = result.color;
|
||||||
@ -99,9 +95,8 @@ public class Recipient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Recipient(long recipientId, RecipientDetails details) {
|
Recipient(Address address, RecipientDetails details) {
|
||||||
this.recipientId = recipientId;
|
this.address = address;
|
||||||
this.number = details.number;
|
|
||||||
this.contactUri = details.contactUri;
|
this.contactUri = details.contactUri;
|
||||||
this.name = details.name;
|
this.name = details.name;
|
||||||
this.contactPhoto = details.avatar;
|
this.contactPhoto = details.avatar;
|
||||||
@ -132,20 +127,16 @@ public class Recipient {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull String getNumber() {
|
public @NonNull Address getAddress() {
|
||||||
return number;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable String getCustomLabel() {
|
public @Nullable String getCustomLabel() {
|
||||||
return customLabel;
|
return customLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRecipientId() {
|
|
||||||
return recipientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isGroupRecipient() {
|
public boolean isGroupRecipient() {
|
||||||
return GroupUtil.isEncodedGroup(number);
|
return address.isGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void addListener(RecipientModifiedListener listener) {
|
public synchronized void addListener(RecipientModifiedListener listener) {
|
||||||
@ -157,17 +148,13 @@ public class Recipient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized String toShortString() {
|
public synchronized String toShortString() {
|
||||||
return (name == null ? number : name);
|
return (name == null ? address.serialize() : name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized @NonNull ContactPhoto getContactPhoto() {
|
public synchronized @NonNull ContactPhoto getContactPhoto() {
|
||||||
return contactPhoto;
|
return contactPhoto;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Recipient getUnknownRecipient() {
|
|
||||||
return new Recipient(-1, new RecipientDetails("Unknown", "Unknown", null, null,
|
|
||||||
ContactPhotoFactory.getDefaultContactPhoto(null), null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
@ -176,12 +163,12 @@ public class Recipient {
|
|||||||
|
|
||||||
Recipient that = (Recipient) o;
|
Recipient that = (Recipient) o;
|
||||||
|
|
||||||
return this.recipientId == that.recipientId;
|
return this.address.equals(that.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return 31 + (int)this.recipientId;
|
return this.address.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyListeners() {
|
private void notifyListeners() {
|
||||||
|
@ -19,16 +19,10 @@ package org.thoughtcrime.securesms.recipients;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.CanonicalAddressDatabase;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
public class RecipientFactory {
|
public class RecipientFactory {
|
||||||
|
|
||||||
@ -36,104 +30,32 @@ public class RecipientFactory {
|
|||||||
|
|
||||||
private static final RecipientProvider provider = new RecipientProvider();
|
private static final RecipientProvider provider = new RecipientProvider();
|
||||||
|
|
||||||
public static Recipients getRecipientsForIds(Context context, String recipientIds, boolean asynchronous) {
|
|
||||||
if (TextUtils.isEmpty(recipientIds))
|
|
||||||
return new Recipients();
|
|
||||||
|
|
||||||
return getRecipientsForIds(context, Util.split(recipientIds, " "), asynchronous);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @NonNull Recipients getRecipientsFor(Context context, Collection<Recipient> recipients, boolean asynchronous) {
|
public static @NonNull Recipients getRecipientsFor(Context context, Collection<Recipient> recipients, boolean asynchronous) {
|
||||||
long[] ids = new long[recipients.size()];
|
Address[] addresses= new Address[recipients.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (Recipient recipient : recipients) {
|
for (Recipient recipient : recipients) {
|
||||||
ids[i++] = recipient.getRecipientId();
|
addresses[i++] = recipient.getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider.getRecipients(context, ids, asynchronous);
|
return provider.getRecipients(context, addresses, asynchronous);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Recipients getRecipientsFor(Context context, Recipient recipient, boolean asynchronous) {
|
public static Recipients getRecipientsFor(Context context, Recipient recipient, boolean asynchronous) {
|
||||||
long[] ids = new long[1];
|
Address[] addresses = new Address[1];
|
||||||
ids[0] = recipient.getRecipientId();
|
addresses[0] = recipient.getAddress();
|
||||||
|
|
||||||
return provider.getRecipients(context, ids, asynchronous);
|
return provider.getRecipients(context, addresses, asynchronous);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull static Recipient getRecipientForId(Context context, long recipientId, boolean asynchronous) {
|
public static @NonNull Recipients getRecipientsFor(@NonNull Context context, @NonNull Address[] addresses, boolean asynchronous) {
|
||||||
return provider.getRecipient(context, recipientId, asynchronous);
|
if (addresses == null || addresses.length == 0) throw new AssertionError(addresses);
|
||||||
|
return provider.getRecipients(context, addresses, asynchronous);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull static Recipients getRecipientsForIds(Context context, long[] recipientIds, boolean asynchronous) {
|
public static @NonNull Recipient getRecipientFor(@NonNull Context context, @NonNull Address address, boolean asynchronous) {
|
||||||
return provider.getRecipients(context, recipientIds, asynchronous);
|
if (address == null) throw new AssertionError(address);
|
||||||
}
|
return provider.getRecipient(context, address, asynchronous);
|
||||||
|
|
||||||
public static @NonNull Recipients getRecipientsFromString(Context context, @NonNull String rawText, boolean asynchronous) {
|
|
||||||
StringTokenizer tokenizer = new StringTokenizer(rawText, ",");
|
|
||||||
List<String> ids = new LinkedList<>();
|
|
||||||
|
|
||||||
while (tokenizer.hasMoreTokens()) {
|
|
||||||
Optional<Long> id = getRecipientIdFromNumber(context, tokenizer.nextToken());
|
|
||||||
|
|
||||||
if (id.isPresent()) {
|
|
||||||
ids.add(String.valueOf(id.get()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getRecipientsForIds(context, ids, asynchronous);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @NonNull Recipients getRecipientsFromStrings(@NonNull Context context, @NonNull List<String> numbers, boolean asynchronous) {
|
|
||||||
List<String> ids = new LinkedList<>();
|
|
||||||
|
|
||||||
for (String number : numbers) {
|
|
||||||
Optional<Long> id = getRecipientIdFromNumber(context, number);
|
|
||||||
|
|
||||||
if (id.isPresent()) {
|
|
||||||
ids.add(String.valueOf(id.get()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getRecipientsForIds(context, ids, asynchronous);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static @NonNull Recipients getRecipientsForIds(Context context, List<String> idStrings, boolean asynchronous) {
|
|
||||||
long[] ids = new long[idStrings.size()];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (String id : idStrings) {
|
|
||||||
ids[i++] = Long.parseLong(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return provider.getRecipients(context, ids, asynchronous);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Optional<Long> getRecipientIdFromNumber(Context context, String number) {
|
|
||||||
number = number.trim();
|
|
||||||
|
|
||||||
if (number.isEmpty()) return Optional.absent();
|
|
||||||
|
|
||||||
if (hasBracketedNumber(number)) {
|
|
||||||
number = parseBracketedNumber(number);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.of(CanonicalAddressDatabase.getInstance(context).getCanonicalAddressId(number));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasBracketedNumber(String recipient) {
|
|
||||||
int openBracketIndex = recipient.indexOf('<');
|
|
||||||
|
|
||||||
return (openBracketIndex != -1) &&
|
|
||||||
(recipient.indexOf('>', openBracketIndex) != -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String parseBracketedNumber(String recipient) {
|
|
||||||
int begin = recipient.indexOf('<');
|
|
||||||
int end = recipient.indexOf('>', begin);
|
|
||||||
String value = recipient.substring(begin + 1, end);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clearCache(Context context) {
|
public static void clearCache(Context context) {
|
||||||
|
@ -30,7 +30,7 @@ import org.thoughtcrime.securesms.color.MaterialColor;
|
|||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
||||||
import org.thoughtcrime.securesms.database.CanonicalAddressDatabase;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||||
@ -66,45 +66,43 @@ class RecipientProvider {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static final Map<String, RecipientDetails> STATIC_DETAILS = new HashMap<String, RecipientDetails>() {{
|
private static final Map<String, RecipientDetails> STATIC_DETAILS = new HashMap<String, RecipientDetails>() {{
|
||||||
put("262966", new RecipientDetails("Amazon", "262966", null, null,
|
put("262966", new RecipientDetails("Amazon", null, null,
|
||||||
ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_amazon),
|
ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_amazon),
|
||||||
ContactColors.UNKNOWN_COLOR));
|
ContactColors.UNKNOWN_COLOR));
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@NonNull Recipient getRecipient(Context context, long recipientId, boolean asynchronous) {
|
@NonNull Recipient getRecipient(Context context, Address address, boolean asynchronous) {
|
||||||
Recipient cachedRecipient = recipientCache.get(recipientId);
|
Recipient cachedRecipient = recipientCache.get(address);
|
||||||
if (cachedRecipient != null && !cachedRecipient.isStale() && (asynchronous || !cachedRecipient.isResolving())) {
|
if (cachedRecipient != null && !cachedRecipient.isStale() && (asynchronous || !cachedRecipient.isResolving())) {
|
||||||
return cachedRecipient;
|
return cachedRecipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
String number = CanonicalAddressDatabase.getInstance(context).getAddressFromId(recipientId);
|
|
||||||
|
|
||||||
if (asynchronous) {
|
if (asynchronous) {
|
||||||
cachedRecipient = new Recipient(recipientId, number, cachedRecipient, getRecipientDetailsAsync(context, recipientId, number));
|
cachedRecipient = new Recipient(address, cachedRecipient, getRecipientDetailsAsync(context, address));
|
||||||
} else {
|
} else {
|
||||||
cachedRecipient = new Recipient(recipientId, getRecipientDetailsSync(context, recipientId, number));
|
cachedRecipient = new Recipient(address, getRecipientDetailsSync(context, address));
|
||||||
}
|
}
|
||||||
|
|
||||||
recipientCache.set(recipientId, cachedRecipient);
|
recipientCache.set(address, cachedRecipient);
|
||||||
return cachedRecipient;
|
return cachedRecipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull Recipients getRecipients(Context context, long[] recipientIds, boolean asynchronous) {
|
@NonNull Recipients getRecipients(Context context, Address[] recipientAddresses, boolean asynchronous) {
|
||||||
Recipients cachedRecipients = recipientsCache.get(new RecipientIds(recipientIds));
|
Recipients cachedRecipients = recipientsCache.get(new RecipientAddresses(recipientAddresses));
|
||||||
if (cachedRecipients != null && !cachedRecipients.isStale() && (asynchronous || !cachedRecipients.isResolving())) {
|
if (cachedRecipients != null && !cachedRecipients.isStale() && (asynchronous || !cachedRecipients.isResolving())) {
|
||||||
return cachedRecipients;
|
return cachedRecipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Recipient> recipientList = new LinkedList<>();
|
List<Recipient> recipientList = new LinkedList<>();
|
||||||
|
|
||||||
for (long recipientId : recipientIds) {
|
for (Address address : recipientAddresses) {
|
||||||
recipientList.add(getRecipient(context, recipientId, asynchronous));
|
recipientList.add(getRecipient(context, address, asynchronous));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asynchronous) cachedRecipients = new Recipients(recipientList, cachedRecipients, getRecipientsPreferencesAsync(context, recipientIds));
|
if (asynchronous) cachedRecipients = new Recipients(recipientList, cachedRecipients, getRecipientsPreferencesAsync(context, recipientAddresses));
|
||||||
else cachedRecipients = new Recipients(recipientList, getRecipientsPreferencesSync(context, recipientIds));
|
else cachedRecipients = new Recipients(recipientList, getRecipientsPreferencesSync(context, recipientAddresses));
|
||||||
|
|
||||||
recipientsCache.set(new RecipientIds(recipientIds), cachedRecipients);
|
recipientsCache.set(new RecipientAddresses(recipientAddresses), cachedRecipients);
|
||||||
return cachedRecipients;
|
return cachedRecipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,14 +111,12 @@ class RecipientProvider {
|
|||||||
recipientsCache.reset();
|
recipientsCache.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull ListenableFutureTask<RecipientDetails> getRecipientDetailsAsync(final Context context,
|
private @NonNull ListenableFutureTask<RecipientDetails> getRecipientDetailsAsync(final Context context, final @NonNull Address address)
|
||||||
final long recipientId,
|
|
||||||
final @NonNull String number)
|
|
||||||
{
|
{
|
||||||
Callable<RecipientDetails> task = new Callable<RecipientDetails>() {
|
Callable<RecipientDetails> task = new Callable<RecipientDetails>() {
|
||||||
@Override
|
@Override
|
||||||
public RecipientDetails call() throws Exception {
|
public RecipientDetails call() throws Exception {
|
||||||
return getRecipientDetailsSync(context, recipientId, number);
|
return getRecipientDetailsSync(context, address);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,15 +125,15 @@ class RecipientProvider {
|
|||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull RecipientDetails getRecipientDetailsSync(Context context, long recipientId, @NonNull String number) {
|
private @NonNull RecipientDetails getRecipientDetailsSync(Context context, @NonNull Address address) {
|
||||||
if (GroupUtil.isEncodedGroup(number)) return getGroupRecipientDetails(context, number);
|
if (address.isGroup()) return getGroupRecipientDetails(context, address);
|
||||||
else return getIndividualRecipientDetails(context, recipientId, number);
|
else return getIndividualRecipientDetails(context, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull RecipientDetails getIndividualRecipientDetails(Context context, long recipientId, @NonNull String number) {
|
private @NonNull RecipientDetails getIndividualRecipientDetails(Context context, @NonNull Address address) {
|
||||||
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(new long[]{recipientId});
|
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(context).getRecipientsPreferences(new Address[]{address});
|
||||||
MaterialColor color = preferences.isPresent() ? preferences.get().getColor() : null;
|
MaterialColor color = preferences.isPresent() ? preferences.get().getColor() : null;
|
||||||
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
|
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(address.toPhoneString()));
|
||||||
Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION,
|
Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION,
|
||||||
null, null, null);
|
null, null, null);
|
||||||
|
|
||||||
@ -151,7 +147,7 @@ class RecipientProvider {
|
|||||||
Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2) + ""),
|
Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2) + ""),
|
||||||
name);
|
name);
|
||||||
|
|
||||||
return new RecipientDetails(cursor.getString(0), resultNumber, cursor.getString(4), contactUri, contactPhoto, color);
|
return new RecipientDetails(cursor.getString(0), cursor.getString(4), contactUri, contactPhoto, color);
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "resultNumber is null");
|
Log.w(TAG, "resultNumber is null");
|
||||||
}
|
}
|
||||||
@ -161,14 +157,14 @@ class RecipientProvider {
|
|||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (STATIC_DETAILS.containsKey(number)) return STATIC_DETAILS.get(number);
|
if (STATIC_DETAILS.containsKey(address.toPhoneString())) return STATIC_DETAILS.get(address.toPhoneString());
|
||||||
else return new RecipientDetails(null, number, null, null, ContactPhotoFactory.getDefaultContactPhoto(null), color);
|
else return new RecipientDetails(null, null, null, ContactPhotoFactory.getDefaultContactPhoto(null), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull RecipientDetails getGroupRecipientDetails(Context context, String groupId) {
|
private @NonNull RecipientDetails getGroupRecipientDetails(Context context, Address groupId) {
|
||||||
try {
|
try {
|
||||||
GroupDatabase.GroupRecord record = DatabaseFactory.getGroupDatabase(context)
|
GroupDatabase.GroupRecord record = DatabaseFactory.getGroupDatabase(context)
|
||||||
.getGroup(GroupUtil.getDecodedId(groupId));
|
.getGroup(GroupUtil.getDecodedId(groupId.toGroupString()));
|
||||||
|
|
||||||
if (record != null) {
|
if (record != null) {
|
||||||
ContactPhoto contactPhoto = ContactPhotoFactory.getGroupContactPhoto(record.getAvatar());
|
ContactPhoto contactPhoto = ContactPhotoFactory.getGroupContactPhoto(record.getAvatar());
|
||||||
@ -178,27 +174,27 @@ class RecipientProvider {
|
|||||||
title = context.getString(R.string.RecipientProvider_unnamed_group);;
|
title = context.getString(R.string.RecipientProvider_unnamed_group);;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RecipientDetails(title, groupId, null, null, contactPhoto, null);
|
return new RecipientDetails(title, null, null, contactPhoto, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), groupId, null, null, ContactPhotoFactory.getDefaultGroupPhoto(), null);
|
return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, null, ContactPhotoFactory.getDefaultGroupPhoto(), null);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w("RecipientProvider", e);
|
Log.w("RecipientProvider", e);
|
||||||
return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), groupId, null, null, ContactPhotoFactory.getDefaultGroupPhoto(), null);
|
return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, null, ContactPhotoFactory.getDefaultGroupPhoto(), null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable RecipientsPreferences getRecipientsPreferencesSync(Context context, long[] recipientIds) {
|
private @Nullable RecipientsPreferences getRecipientsPreferencesSync(Context context, Address[] addresses) {
|
||||||
return DatabaseFactory.getRecipientPreferenceDatabase(context)
|
return DatabaseFactory.getRecipientPreferenceDatabase(context)
|
||||||
.getRecipientsPreferences(recipientIds)
|
.getRecipientsPreferences(addresses)
|
||||||
.orNull();
|
.orNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListenableFutureTask<RecipientsPreferences> getRecipientsPreferencesAsync(final Context context, final long[] recipientIds) {
|
private ListenableFutureTask<RecipientsPreferences> getRecipientsPreferencesAsync(final Context context, final Address[] addresses) {
|
||||||
ListenableFutureTask<RecipientsPreferences> task = new ListenableFutureTask<>(new Callable<RecipientsPreferences>() {
|
ListenableFutureTask<RecipientsPreferences> task = new ListenableFutureTask<>(new Callable<RecipientsPreferences>() {
|
||||||
@Override
|
@Override
|
||||||
public RecipientsPreferences call() throws Exception {
|
public RecipientsPreferences call() throws Exception {
|
||||||
return getRecipientsPreferencesSync(context, recipientIds);
|
return getRecipientsPreferencesSync(context, addresses);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -209,52 +205,50 @@ class RecipientProvider {
|
|||||||
|
|
||||||
public static class RecipientDetails {
|
public static class RecipientDetails {
|
||||||
@Nullable public final String name;
|
@Nullable public final String name;
|
||||||
@NonNull public final String number;
|
|
||||||
@Nullable public final String customLabel;
|
@Nullable public final String customLabel;
|
||||||
@NonNull public final ContactPhoto avatar;
|
@NonNull public final ContactPhoto avatar;
|
||||||
@Nullable public final Uri contactUri;
|
@Nullable public final Uri contactUri;
|
||||||
@Nullable public final MaterialColor color;
|
@Nullable public final MaterialColor color;
|
||||||
|
|
||||||
public RecipientDetails(@Nullable String name, @NonNull String number,
|
public RecipientDetails(@Nullable String name, @Nullable String customLabel,
|
||||||
@Nullable String customLabel, @Nullable Uri contactUri,
|
@Nullable Uri contactUri, @NonNull ContactPhoto avatar,
|
||||||
@NonNull ContactPhoto avatar, @Nullable MaterialColor color)
|
@Nullable MaterialColor color)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.customLabel = customLabel;
|
this.customLabel = customLabel;
|
||||||
this.number = number;
|
|
||||||
this.avatar = avatar;
|
this.avatar = avatar;
|
||||||
this.contactUri = contactUri;
|
this.contactUri = contactUri;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RecipientIds {
|
private static class RecipientAddresses {
|
||||||
private final long[] ids;
|
private final Address[] addresses;
|
||||||
|
|
||||||
private RecipientIds(long[] ids) {
|
private RecipientAddresses(Address[] addresses) {
|
||||||
this.ids = ids;
|
this.addresses = addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
if (other == null || !(other instanceof RecipientIds)) return false;
|
if (other == null || !(other instanceof RecipientAddresses)) return false;
|
||||||
return Arrays.equals(this.ids, ((RecipientIds) other).ids);
|
return Arrays.equals(this.addresses, ((RecipientAddresses) other).addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Arrays.hashCode(ids);
|
return Arrays.hashCode(addresses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RecipientCache {
|
private static class RecipientCache {
|
||||||
|
|
||||||
private final Map<Long,Recipient> cache = new LRUCache<>(1000);
|
private final Map<Address,Recipient> cache = new LRUCache<>(1000);
|
||||||
|
|
||||||
public synchronized Recipient get(long recipientId) {
|
public synchronized Recipient get(Address address) {
|
||||||
return cache.get(recipientId);
|
return cache.get(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void set(long recipientId, Recipient recipient) {
|
public synchronized void set(Address address, Recipient recipient) {
|
||||||
cache.put(recipientId, recipient);
|
cache.put(address, recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void reset() {
|
public synchronized void reset() {
|
||||||
@ -267,14 +261,14 @@ class RecipientProvider {
|
|||||||
|
|
||||||
private static class RecipientsCache {
|
private static class RecipientsCache {
|
||||||
|
|
||||||
private final Map<RecipientIds,Recipients> cache = new LRUCache<>(1000);
|
private final Map<RecipientAddresses,Recipients> cache = new LRUCache<>(1000);
|
||||||
|
|
||||||
public synchronized Recipients get(RecipientIds ids) {
|
public synchronized Recipients get(RecipientAddresses addresses) {
|
||||||
return cache.get(ids);
|
return cache.get(addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void set(RecipientIds ids, Recipients recipients) {
|
public synchronized void set(RecipientAddresses addresses, Recipients recipients) {
|
||||||
cache.put(ids, recipients);
|
cache.put(addresses, recipients);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void reset() {
|
public synchronized void reset() {
|
||||||
|
@ -20,20 +20,17 @@ import android.net.Uri;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Patterns;
|
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState;
|
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
|
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
|
||||||
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||||
import org.thoughtcrime.securesms.util.NumberUtil;
|
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -217,15 +214,16 @@ public class Recipients implements Iterable<Recipient>, RecipientModifiedListene
|
|||||||
|
|
||||||
public boolean isEmailRecipient() {
|
public boolean isEmailRecipient() {
|
||||||
for (Recipient recipient : recipients) {
|
for (Recipient recipient : recipients) {
|
||||||
if (NumberUtil.isValidEmail(recipient.getNumber()))
|
if (recipient.getAddress().isEmail()) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGroupRecipient() {
|
public boolean isGroupRecipient() {
|
||||||
return isSingleRecipient() && GroupUtil.isEncodedGroup(recipients.get(0).getNumber());
|
return isSingleRecipient() && recipients.get(0).getAddress().isGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
@ -247,57 +245,20 @@ public class Recipients implements Iterable<Recipient>, RecipientModifiedListene
|
|||||||
return this.recipients;
|
return this.recipients;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long[] getIds() {
|
public Address[] getAddresses() {
|
||||||
long[] ids = new long[recipients.size()];
|
Address[] addresses = new Address[recipients.size()];
|
||||||
for (int i=0; i<recipients.size(); i++) {
|
for (int i=0;i<recipients.size();i++) {
|
||||||
ids[i] = recipients.get(i).getRecipientId();
|
addresses[i] = recipients.get(i).getAddress();
|
||||||
}
|
}
|
||||||
return ids;
|
|
||||||
|
Arrays.sort(addresses);
|
||||||
|
|
||||||
|
return addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSortedIdsString() {
|
public List<Address> getAddressesList() {
|
||||||
Set<Long> recipientSet = new HashSet<>();
|
List<Address> results = new LinkedList<>();
|
||||||
|
Collections.addAll(results, getAddresses());
|
||||||
for (Recipient recipient : this.recipients) {
|
|
||||||
recipientSet.add(recipient.getRecipientId());
|
|
||||||
}
|
|
||||||
|
|
||||||
long[] recipientArray = new long[recipientSet.size()];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (Long recipientId : recipientSet) {
|
|
||||||
recipientArray[i++] = recipientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
Arrays.sort(recipientArray);
|
|
||||||
|
|
||||||
return Util.join(recipientArray, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull String[] toNumberStringArray(boolean scrub) {
|
|
||||||
String[] recipientsArray = new String[recipients.size()];
|
|
||||||
Iterator<Recipient> iterator = recipients.iterator();
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
String number = iterator.next().getNumber();
|
|
||||||
|
|
||||||
if (scrub && number != null &&
|
|
||||||
!Patterns.EMAIL_ADDRESS.matcher(number).matches() &&
|
|
||||||
!GroupUtil.isEncodedGroup(number))
|
|
||||||
{
|
|
||||||
number = number.replaceAll("[^0-9+]", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
recipientsArray[i++] = number;
|
|
||||||
}
|
|
||||||
|
|
||||||
return recipientsArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull List<String> toNumberStringList(boolean scrub) {
|
|
||||||
List<String> results = new LinkedList<>();
|
|
||||||
Collections.addAll(results, toNumberStringArray(scrub));
|
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcel;
|
||||||
import android.service.chooser.ChooserTarget;
|
import android.service.chooser.ChooserTarget;
|
||||||
import android.service.chooser.ChooserTargetService;
|
import android.service.chooser.ChooserTargetService;
|
||||||
import android.support.annotation.RequiresApi;
|
import android.support.annotation.RequiresApi;
|
||||||
@ -48,17 +49,22 @@ public class DirectShareService extends ChooserTargetService {
|
|||||||
ThreadRecord record;
|
ThreadRecord record;
|
||||||
|
|
||||||
while ((record = reader.getNext()) != null && results.size() < 10) {
|
while ((record = reader.getNext()) != null && results.size() < 10) {
|
||||||
Recipients recipients = RecipientFactory.getRecipientsForIds(this, record.getRecipients().getIds(), false);
|
Recipients recipients = RecipientFactory.getRecipientsFor(this, record.getRecipients().getAddresses(), false);
|
||||||
String name = recipients.toShortString();
|
String name = recipients.toShortString();
|
||||||
Drawable drawable = recipients.getContactPhoto().asDrawable(this, recipients.getColor().toConversationColor(this));
|
Drawable drawable = recipients.getContactPhoto().asDrawable(this, recipients.getColor().toConversationColor(this));
|
||||||
Bitmap avatar = BitmapUtil.createFromDrawable(drawable, 500, 500);
|
Bitmap avatar = BitmapUtil.createFromDrawable(drawable, 500, 500);
|
||||||
|
|
||||||
|
Parcel parcel = Parcel.obtain();
|
||||||
|
parcel.writeTypedArray(recipients.getAddresses(), 0);
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putLong(ShareActivity.EXTRA_THREAD_ID, record.getThreadId());
|
bundle.putLong(ShareActivity.EXTRA_THREAD_ID, record.getThreadId());
|
||||||
bundle.putLongArray(ShareActivity.EXTRA_RECIPIENT_IDS, recipients.getIds());
|
bundle.putByteArray(ShareActivity.EXTRA_ADDRESSES_MARSHALLED, parcel.marshall());
|
||||||
bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, record.getDistributionType());
|
bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, record.getDistributionType());
|
||||||
|
bundle.setClassLoader(getClassLoader());
|
||||||
|
|
||||||
results.add(new ChooserTarget(name, Icon.createWithBitmap(avatar), 1.0f, componentName, bundle));
|
results.add(new ChooserTarget(name, Icon.createWithBitmap(avatar), 1.0f, componentName, bundle));
|
||||||
|
parcel.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
|
@ -9,6 +9,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
@ -49,12 +50,20 @@ public class QuickResponseService extends MasterSecretIntentService {
|
|||||||
Rfc5724Uri uri = new Rfc5724Uri(intent.getDataString());
|
Rfc5724Uri uri = new Rfc5724Uri(intent.getDataString());
|
||||||
String content = intent.getStringExtra(Intent.EXTRA_TEXT);
|
String content = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||||
String numbers = uri.getPath();
|
String numbers = uri.getPath();
|
||||||
if(numbers.contains("%")){
|
|
||||||
|
if (numbers.contains("%")){
|
||||||
numbers = URLDecoder.decode(numbers);
|
numbers = URLDecoder.decode(numbers);
|
||||||
}
|
}
|
||||||
|
|
||||||
Recipients recipients = RecipientFactory.getRecipientsFromString(this, numbers, false);
|
String[] numbersArray = numbers.split(",");
|
||||||
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(this).getRecipientsPreferences(recipients.getIds());
|
Address[] addresses = new Address[numbersArray.length];
|
||||||
|
|
||||||
|
for (int i=0;i<numbersArray.length;i++) {
|
||||||
|
addresses[i] = Address.fromExternal(this, numbersArray[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Recipients recipients = RecipientFactory.getRecipientsFor(this, addresses, false);
|
||||||
|
Optional<RecipientsPreferences> preferences = DatabaseFactory.getRecipientPreferenceDatabase(this).getRecipientsPreferences(recipients.getAddresses());
|
||||||
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
int subscriptionId = preferences.isPresent() ? preferences.get().getDefaultSubscriptionId().or(-1) : -1;
|
||||||
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
|
long expiresIn = preferences.isPresent() ? preferences.get().getExpireMessages() * 1000 : 0;
|
||||||
|
|
||||||
|
@ -16,12 +16,11 @@ import org.thoughtcrime.securesms.R;
|
|||||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.PreKeyUtil;
|
import org.thoughtcrime.securesms.crypto.PreKeyUtil;
|
||||||
import org.thoughtcrime.securesms.crypto.SessionUtil;
|
import org.thoughtcrime.securesms.crypto.SessionUtil;
|
||||||
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
import org.thoughtcrime.securesms.jobs.GcmRefreshJob;
|
import org.thoughtcrime.securesms.jobs.GcmRefreshJob;
|
||||||
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
|
||||||
import org.thoughtcrime.securesms.util.DirectoryHelper;
|
import org.thoughtcrime.securesms.util.DirectoryHelper;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
@ -237,7 +236,7 @@ public class RegistrationService extends Service {
|
|||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
setState(new RegistrationState(RegistrationState.STATE_GENERATING_KEYS, number));
|
setState(new RegistrationState(RegistrationState.STATE_GENERATING_KEYS, number));
|
||||||
Recipient self = RecipientFactory.getRecipientsFromString(this, number, false).getPrimaryRecipient();
|
Address self = Address.fromSerialized(number);
|
||||||
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(this);
|
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(this);
|
||||||
List<PreKeyRecord> records = PreKeyUtil.generatePreKeys(this);
|
List<PreKeyRecord> records = PreKeyUtil.generatePreKeys(this);
|
||||||
SignedPreKeyRecord signedPreKey = PreKeyUtil.generateSignedPreKey(this, identityKey, true);
|
SignedPreKeyRecord signedPreKey = PreKeyUtil.generateSignedPreKey(this, identityKey, true);
|
||||||
@ -257,7 +256,7 @@ public class RegistrationService extends Service {
|
|||||||
|
|
||||||
TextSecurePreferences.setWebsocketRegistered(this, true);
|
TextSecurePreferences.setWebsocketRegistered(this, true);
|
||||||
|
|
||||||
DatabaseFactory.getIdentityDatabase(this).saveIdentity(self.getRecipientId(), identityKey.getPublicKey(), IdentityDatabase.VerifiedStatus.VERIFIED, true, System.currentTimeMillis(), true);
|
DatabaseFactory.getIdentityDatabase(this).saveIdentity(self, identityKey.getPublicKey(), IdentityDatabase.VerifiedStatus.VERIFIED, true, System.currentTimeMillis(), true);
|
||||||
DirectoryHelper.refreshDirectory(this, accountManager, number);
|
DirectoryHelper.refreshDirectory(this, accountManager, number);
|
||||||
|
|
||||||
DirectoryRefreshListener.schedule(this);
|
DirectoryRefreshListener.schedule(this);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user