Пример #1
0
  @Override
  public void onSend(MasterSecret masterSecret)
      throws MmsException, IOException, NoSuchMessageException {
    MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
    SendReq message = database.getOutgoingMessage(masterSecret, messageId);

    try {
      deliver(masterSecret, message);

      database.markAsPush(messageId);
      database.markAsSecure(messageId);
      database.markAsSent(messageId, "push".getBytes(), 0);
    } catch (InvalidNumberException | RecipientFormattingException e) {
      Log.w(TAG, e);
      database.markAsSentFailed(messageId);
      notifyMediaMessageDeliveryFailed(context, messageId);
    } catch (EncapsulatedExceptions e) {
      Log.w(TAG, e);
      if (!e.getUnregisteredUserExceptions().isEmpty()) {
        database.markAsSentFailed(messageId);
      }

      for (UntrustedIdentityException uie : e.getUntrustedIdentityExceptions()) {
        IncomingIdentityUpdateMessage identityUpdateMessage =
            IncomingIdentityUpdateMessage.createFor(
                message.getTo()[0].getString(), uie.getIdentityKey());
        DatabaseFactory.getEncryptingSmsDatabase(context)
            .insertMessageInbox(masterSecret, identityUpdateMessage);
        database.markAsSentFailed(messageId);
      }

      notifyMediaMessageDeliveryFailed(context, messageId);
    }
  }
  public ExpiringMessageManager(Context context) {
    this.context = context.getApplicationContext();
    this.smsDatabase = DatabaseFactory.getSmsDatabase(context);
    this.mmsDatabase = DatabaseFactory.getMmsDatabase(context);

    executor.execute(new LoadTask());
    executor.execute(new ProcessTask());
  }
Пример #3
0
  private void handleSentResult(MasterSecret masterSecret, long messageId, int result) {
    try {
      EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
      SmsMessageRecord record = database.getMessage(masterSecret, messageId);

      switch (result) {
        case Activity.RESULT_OK:
          database.markAsSent(messageId);

          if (record != null && record.isEndSession()) {
            Log.w(TAG, "Ending session...");
            SessionStore sessionStore = new TextSecureSessionStore(context, masterSecret);
            sessionStore.deleteAllSessions(record.getIndividualRecipient().getRecipientId());
            SecurityEvent.broadcastSecurityUpdateEvent(context, record.getThreadId());
          }

          break;
        case SmsManager.RESULT_ERROR_NO_SERVICE:
        case SmsManager.RESULT_ERROR_RADIO_OFF:
          Log.w(TAG, "Service connectivity problem, requeuing...");
          ApplicationContext.getInstance(context)
              .getJobManager()
              .add(new SmsSendJob(context, messageId, record.getIndividualRecipient().getNumber()));

          break;
        default:
          database.markAsSentFailed(messageId);
          MessageNotifier.notifyMessageDeliveryFailed(
              context, record.getRecipients(), record.getThreadId());
      }
    } catch (NoSuchMessageException e) {
      Log.w(TAG, e);
    }
  }
    public void onClick(View v) {
      if (identityName.getText() == null
          || identityName.getText().toString().trim().length() == 0) {
        Toast.makeText(
                SaveIdentityActivity.this,
                "You must specify a name for this identity!",
                Toast.LENGTH_LONG)
            .show();
        return;
      }

      try {
        DatabaseFactory.getIdentityDatabase(SaveIdentityActivity.this)
            .saveIdentity(masterSecret, identityKey, identityName.getText().toString());
      } catch (InvalidKeyException e) {
        AlertDialog.Builder builder = new AlertDialog.Builder(SaveIdentityActivity.this);
        builder.setTitle("Identity Name Exists!");
        builder.setMessage("An identity key with the specified name already exists.");
        builder.setPositiveButton(
            "Manage Identities",
            new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int which) {
                Intent intent =
                    new Intent(SaveIdentityActivity.this, ReviewIdentitiesActivity.class);
                intent.putExtra("master_secret", masterSecret);
                startActivity(intent);
              }
            });
        builder.setNegativeButton("Cancel", null);
        builder.show();
        return;
      }

      finish();
    }
