void insertParts(MasterSecret masterSecret, long mmsId, PduBody body) throws MmsException { for (int i = 0; i < body.getPartsNum(); i++) { PduPart part = body.getPart(i); PartId partId = insertPart(masterSecret, part, mmsId, part.getThumbnail()); Log.w(TAG, "Inserted part at ID: " + partId); } }
private static PduPart constructPartFromUri(Context context, Uri uri) throws IOException, MediaTooLargeException { PduPart part = new PduPart(); ContentResolver resolver = context.getContentResolver(); Cursor cursor = null; try { cursor = resolver.query(uri, new String[] {MediaStore.Video.Media.MIME_TYPE}, null, null, null); if (cursor != null && cursor.moveToFirst()) { Log.w("VideoSlide", "Setting mime type: " + cursor.getString(0)); part.setContentType(cursor.getString(0).getBytes()); } } finally { if (cursor != null) cursor.close(); } if (getMediaSize(context, uri) > MAX_MESSAGE_SIZE) throw new MediaTooLargeException("Video exceeds maximum message size."); part.setDataUri(uri); part.setContentId((System.currentTimeMillis() + "").getBytes()); part.setName(("Video" + System.currentTimeMillis()).getBytes()); return part; }
public static PduPart constructPartFromUri(Context context, Uri uri) throws IOException, MediaTooLargeException { PduPart part = new PduPart(); assertMediaSize(context, uri, MmsMediaConstraints.MAX_MESSAGE_SIZE); Cursor cursor = null; try { cursor = context .getContentResolver() .query(uri, new String[] {Audio.Media.MIME_TYPE}, null, null, null); if (cursor != null && cursor.moveToFirst()) part.setContentType(cursor.getString(0).getBytes()); else throw new IOException("Unable to query content type."); } finally { if (cursor != null) cursor.close(); } part.setDataUri(uri); part.setContentId((System.currentTimeMillis() + "").getBytes()); part.setName(("Audio" + System.currentTimeMillis()).getBytes()); return part; }
private PartId insertPart(MasterSecret masterSecret, PduPart part, long mmsId, Bitmap thumbnail) throws MmsException { Log.w(TAG, "inserting part to mms " + mmsId); SQLiteDatabase database = databaseHelper.getWritableDatabase(); Pair<File, Long> partData = null; if (!part.isPendingPush()) { partData = writePartData(masterSecret, part); Log.w(TAG, "Wrote part to file: " + partData.first.getAbsolutePath()); } ContentValues contentValues = getContentValuesForPart(part); contentValues.put(MMS_ID, mmsId); if (partData != null) { contentValues.put(DATA, partData.first.getAbsolutePath()); contentValues.put(SIZE, partData.second); } long partRowId = database.insert(TABLE_NAME, null, contentValues); PartId partId = new PartId(partRowId, part.getUniqueId()); if (thumbnail != null) { Log.w(TAG, "inserting pre-generated thumbnail"); ThumbnailData data = new ThumbnailData(thumbnail); updatePartThumbnail(masterSecret, partId, part, data.toDataStream(), data.getAspectRatio()); } else if (!part.isPendingPush()) { thumbnailExecutor.submit(new ThumbnailFetchCallable(masterSecret, partId)); } return partId; }
private PduPart getPart(Cursor cursor) { PduPart part = new PduPart(); getPartValues(part, cursor); part.setDataUri(PartAuthority.getPartUri(part.getPartId())); return part; }
@Override public void onCanceled() { PartDatabase database = DatabaseFactory.getPartDatabase(context); List<PduPart> parts = database.getParts(messageId); for (PduPart part : parts) { markFailed(messageId, part, part.getPartId()); } }
private static PduPart constructPartFromUri(Uri uri) throws IOException, BitmapDecodingException { PduPart part = new PduPart(); part.setDataUri(uri); part.setContentType(ContentType.IMAGE_JPEG.getBytes()); part.setContentId((System.currentTimeMillis() + "").getBytes()); part.setName(("Image" + System.currentTimeMillis()).getBytes()); return part; }
@Override public void onRun(MasterSecret masterSecret) throws IOException { PartDatabase database = DatabaseFactory.getPartDatabase(context); Log.w(TAG, "Downloading push parts for: " + messageId); List<PduPart> parts = database.getParts(messageId); for (PduPart part : parts) { retrievePart(masterSecret, part, messageId); Log.w(TAG, "Got part: " + part.getPartId()); } }
public void updateFailedDownloadedPart(long messageId, PartId partId, PduPart part) throws MmsException { SQLiteDatabase database = databaseHelper.getWritableDatabase(); part.setContentDisposition(new byte[0]); part.setPendingPush(false); ContentValues values = getContentValuesForPart(part); values.put(DATA, (String) null); database.update(TABLE_NAME, values, PART_ID_WHERE, partId.toStrings()); notifyConversationListeners( DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId)); }
private Pair<File, Long> writePartData(MasterSecret masterSecret, PduPart part) throws MmsException { try { if (part.getData() != null) { Log.w(TAG, "Writing part data from buffer"); return writePartData(masterSecret, part, new ByteArrayInputStream(part.getData())); } else if (part.getDataUri() != null) { Log.w(TAG, "Writing part data from URI"); InputStream in = PartAuthority.getPartStream(context, masterSecret, part.getDataUri()); return writePartData(masterSecret, part, in); } else { throw new MmsException("Part is empty!"); } } catch (IOException e) { throw new MmsException(e); } }
private TextSecureAttachmentPointer createAttachmentPointer( MasterSecret masterSecret, PduPart part) throws InvalidPartException { try { MasterCipher masterCipher = new MasterCipher(masterSecret); long id = Long.parseLong(Util.toIsoString(part.getContentLocation())); byte[] key = masterCipher.decryptBytes(Base64.decode(Util.toIsoString(part.getContentDisposition()))); String relay = null; if (part.getName() != null) { relay = Util.toIsoString(part.getName()); } return new TextSecureAttachmentPointer(id, null, key, relay); } catch (InvalidMessageException | IOException e) { Log.w(TAG, e); throw new InvalidPartException(e); } }
private static PduBody pduBodyFor( MasterSecret masterSecret, List<TextSecureAttachment> attachments) { PduBody body = new PduBody(); for (TextSecureAttachment attachment : attachments) { if (attachment.isPointer()) { PduPart media = new PduPart(); byte[] encryptedKey = new MasterCipher(masterSecret).encryptBytes(attachment.asPointer().getKey()); media.setContentType(Util.toIsoBytes(attachment.getContentType())); media.setContentLocation(Util.toIsoBytes(String.valueOf(attachment.asPointer().getId()))); media.setContentDisposition(Util.toIsoBytes(Base64.encodeBytes(encryptedKey))); media.setPendingPush(true); body.addPart(media); } } return body; }
@Override public InputStream call() throws Exception { final InputStream stream = getDataStream(masterSecret, partId, THUMBNAIL); if (stream != null) { return stream; } try { PduPart part = getPart(partId); ThumbnailData data = MediaUtil.generateThumbnail( context, masterSecret, part.getDataUri(), Util.toIsoString(part.getContentType())); if (data == null) { return null; } updatePartThumbnail(masterSecret, partId, part, data.toDataStream(), data.getAspectRatio()); } catch (BitmapDecodingException bde) { throw new IOException(bde); } return getDataStream(masterSecret, partId, THUMBNAIL); }
public void updateDownloadedPart( MasterSecret masterSecret, long messageId, PartId partId, PduPart part, InputStream data) throws MmsException { SQLiteDatabase database = databaseHelper.getWritableDatabase(); Pair<File, Long> partData = writePartData(masterSecret, part, data); part.setContentDisposition(new byte[0]); part.setPendingPush(false); ContentValues values = getContentValuesForPart(part); if (partData != null) { values.put(DATA, partData.first.getAbsolutePath()); values.put(SIZE, partData.second); } database.update(TABLE_NAME, values, PART_ID_WHERE, partId.toStrings()); thumbnailExecutor.submit(new ThumbnailFetchCallable(masterSecret, partId)); notifyConversationListeners( DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId)); }
public void updatePartData(MasterSecret masterSecret, PduPart part, InputStream data) throws MmsException { SQLiteDatabase database = databaseHelper.getWritableDatabase(); Pair<File, Long> partData = writePartData(masterSecret, part, data); if (partData == null) throw new MmsException("couldn't update part data"); Cursor cursor = null; try { cursor = database.query( TABLE_NAME, new String[] {DATA}, PART_ID_WHERE, part.getPartId().toStrings(), null, null, null); if (cursor != null && cursor.moveToFirst()) { int dataColumn = cursor.getColumnIndexOrThrow(DATA); if (!cursor.isNull(dataColumn) && !new File(cursor.getString(dataColumn)).delete()) { Log.w(TAG, "Couldn't delete old part file"); } } } finally { if (cursor != null) cursor.close(); } ContentValues values = new ContentValues(2); values.put(DATA, partData.first.getAbsolutePath()); values.put(SIZE, partData.second); part.setDataSize(partData.second); database.update(TABLE_NAME, values, PART_ID_WHERE, part.getPartId().toStrings()); Log.w(TAG, "updated data for part #" + part.getPartId()); }
private void retrievePart(MasterSecret masterSecret, PduPart part, long messageId) throws IOException { PartDatabase database = DatabaseFactory.getPartDatabase(context); File attachmentFile = null; PartDatabase.PartId partId = part.getPartId(); try { attachmentFile = createTempFile(); TextSecureAttachmentPointer pointer = createAttachmentPointer(masterSecret, part); InputStream attachment = messageReceiver.retrieveAttachment(pointer, attachmentFile); database.updateDownloadedPart(masterSecret, messageId, partId, part, attachment); } catch (InvalidPartException | NonSuccessfulResponseCodeException | InvalidMessageException | MmsException e) { Log.w(TAG, e); markFailed(messageId, part, partId); } finally { if (attachmentFile != null) attachmentFile.delete(); } }
@Override public boolean onResourceReady( GlideDrawable resource, Object model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) { if (resource instanceof GlideBitmapDrawable) { Log.w(TAG, "onResourceReady() for a Bitmap. Saving."); part.setThumbnail(((GlideBitmapDrawable) resource).getBitmap()); } LayoutParams layoutParams = (LayoutParams) getRemoveButton().getLayoutParams(); if (resource.getIntrinsicWidth() < getWidth()) { layoutParams.topMargin = 0; layoutParams.rightMargin = Math.max(0, (getWidth() - image.getPaddingRight() - resource.getIntrinsicWidth()) / 2); } else { layoutParams.topMargin = Math.max(0, (getHeight() - image.getPaddingTop() - resource.getIntrinsicHeight()) / 2); layoutParams.rightMargin = 0; } getRemoveButton().setLayoutParams(layoutParams); return false; }
private void getPartValues(PduPart part, Cursor cursor) { part.setRowId(cursor.getLong(cursor.getColumnIndexOrThrow(ROW_ID))); part.setUniqueId(cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID))); int charsetColumn = cursor.getColumnIndexOrThrow(CHARSET); if (!cursor.isNull(charsetColumn)) part.setCharset(cursor.getInt(charsetColumn)); int contentTypeColumn = cursor.getColumnIndexOrThrow(CONTENT_TYPE); if (!cursor.isNull(contentTypeColumn)) part.setContentType(Util.toIsoBytes(cursor.getString(contentTypeColumn))); int nameColumn = cursor.getColumnIndexOrThrow(NAME); if (!cursor.isNull(nameColumn)) part.setName(Util.toIsoBytes(cursor.getString(nameColumn))); int fileNameColumn = cursor.getColumnIndexOrThrow(FILENAME); if (!cursor.isNull(fileNameColumn)) part.setFilename(Util.toIsoBytes(cursor.getString(fileNameColumn))); int contentDispositionColumn = cursor.getColumnIndexOrThrow(CONTENT_DISPOSITION); if (!cursor.isNull(contentDispositionColumn)) part.setContentDisposition(Util.toIsoBytes(cursor.getString(contentDispositionColumn))); int contentIdColumn = cursor.getColumnIndexOrThrow(CONTENT_ID); if (!cursor.isNull(contentIdColumn)) part.setContentId(Util.toIsoBytes(cursor.getString(contentIdColumn))); int contentLocationColumn = cursor.getColumnIndexOrThrow(CONTENT_LOCATION); if (!cursor.isNull(contentLocationColumn)) part.setContentLocation(Util.toIsoBytes(cursor.getString(contentLocationColumn))); int encryptedColumn = cursor.getColumnIndexOrThrow(ENCRYPTED); if (!cursor.isNull(encryptedColumn)) part.setEncrypted(cursor.getInt(encryptedColumn) == 1); int pendingPushColumn = cursor.getColumnIndexOrThrow(PENDING_PUSH_ATTACHMENT); if (!cursor.isNull(pendingPushColumn)) part.setPendingPush(cursor.getInt(pendingPushColumn) == 1); int sizeColumn = cursor.getColumnIndexOrThrow(SIZE); if (!cursor.isNull(sizeColumn)) part.setDataSize(cursor.getLong(cursor.getColumnIndexOrThrow(SIZE))); }
private ContentValues getContentValuesForPart(PduPart part) throws MmsException { ContentValues contentValues = new ContentValues(); if (part.getCharset() != 0) { contentValues.put(CHARSET, part.getCharset()); } if (part.getContentType() != null) { contentValues.put(CONTENT_TYPE, Util.toIsoString(part.getContentType())); if (Util.toIsoString(part.getContentType()).equals(ContentType.APP_SMIL)) { contentValues.put(SEQUENCE, -1); } } else { throw new MmsException("There is no content type for this part."); } if (part.getName() != null) { contentValues.put(NAME, new String(part.getName())); } if (part.getFilename() != null) { contentValues.put(FILENAME, new String(part.getFilename())); } if (part.getContentDisposition() != null) { contentValues.put(CONTENT_DISPOSITION, Util.toIsoString(part.getContentDisposition())); } if (part.getContentId() != null) { contentValues.put(CONTENT_ID, Util.toIsoString(part.getContentId())); } if (part.getContentLocation() != null) { contentValues.put(CONTENT_LOCATION, Util.toIsoString(part.getContentLocation())); } contentValues.put(ENCRYPTED, part.getEncrypted() ? 1 : 0); contentValues.put(PENDING_PUSH_ATTACHMENT, part.isPendingPush() ? 1 : 0); contentValues.put(UNIQUE_ID, part.getUniqueId()); return contentValues; }
protected OutputStream getPartOutputStream(MasterSecret masterSecret, File path, PduPart part) throws FileNotFoundException { Log.w(TAG, "Writing part to: " + path.getAbsolutePath()); part.setEncrypted(true); return new EncryptingPartOutputStream(path, masterSecret); }