if (LOCAL_LOGV) Log.v(TAG, "fetching message uid " + message.getUid()); message.getFolder().fetch(Collections.singletonList(message), fp, null); dataType = converter.getDataType(message);
private void importCallLog(final Message message) throws MessagingException, IOException { if (LOCAL_LOGV) Log.v(TAG, "importCallLog(" + message + ")"); final ContentValues values = converter.messageToContentValues(message); if (!callLogExists(values)) { final Uri uri = resolver.insert(Consts.CALLLOG_PROVIDER, values); if (uri != null) callLogIds.add(uri.getLastPathSegment()); } else { if (LOCAL_LOGV) Log.d(TAG, "ignoring call log"); } }
public @NonNull ConversionResult convertMessages(final Cursor cursor, DataType dataType) throws MessagingException { final Map<String, String> msgMap = getMessageMap(cursor); final Message m = messageGenerator.messageForDataType(msgMap, dataType); final ConversionResult result = new ConversionResult(dataType); if (m != null) { m.setFlag(Flag.SEEN, markAsSeen(dataType, msgMap)); result.add(m, msgMap); } return result; }
@Test public void testConvertMessagesSeenFlagFromMessageStatusWithSMS() throws Exception { MatrixCursor cursor = new MatrixCursor(new String[] {Telephony.TextBasedSmsColumns.ADDRESS, Telephony.TextBasedSmsColumns.READ} ); cursor.addRow(new Object[]{ "foo", "0" }); cursor.addRow(new Object[]{ "foo", "1" }); cursor.moveToFirst(); PersonRecord record = mock(PersonRecord.class); when(personLookup.lookupPerson(any(String.class))).thenReturn(record); when(record.getAddress(any(AddressStyle.class))).thenReturn(new Address("foo")); when(preferences.getMarkAsReadType()).thenReturn(MarkAsReadTypes.MESSAGE_STATUS); messageConverter = new MessageConverter(RuntimeEnvironment.application, preferences, "foo@example.com", personLookup, contactAccessor); ConversionResult res = messageConverter.convertMessages(cursor, DataType.SMS); assertThat(res.getMessages().get(0).isSet(Flag.SEEN)).isFalse(); cursor.moveToNext(); res = messageConverter.convertMessages(cursor, DataType.SMS); assertThat(res.getMessages().get(0).isSet(Flag.SEEN)).isTrue(); }
@Test public void shouldVerifyStoreSettings() throws Exception { mockFetch(SMS, 1); when(converter.convertMessages(any(Cursor.class), eq(SMS))).thenReturn(result(SMS, 1)); when(store.getFolder(SMS, dataTypePreferences)).thenReturn(folder); task.doInBackground(config); verify(store).checkSettings(); }
@Test public void shouldRestoreItems() throws Exception { Date now = new Date(); List<ImapMessage> messages = new ArrayList<ImapMessage>(); ContentValues values = new ContentValues(); values.put(Telephony.TextBasedSmsColumns.TYPE, Telephony.TextBasedSmsColumns.MESSAGE_TYPE_INBOX); values.put(Telephony.TextBasedSmsColumns.DATE, now.getTime()); ImapMessage mockMessage = mock(ImapMessage.class); when(mockMessage.getFolder()).thenReturn(folder); when(converter.getDataType(mockMessage)).thenReturn(DataType.SMS); when(converter.messageToContentValues(mockMessage)).thenReturn(values); messages.add(mockMessage); when(folder.getMessages(anyInt(), anyBoolean(), any(Date.class))).thenReturn(messages); when(resolver.insert(Consts.SMS_PROVIDER, values)).thenReturn(Uri.parse("content://sms/123")); task.doInBackground(config); verify(resolver).insert(Consts.SMS_PROVIDER, values); verify(resolver).delete(Uri.parse("content://sms/conversations/-1"), null, null); assertThat(service.getPreferences().getDataTypePreferences().getMaxSyncedDate(DataType.SMS)).isEqualTo(now.getTime()); assertThat(task.getSmsIds()).containsExactly("123"); verify(store).closeFolders(); } }
@Before public void setUp() throws Exception { initMocks(this); BinaryTempFileBody.setTempDirectory(RuntimeEnvironment.application.getCacheDir()); messageConverter = new MessageConverter(RuntimeEnvironment.application, preferences, "foo@example.com", personLookup, contactAccessor); }
public MessageConverter(Context context, Preferences preferences, String userEmail, PersonLookup personLookup, ContactAccessor contactAccessor) { this.context = context; markAsReadType = preferences.getMarkAsReadType(); this.personLookup = personLookup; markAsReadOnRestore = preferences.getMarkAsReadOnRestore(); String referenceUid = preferences.getReferenceUid(); if (referenceUid == null) { referenceUid = generateReferenceValue(); preferences.setReferenceUid(referenceUid); } final ContactGroup backupContactGroup = preferences.getBackupContactGroup(); ContactGroupIds allowedIds = contactAccessor.getGroupContactIds(context.getContentResolver(), backupContactGroup); if (LOCAL_LOGV) Log.v(TAG, "whitelisted ids for backup: " + allowedIds); messageGenerator = new MessageGenerator(context, new Address(userEmail), preferences.getEmailAddressStyle(), new HeaderGenerator(referenceUid, App.getVersionCode(context)), personLookup, preferences.getMailSubjectPrefix(), allowedIds, new MmsSupport(context.getContentResolver(), personLookup), preferences.getCallLogType(), preferences.getDataTypePreferences()); }
@Test public void testConvertMessagesSeenFlagUnreadWithSMS() throws Exception { MatrixCursor cursor = new MatrixCursor(new String[] {Telephony.TextBasedSmsColumns.ADDRESS, Telephony.TextBasedSmsColumns.READ} ); cursor.addRow(new Object[]{ "foo", "0" }); cursor.addRow(new Object[]{ "foo", "1" }); cursor.moveToFirst(); PersonRecord record = mock(PersonRecord.class); when(personLookup.lookupPerson(any(String.class))).thenReturn(record); when(record.getAddress(any(AddressStyle.class))).thenReturn(new Address("foo")); when(preferences.getMarkAsReadType()).thenReturn(MarkAsReadTypes.UNREAD); messageConverter = new MessageConverter(RuntimeEnvironment.application, preferences, "foo@example.com", personLookup, contactAccessor); ConversionResult res = messageConverter.convertMessages(cursor, DataType.SMS); assertThat(res.getMessages().get(0).isSet(Flag.SEEN)).isFalse(); cursor.moveToNext(); res = messageConverter.convertMessages(cursor, DataType.SMS); assertThat(res.getMessages().get(0).isSet(Flag.SEEN)).isFalse(); }
@Test public void shouldCreateFoldersLazilyOnlyForNeededTypes() throws Exception { mockFetch(SMS, 1); when(converter.convertMessages(any(Cursor.class), eq(SMS))).thenReturn(result(SMS, 1)); when(store.getFolder(notNull(DataType.class), same(dataTypePreferences))).thenReturn(folder); task.doInBackground(config); verify(store).getFolder(SMS, dataTypePreferences); verify(store, never()).getFolder(MMS, dataTypePreferences); verify(store, never()).getFolder(CALLLOG, dataTypePreferences); }
BackupTask(@NonNull SmsBackupService service) { final Context context = service.getApplicationContext(); this.service = service; this.authPreferences = service.getAuthPreferences(); this.preferences = service.getPreferences(); this.fetcher = new BackupItemsFetcher( context.getContentResolver(), new BackupQueryBuilder(preferences.getDataTypePreferences())); PersonLookup personLookup = new PersonLookup(service.getContentResolver()); this.contactAccessor = new ContactAccessor(); this.converter = new MessageConverter(context, service.getPreferences(), authPreferences.getUserEmail(), personLookup, contactAccessor); if (preferences.isCallLogCalendarSyncEnabled()) { calendarSyncer = new CalendarSyncer( CalendarAccessor.Get.instance(service.getContentResolver()), preferences.getCallLogCalendarId(), personLookup, new CallFormatter(context.getResources()) ); } else { calendarSyncer = null; } this.tokenRefresher = new TokenRefresher(service, new OAuth2Client(authPreferences.getOAuth2ClientId()), authPreferences); }
@Test public void testConvertMessagesSeenFlagReadWithSMS() throws Exception { MatrixCursor cursor = new MatrixCursor(new String[] {Telephony.TextBasedSmsColumns.ADDRESS, Telephony.TextBasedSmsColumns.READ} ); cursor.addRow(new Object[]{ "foo", "0" }); cursor.addRow(new Object[]{ "foo", "1" }); cursor.moveToFirst(); PersonRecord record = mock(PersonRecord.class); when(personLookup.lookupPerson(any(String.class))).thenReturn(record); when(record.getAddress(any(AddressStyle.class))).thenReturn(new Address("foo")); when(preferences.getMarkAsReadType()).thenReturn(MarkAsReadTypes.READ); messageConverter = new MessageConverter(RuntimeEnvironment.application, preferences, "foo@example.com", personLookup, contactAccessor); ConversionResult res = messageConverter.convertMessages(cursor, DataType.SMS); assertThat(res.getMessages().get(0).isSet(Flag.SEEN)).isTrue(); cursor.moveToNext(); res = messageConverter.convertMessages(cursor, DataType.SMS); assertThat(res.getMessages().get(0).isSet(Flag.SEEN)).isTrue(); }
@Test public void shouldCloseImapFolderAfterBackup() throws Exception { mockFetch(SMS, 1); when(converter.convertMessages(any(Cursor.class), eq(SMS))).thenReturn(result(SMS, 1)); when(store.getFolder(notNull(DataType.class), same(dataTypePreferences))).thenReturn(folder); task.doInBackground(config); verify(store).closeFolders(); }
@Test(expected = MessagingException.class) public void testMessageToContentValuesWithNullMessageThrowsMessagingException() throws Exception { messageConverter.messageToContentValues(null); }
MessageConverter converter = new MessageConverter(service, getPreferences(), getAuthPreferences().getUserEmail(),
switch (getDataType(message)) { case SMS: if (message.getBody() == null) throw new MessagingException("body is null"); throw new MessagingException("don't know how to restore " + getDataType(message));
@Test public void shouldHandleAuthErrorAndTokenCannotBeRefreshed() throws Exception { mockFetch(SMS, 1); when(converter.convertMessages(any(Cursor.class), notNull(DataType.class))).thenReturn(result(SMS, 1)); XOAuth2AuthenticationFailedException exception = mock(XOAuth2AuthenticationFailedException.class); when(exception.getStatus()).thenReturn(400); when(store.getFolder(notNull(DataType.class), same(dataTypePreferences))).thenThrow(exception); doThrow(new TokenRefreshException("failed")).when(tokenRefresher).refreshOAuth2Token(); task.doInBackground(config); verify(tokenRefresher, times(1)).refreshOAuth2Token(); verify(service).transition(SmsSyncState.ERROR, exception); // make sure locks only get acquired+released once verify(service).acquireLocks(); verify(service).releaseLocks(); }
private void importSms(final Message message) throws IOException, MessagingException { if (LOCAL_LOGV) Log.v(TAG, "importSms(" + message + ")"); final ContentValues values = converter.messageToContentValues(message); final Integer type = values.getAsInteger(Telephony.TextBasedSmsColumns.TYPE); // only restore inbox messages and sent messages - otherwise sms might get sent on restore if (type != null && (type == Telephony.TextBasedSmsColumns.MESSAGE_TYPE_INBOX || type == Telephony.TextBasedSmsColumns.MESSAGE_TYPE_SENT) && !smsExists(values)) { final Uri uri = resolver.insert(Consts.SMS_PROVIDER, values); if (uri != null) { smsIds.add(uri.getLastPathSegment()); Long timestamp = values.getAsLong(Telephony.TextBasedSmsColumns.DATE); if (timestamp != null && preferences.getDataTypePreferences().getMaxSyncedDate(SMS) < timestamp) { preferences.getDataTypePreferences().setMaxSyncedDate(SMS, timestamp); } if (LOCAL_LOGV) Log.v(TAG, "inserted " + uri); } } else { if (LOCAL_LOGV) Log.d(TAG, "ignoring sms"); } }
@Test public void shouldBackupMultipleTypes() throws Exception { mockFetch(SMS, 1); mockFetch(MMS, 2); when(store.getFolder(notNull(DataType.class), same(dataTypePreferences))).thenReturn(folder); when(converter.convertMessages(any(Cursor.class), any(DataType.class))).thenReturn(result(SMS, 1)); BackupState finalState = task.doInBackground(getBackupConfig(EnumSet.of(SMS, MMS))); assertThat(finalState.currentSyncedItems).isEqualTo(3); verify(folder, times(3)).appendMessages(anyListOf(Message.class)); }
@Test(expected = MessagingException.class) public void testMessageToContentValuesWithUnknownMessageTypeThrowsException() throws Exception { final String message = "Subject: Call with +12121\n" + "From: +12121 <+12121@unknown.email>\n" + "To: test@example.com\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain;\n" + " charset=utf-8\n" + "References: <3j20u1wmbcyik9lw0yaf8bfc.+12121@sms-backup-plus.local>\n" + "Message-ID: <5c0e190205376da44656936fd7d9900c@sms-backup-plus.local>\n" + "X-smssync-datatype: INVALID\n" + "Content-Transfer-Encoding: quoted-printable\n" + "\n" + "Some Text"; final MimeMessage mimeMessage = MimeMessage.parseMimeMessage(new ByteArrayInputStream(message.getBytes()), true); messageConverter.messageToContentValues(mimeMessage); }