Пример #5
0
  private void handleCommonRegistration(
      MasterSecret masterSecret, TextSecureAccountManager accountManager, String number)
      throws IOException {
    setState(new RegistrationState(RegistrationState.STATE_GENERATING_KEYS, number));
    Recipient self =
        RecipientFactory.getRecipientsFromString(this, number, false).getPrimaryRecipient();
    IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(this, masterSecret);
    List<PreKeyRecord> records = PreKeyUtil.generatePreKeys(this, masterSecret);
    PreKeyRecord lastResort = PreKeyUtil.generateLastResortKey(this, masterSecret);
    SignedPreKeyRecord signedPreKey =
        PreKeyUtil.generateSignedPreKey(this, masterSecret, identityKey);
    accountManager.setPreKeys(identityKey.getPublicKey(), lastResort, signedPreKey, records);

    setState(new RegistrationState(RegistrationState.STATE_GCM_REGISTERING, number));

    String gcmRegistrationId = "";
    accountManager.setGcmId(Optional.of(gcmRegistrationId));

    TextSecurePreferences.setGcmRegistrationId(this, gcmRegistrationId);
    TextSecurePreferences.setWebsocketRegistered(this, true);

    DatabaseFactory.getIdentityDatabase(this)
        .saveIdentity(masterSecret, self.getRecipientId(), identityKey.getPublicKey());
    DirectoryHelper.refreshDirectory(this, accountManager, number);

    DirectoryRefreshListener.schedule(this);
  }
Пример #6
0
  private @NonNull RecipientDetails getIndividualRecipientDetails(
      Context context, long recipientId, String number) {
    Optional<RecipientsPreferences> preferences =
        DatabaseFactory.getRecipientPreferenceDatabase(context)
            .getRecipientsPreferences(new long[] {recipientId});
    MaterialColor color = preferences.isPresent() ? preferences.get().getColor() : null;
    Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
    Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION, null, null, null);

    try {
      if (cursor != null && cursor.moveToFirst()) {
        Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1));
        String name = cursor.getString(3).equals(cursor.getString(0)) ? null : cursor.getString(0);
        ContactPhoto contactPhoto =
            ContactPhotoFactory.getContactPhoto(
                context, Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2) + ""), name);

        return new RecipientDetails(
            cursor.getString(0), cursor.getString(3), contactUri, contactPhoto, color);
      }
    } finally {
      if (cursor != null) cursor.close();
    }

    return new RecipientDetails(
        null, number, null, ContactPhotoFactory.getDefaultContactPhoto(null), color);
  }
Пример #7
0
  private void handleSentMessage(Intent intent) {
    long messageId = intent.getLongExtra("message_id", -1);
    int result = intent.getIntExtra("ResultCode", -31337);
    boolean upgraded = intent.getBooleanExtra("upgraded", false);
    boolean push = intent.getBooleanExtra("push", false);

    Log.w("SMSReceiverService", "Intent resultcode: " + result);
    Log.w("SMSReceiverService", "Running sent callback: " + messageId);

    if (result == Activity.RESULT_OK) {
      SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
      Cursor cursor = database.getMessage(messageId);
      SmsDatabase.Reader reader = database.readerFor(cursor);

      database.markAsSent(messageId);

      if (upgraded) database.markAsSecure(messageId);
      if (push) database.markAsPush(messageId);

      SmsMessageRecord record = reader.getNext();

      if (record != null && record.isEndSession()) {
        Log.w("SmsSender", "Ending session...");
        Session.abortSessionFor(context, record.getIndividualRecipient());
        KeyExchangeProcessor.broadcastSecurityUpdateEvent(context, record.getThreadId());
      }

      unregisterForRadioChanges();
    } else if (result == SmsManager.RESULT_ERROR_NO_SERVICE
        || result == SmsManager.RESULT_ERROR_RADIO_OFF) {
      DatabaseFactory.getSmsDatabase(context).markAsOutbox(messageId);
      toastHandler
          .obtainMessage(
              0, context.getString(R.string.SmsReceiver_currently_unable_to_send_your_sms_message))
          .sendToTarget();
      registerForRadioChanges();
    } else {
      long threadId = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageId);
      Recipients recipients =
          DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(threadId);

      DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
      MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
      unregisterForRadioChanges();
    }
  }
 @Override
 protected Recipients doInBackground(Void... params) {
   try {
     String groupId = recipients.getPrimaryRecipient().getNumber();
     return DatabaseFactory.getGroupDatabase(context)
         .getGroupMembers(GroupUtil.getDecodedId(groupId), true);
   } catch (IOException e) {
     Log.w(TAG, e);
     return RecipientFactory.getRecipientsFor(context, new LinkedList<Recipient>(), true);
   }
 }
