private void addChildrenToStack(Stack<PartContainer> stack, Part part, long parentMessageId) { Body body = part.getBody(); if (body instanceof Multipart) { Multipart multipart = (Multipart) body; for (int i = multipart.getCount() - 1; i >= 0; i--) { BodyPart childPart = multipart.getBodyPart(i); stack.push(new PartContainer(parentMessageId, childPart)); } } else if (body instanceof Message) { Message innerMessage = (Message) body; stack.push(new PartContainer(parentMessageId, innerMessage)); } }
public static boolean isCompletePartAvailable(Part part) { Stack<Part> partsToCheck = new Stack<>(); partsToCheck.push(part); while (!partsToCheck.isEmpty()) { Part currentPart = partsToCheck.pop(); Body body = currentPart.getBody(); boolean isBodyMissing = body == null; if (isBodyMissing) { return false; } if (body instanceof Multipart) { Multipart multipart = (Multipart) body; for (BodyPart bodyPart : multipart.getBodyParts()) { partsToCheck.push(bodyPart); } } } return true; }
private void multipartToContentValues(ContentValues cv, Multipart multipart) { cv.put("data_location", DataLocation.CHILD_PART_CONTAINS_DATA); cv.put("preamble", multipart.getPreamble()); cv.put("epilogue", multipart.getEpilogue()); cv.put("boundary", multipart.getBoundary()); }
@Override public void endMultipart() { expect(Multipart.class); Multipart multipart = (Multipart) stack.removeFirst(); boolean hasNoBodyParts = multipart.getCount() == 0; boolean hasNoEpilogue = multipart.getEpilogue() == null; if (hasNoBodyParts && hasNoEpilogue) { /* * The parser is calling startMultipart(), preamble(), and endMultipart() when all we have is * headers of a "multipart/*" part. But there's really no point in keeping a Multipart body if all * of the content is missing. */ expect(Part.class); Part part = (Part) stack.peek(); part.setBody(null); } }
if (multipart.getCount() > 0) { BodyPart bodyPart = multipart.getBodyPart(0); findViewablesAndAttachments(bodyPart, outputViewableParts, outputNonViewableParts); for (Part bodyPart : multipart.getBodyParts()) { findViewablesAndAttachments(bodyPart, outputViewableParts, outputNonViewableParts);
@Test public void migratePgpMimeEncryptedMessage() throws Exception { SQLiteDatabase db = createV50Database(); insertPgpMimeEncryptedMessage(db); db.close(); LocalStore localStore = DI.get(LocalStoreProvider.class).getInstance(account); LocalMessage msg = localStore.getFolder("dev").getMessage("6"); FetchProfile fp = new FetchProfile(); fp.add(FetchProfile.Item.BODY); localStore.getFolder("dev").fetch(Collections.singletonList(msg), fp, null); Assert.assertEquals(5, msg.getDatabaseId()); Assert.assertEquals(13, msg.getHeaderNames().size()); Assert.assertEquals("multipart/encrypted", msg.getMimeType()); Assert.assertEquals(2, msg.getAttachmentCount()); Multipart body = (Multipart) msg.getBody(); Assert.assertEquals(1, msg.getHeader(MimeHeader.HEADER_CONTENT_TYPE).length); Assert.assertEquals("application/pgp-encrypted", MimeUtility.getHeaderParameter(msg.getHeader(MimeHeader.HEADER_CONTENT_TYPE)[0], "protocol")); Assert.assertEquals("UoPmpPX/dBe4BELn", MimeUtility.getHeaderParameter(msg.getHeader(MimeHeader.HEADER_CONTENT_TYPE)[0], "boundary")); Assert.assertEquals("UoPmpPX/dBe4BELn", body.getBoundary()); Assert.assertEquals(2, body.getCount()); Assert.assertEquals("application/pgp-encrypted", body.getBodyPart(0).getMimeType()); Assert.assertEquals("application/octet-stream", body.getBodyPart(1).getMimeType()); }
public static byte[] getSignatureData(Part part) throws IOException, MessagingException { if (isPartMultipartSigned(part)) { Body body = part.getBody(); if (body instanceof Multipart) { Multipart multi = (Multipart) body; BodyPart signatureBody = multi.getBodyPart(1); ByteArrayOutputStream bos = new ByteArrayOutputStream(); signatureBody.getBody().writeTo(bos); return bos.toByteArray(); } } return null; }
@Test public void migrateHtmlWithRelatedMessage() throws Exception { SQLiteDatabase db = createV50Database(); insertHtmlWithRelatedMessage(db); db.close(); LocalStore localStore = DI.get(LocalStoreProvider.class).getInstance(account); LocalMessage msg = localStore.getFolder("dev").getMessage("10"); FetchProfile fp = new FetchProfile(); fp.add(FetchProfile.Item.BODY); localStore.getFolder("dev").fetch(Collections.singletonList(msg), fp, null); Assert.assertEquals(9, msg.getDatabaseId()); Assert.assertEquals(11, msg.getHeaderNames().size()); Assert.assertEquals("multipart/mixed", msg.getMimeType()); Assert.assertEquals(1, msg.getAttachmentCount()); Multipart msgBody = (Multipart) msg.getBody(); Assert.assertEquals("------------050707070308090509030605", msgBody.getBoundary()); Multipart multipartAlternativePart = (Multipart) msgBody.getBodyPart(0).getBody(); BodyPart htmlPart = multipartAlternativePart.getBodyPart(1); String msgTextContent = MessageExtractor.getTextFromPart(htmlPart); Assert.assertNotNull(msgTextContent); Assert.assertTrue(msgTextContent.contains("cid:part1.07090108.09020601@example.org")); Assert.assertEquals("image/jpeg", msgBody.getBodyPart(1).getMimeType()); }
public static void setBody(Part part, Body body) throws MessagingException { part.setBody(body); if (part instanceof Message) { part.setHeader("MIME-Version", "1.0"); } if (body instanceof Multipart) { Multipart multipart = ((Multipart) body); multipart.setParent(part); String contentType = Headers.contentTypeForMultipart(multipart.getMimeType(), multipart.getBoundary()); part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType); // note: if this is ever changed to 8bit, multipart/signed parts must always be 7bit! setEncoding(part, MimeUtil.ENC_7BIT); } else if (body instanceof TextBody) { MimeValue contentTypeHeader = MimeParameterDecoder.decode(part.getContentType()); String mimeType = contentTypeHeader.getValue(); if (MimeUtility.mimeTypeMatches(mimeType, "text/*")) { String name = contentTypeHeader.getParameters().get("name"); String contentType = Headers.contentType(mimeType, "utf-8", name); part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType); } else { part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType); } setEncoding(part, MimeUtil.ENC_QUOTED_PRINTABLE); } else if (body instanceof RawDataBody) { String encoding = ((RawDataBody) body).getEncoding(); part.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, encoding); } }
@Override public void startBodyPart() throws MimeException { try { Multipart multipart = (Multipart) stack.peek(); BodyPart bodyPart = new MimeBodyPart(); multipart.addBodyPart(bodyPart); stack.push(bodyPart); } catch (MessagingException e) { throw new MimeException(e); } }
@Test public void migrateTextHtml() throws Exception { SQLiteDatabase db = createV50Database(); insertMultipartAlternativeMessage(db); db.close(); LocalStore localStore = DI.get(LocalStoreProvider.class).getInstance(account); LocalMessage msg = localStore.getFolder("dev").getMessage("9"); FetchProfile fp = new FetchProfile(); fp.add(FetchProfile.Item.BODY); localStore.getFolder("dev").fetch(Collections.singletonList(msg), fp, null); Assert.assertEquals(8, msg.getDatabaseId()); Assert.assertEquals(9, msg.getHeaderNames().size()); Assert.assertEquals("multipart/alternative", msg.getMimeType()); Assert.assertEquals(0, msg.getAttachmentCount()); Multipart msgBody = (Multipart) msg.getBody(); Assert.assertEquals("------------060200010509000000040004", msgBody.getBoundary()); }
static Part getPart(Part searchRootPart, int... indexes) { Part part = searchRootPart; for (int index : indexes) { part = ((Multipart) part.getBody()).getBodyPart(index); } return part; } }
@Test public void buildCidMap__onMultipartWithEmptyBodyPart__shouldReturnEmptyMap() throws Exception { Multipart multipartBody = MimeMultipart.newInstance(); BodyPart bodyPart = spy(new MimeBodyPart()); Part multipartPart = new MimeBodyPart(multipartBody); multipartBody.addBodyPart(bodyPart); Map<String,Uri> result = AttachmentResolver.buildCidToAttachmentUriMap(attachmentInfoExtractor, multipartPart); verify(bodyPart).getContentId(); assertTrue(result.isEmpty()); }
public static List<Part> findMultipartEncryptedParts(Part startPart) { List<Part> encryptedParts = new ArrayList<>(); Stack<Part> partsToCheck = new Stack<>(); partsToCheck.push(startPart); while (!partsToCheck.isEmpty()) { Part part = partsToCheck.pop(); Body body = part.getBody(); if (isPartMultipartEncrypted(part)) { encryptedParts.add(part); continue; } if (body instanceof Multipart) { Multipart multipart = (Multipart) body; for (int i = multipart.getCount() - 1; i >= 0; i--) { BodyPart bodyPart = multipart.getBodyPart(i); partsToCheck.push(bodyPart); } } } return encryptedParts; }
/** * Traverse the MIME tree and add everything that's not a known text part to 'attachments'. * * @param multipart * The {@link Multipart} to start from. * @param knownTextParts * A set of known text parts we don't want to end up in 'attachments'. * @param attachments * A list that will receive the parts that are considered attachments. */ private static void findAttachments(Multipart multipart, Set<Part> knownTextParts, @NonNull List<Part> attachments) { for (Part part : multipart.getBodyParts()) { Body body = part.getBody(); if (body instanceof Multipart) { Multipart innerMultipart = (Multipart) body; findAttachments(innerMultipart, knownTextParts, attachments); } else if (!knownTextParts.contains(part)) { attachments.add(part); } } }
@Override public Long getSizeForProgress() { Part part = currentCryptoPart.part; CryptoPartType cryptoPartType = currentCryptoPart.type; Body body; if (cryptoPartType == CryptoPartType.PGP_ENCRYPTED) { Multipart multipartEncryptedMultipart = (Multipart) part.getBody(); BodyPart encryptionPayloadPart = multipartEncryptedMultipart.getBodyPart(1); body = encryptionPayloadPart.getBody(); } else if (cryptoPartType == CryptoPartType.PGP_INLINE) { body = part.getBody(); } else { throw new IllegalStateException("part to stream must be encrypted or inline!"); } if (body instanceof SizeAware) { return ((SizeAware) body).getSize(); } return null; }
if (MimeUtility.isMultipart(parentMimeType)) { BodyPart bodyPart = new LocalBodyPart(getAccountUuid(), message, id, size); ((Multipart) parentPart.getBody()).addBodyPart(bodyPart); part = bodyPart; } else if (MimeUtility.isMessage(parentMimeType)) {
public static List<Part> findPgpInlineParts(Part startPart) { List<Part> inlineParts = new ArrayList<>(); Stack<Part> partsToCheck = new Stack<>(); partsToCheck.push(startPart); while (!partsToCheck.isEmpty()) { Part part = partsToCheck.pop(); Body body = part.getBody(); if (isPartPgpInlineEncryptedOrSigned(part)) { inlineParts.add(part); continue; } if (body instanceof Multipart) { Multipart multipart = (Multipart) body; for (int i = multipart.getCount() - 1; i >= 0; i--) { BodyPart bodyPart = multipart.getBodyPart(i); partsToCheck.push(bodyPart); } } } return inlineParts; }
public static boolean hasMissingParts(Part part) { Body body = part.getBody(); if (body == null) { return true; } if (body instanceof Multipart) { Multipart multipart = (Multipart) body; for (Part subPart : multipart.getBodyParts()) { if (hasMissingParts(subPart)) { return true; } } } return false; }
@Override @WorkerThread public void writeTo(OutputStream os) throws IOException { try { Part part = currentCryptoPart.part; CryptoPartType cryptoPartType = currentCryptoPart.type; if (cryptoPartType == CryptoPartType.PGP_ENCRYPTED) { Multipart multipartEncryptedMultipart = (Multipart) part.getBody(); BodyPart encryptionPayloadPart = multipartEncryptedMultipart.getBodyPart(1); Body encryptionPayloadBody = encryptionPayloadPart.getBody(); encryptionPayloadBody.writeTo(os); } else if (cryptoPartType == CryptoPartType.PGP_INLINE) { String text = MessageExtractor.getTextFromPart(part); os.write(text.getBytes()); } else { throw new IllegalStateException("part to stream must be encrypted or inline!"); } } catch (MessagingException e) { Timber.e(e, "MessagingException while writing message to crypto provider"); } } };