Пример #9
0
  private void handleDeliveredMessage(Intent intent) {
    long messageId = intent.getLongExtra("message_id", -1);
    byte[] pdu = intent.getByteArrayExtra("pdu");
    SmsMessage message = SmsMessage.createFromPdu(pdu);

    if (message == null) {
      return;
    }

    DatabaseFactory.getSmsDatabase(context).markStatus(messageId, message.getStatus());
  }
  private Cursor getUnarchivedConversationList() {
    List<Cursor> cursorList = new LinkedList<>();
    cursorList.add(DatabaseFactory.getThreadDatabase(context).getConversationList());

    int archivedCount =
        DatabaseFactory.getThreadDatabase(context).getArchivedConversationListCount();

    if (archivedCount > 0) {
      MatrixCursor switchToArchiveCursor =
          new MatrixCursor(
              new String[] {
                ThreadDatabase.ID, ThreadDatabase.DATE, ThreadDatabase.MESSAGE_COUNT,
                ThreadDatabase.RECIPIENT_IDS, ThreadDatabase.SNIPPET, ThreadDatabase.READ,
                ThreadDatabase.TYPE, ThreadDatabase.SNIPPET_TYPE, ThreadDatabase.SNIPPET_URI,
                ThreadDatabase.ARCHIVED, ThreadDatabase.STATUS, ThreadDatabase.RECEIPT_COUNT,
                ThreadDatabase.EXPIRES_IN
              },
              1);

      switchToArchiveCursor.addRow(
          new Object[] {
            -1L,
            System.currentTimeMillis(),
            archivedCount,
            "-1",
            null,
            1,
            ThreadDatabase.DistributionTypes.ARCHIVE,
            0,
            null,
            0,
            -1,
            0,
            0
          });

      cursorList.add(switchToArchiveCursor);
    }

    return new MergeCursor(cursorList.toArray(new Cursor[0]));
  }
Пример #11
0
  private boolean isActiveGroup() {
    if (!isGroupConversation()) return false;

    try {
      byte[] groupId = GroupUtil.getDecodedId(getRecipients().getPrimaryRecipient().getNumber());
      GroupRecord record = DatabaseFactory.getGroupDatabase(this).getGroup(groupId);

      return record != null && record.isActive();
    } catch (IOException e) {
      Log.w("ConversationActivity", e);
      return false;
    }
  }
Пример #12
0
  private void handleSendMessage(MasterSecret masterSecret, Intent intent) {
    long messageId = intent.getLongExtra("message_id", -1);
    UniversalTransport transport = new UniversalTransport(context, masterSecret);
    EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);

    EncryptingSmsDatabase.Reader reader = null;
    SmsMessageRecord record;

    Log.w("SmsSender", "Sending message: " + messageId);

    try {
      if (messageId != -1) reader = database.getMessage(masterSecret, messageId);
      else reader = database.getOutgoingMessages(masterSecret);

      while (reader != null && (record = reader.getNext()) != null) {
        try {
          database.markAsSending(record.getId());

          transport.deliver(record);
        } catch (UntrustedIdentityException e) {
          Log.w("SmsSender", e);
          IncomingIdentityUpdateMessage identityUpdateMessage =
              IncomingIdentityUpdateMessage.createFor(e.getE164Number(), e.getIdentityKey());
          DatabaseFactory.getEncryptingSmsDatabase(context)
              .insertMessageInbox(masterSecret, identityUpdateMessage);
          DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
        } catch (UndeliverableMessageException ude) {
          Log.w("SmsSender", ude);
          DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
        } catch (RetryLaterException rle) {
          Log.w("SmsSender", rle);
          if (systemStateListener.isConnected()) scheduleQuickRetryAlarm();
          else systemStateListener.registerForConnectivityChange();
        }
      }
    } finally {
      if (reader != null) reader.close();
    }
  }
Пример #13
0
  private Pair<Long, Long> storeMessage(
      MasterSecretUnion masterSecret, IncomingTextMessage message) {
    EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);

    Pair<Long, Long> messageAndThreadId;

    if (message.isSecureMessage()) {
      IncomingTextMessage placeholder = new IncomingTextMessage(message, "");
      messageAndThreadId = database.insertMessageInbox(placeholder);
      database.markAsLegacyVersion(messageAndThreadId.first);
    } else {
      messageAndThreadId = database.insertMessageInbox(masterSecret, message);
    }

    return messageAndThreadId;
  }
Пример #14
0
  private @NonNull RecipientDetails getGroupRecipientDetails(Context context, String groupId) {
    try {
      GroupDatabase.GroupRecord record =
          DatabaseFactory.getGroupDatabase(context).getGroup(GroupUtil.getDecodedId(groupId));

      if (record != null) {
        ContactPhoto contactPhoto = ContactPhotoFactory.getGroupContactPhoto(record.getAvatar());
        return new RecipientDetails(record.getTitle(), groupId, null, contactPhoto, null);
      }

      return new RecipientDetails(
          null, groupId, null, ContactPhotoFactory.getDefaultGroupPhoto(), null);
    } catch (IOException e) {
      Log.w("RecipientProvider", e);
      return new RecipientDetails(
          null, groupId, null, ContactPhotoFactory.getDefaultGroupPhoto(), null);
    }
  }
Пример #15
0
  private void deliver(MasterSecret masterSecret, SendReq message)
      throws IOException, RecipientFormattingException, InvalidNumberException,
          EncapsulatedExceptions {
    TextSecureMessageSender messageSender = messageSenderFactory.create(masterSecret);
    byte[] groupId = GroupUtil.getDecodedId(message.getTo()[0].getString());
    Recipients recipients =
        DatabaseFactory.getGroupDatabase(context).getGroupMembers(groupId, false);
    List<PushAddress> addresses = getPushAddresses(recipients);
    List<TextSecureAttachment> attachments = getAttachments(masterSecret, message);

    if (MmsSmsColumns.Types.isGroupUpdate(message.getDatabaseMessageBox())
        || MmsSmsColumns.Types.isGroupQuit(message.getDatabaseMessageBox())) {
      String content = PartParser.getMessageText(message.getBody());

      if (content != null && !content.trim().isEmpty()) {
        PushMessageProtos.PushMessageContent.GroupContext groupContext =
            PushMessageProtos.PushMessageContent.GroupContext.parseFrom(Base64.decode(content));
        TextSecureAttachment avatar = attachments.isEmpty() ? null : attachments.get(0);
        TextSecureGroup.Type type =
            MmsSmsColumns.Types.isGroupQuit(message.getDatabaseMessageBox())
                ? TextSecureGroup.Type.QUIT
                : TextSecureGroup.Type.UPDATE;
        TextSecureGroup group =
            new TextSecureGroup(
                type, groupId, groupContext.getName(), groupContext.getMembersList(), avatar);
        TextSecureMessage groupMessage =
            new TextSecureMessage(message.getSentTimestamp(), group, null, null);

        messageSender.sendMessage(addresses, groupMessage);
      }
    } else {
      String body = PartParser.getMessageText(message.getBody());
      TextSecureGroup group = new TextSecureGroup(groupId);
      TextSecureMessage groupMessage =
          new TextSecureMessage(message.getSentTimestamp(), group, attachments, body);

      messageSender.sendMessage(addresses, groupMessage);
    }
  }
  private void createConversationIfNecessary(Intent intent) {
    long thread = intent.getLongExtra("thread_id", -1L);
    Recipients recipients = null;

    if (intent.getAction() != null && intent.getAction().equals("android.intent.action.SENDTO")) {
      try {
        recipients =
            RecipientFactory.getRecipientsFromString(
                this, intent.getData().getSchemeSpecificPart());
        thread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipients);
      } catch (RecipientFormattingException rfe) {
        recipients = null;
      }
    } else {
      recipients = intent.getParcelableExtra("recipients");
    }

    if (recipients != null) {
      createConversation(thread, recipients);
      intent.putExtra("thread_id", -1L);
      intent.putExtra("recipients", (Parcelable) null);
      intent.setAction(null);
    }
  }
Пример #17
0
 private static Recipient getRecipientFromProviderId(
     Context context, String recipientId, boolean asynchronous) {
   String number = DatabaseFactory.getAddressDatabase(context).getAddressFromId(recipientId);
   return getRecipientForNumber(context, number, asynchronous);
 }
 private Cursor getArchivedConversationList() {
   return DatabaseFactory.getThreadDatabase(context).getArchivedConversationList();
 }
 private Cursor getFilteredConversationList(String filter) {
   List<String> numbers =
       ContactAccessor.getInstance().getNumbersForThreadSearchFilter(context, filter);
   return DatabaseFactory.getThreadDatabase(context).getFilteredConversationList(numbers);
 }
Пример #20
0
 private void handleDeliveredResult(long messageId, int result) {
   DatabaseFactory.getEncryptingSmsDatabase(context).markStatus(messageId, result);
 }
Пример #21
0
 private @Nullable RecipientsPreferences getRecipientsPreferencesSync(
     Context context, long[] recipientIds) {
   return DatabaseFactory.getRecipientPreferenceDatabase(context)
       .getRecipientsPreferences(recipientIds)
       .orNull();
 }
Пример #22
0
 @Override
 public void onCanceled() {
   DatabaseFactory.getMmsDatabase(context).markAsSentFailed(messageId);
 }