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; }
BodyPart bodyPart = multipart.getBodyPart(0); findViewablesAndAttachments(bodyPart, outputViewableParts, outputNonViewableParts);
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; }
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 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; }
static Part getPart(Part searchRootPart, int... indexes) { Part part = searchRootPart; for (int index : indexes) { part = ((Multipart) part.getBody()).getBodyPart(index); } return part; } }
public static List<Part> findMultipartSignedParts(Part startPart, MessageCryptoAnnotations messageCryptoAnnotations) { List<Part> signedParts = new ArrayList<>(); Stack<Part> partsToCheck = new Stack<>(); partsToCheck.push(startPart); while (!partsToCheck.isEmpty()) { Part part = partsToCheck.pop(); if (messageCryptoAnnotations.has(part)) { CryptoResultAnnotation resultAnnotation = messageCryptoAnnotations.get(part); MimeBodyPart replacementData = resultAnnotation.getReplacementData(); if (replacementData != null) { part = replacementData; } } Body body = part.getBody(); if (isPartMultipartSigned(part)) { signedParts.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 signedParts; }
@Nullable private static Part findPrimaryPartInMixed(Part part, List<Part> outputExtraParts) { Body body = part.getBody(); boolean isMultipartMixed = part.isMimeType("multipart/mixed") && body instanceof Multipart; if (!isMultipartMixed) { return null; } Multipart multipart = (Multipart) body; if (multipart.getCount() == 0) { return null; } BodyPart firstBodyPart = multipart.getBodyPart(0); Part foundPart; if (isPartEncryptedOrSigned(firstBodyPart)) { foundPart = firstBodyPart; } else { foundPart = findPrimaryPartInAlternative(firstBodyPart); } if (foundPart != null && outputExtraParts != null) { for (int i = 1; i < multipart.getCount(); i++) { outputExtraParts.add(multipart.getBodyPart(i)); } } return foundPart; }
@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; }
@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"); } } };
private static Part findPrimaryPartInAlternative(Part part) { Body body = part.getBody(); if (part.isMimeType("multipart/alternative") && body instanceof Multipart) { Multipart multipart = (Multipart) body; if (multipart.getCount() == 0) { return null; } BodyPart firstBodyPart = multipart.getBodyPart(0); if (isPartPgpInlineEncryptedOrSigned(firstBodyPart)) { return firstBodyPart; } } return null; }
@Override public void writeTo(OutputStream os) throws IOException { try { Multipart multipartSignedMultipart = (Multipart) signedPart.getBody(); BodyPart signatureBodyPart = multipartSignedMultipart.getBodyPart(0); Timber.d("signed data type: %s", signatureBodyPart.getMimeType()); signatureBodyPart.writeTo(os); } catch (MessagingException e) { Timber.e(e, "Exception while writing message to crypto provider"); } } };
@Test public void migratePgpMimeSignedMessage() throws Exception { SQLiteDatabase db = createV50Database(); insertPgpMimeSignedMessage(db); db.close(); LocalStore localStore = DI.get(LocalStoreProvider.class).getInstance(account); LocalMessage msg = localStore.getFolder("dev").getMessage("5"); FetchProfile fp = new FetchProfile(); fp.add(FetchProfile.Item.BODY); localStore.getFolder("dev").fetch(Collections.singletonList(msg), fp, null); Assert.assertEquals(4, msg.getDatabaseId()); Assert.assertEquals(8, msg.getHeaderNames().size()); Assert.assertEquals("multipart/mixed", msg.getMimeType()); Assert.assertEquals(2, msg.getAttachmentCount()); Multipart body = (Multipart) msg.getBody(); Assert.assertEquals(3, body.getCount()); Assert.assertEquals("multipart/alternative", body.getBodyPart(0).getMimeType()); Assert.assertEquals("image/png", body.getBodyPart(1).getMimeType()); Assert.assertEquals("application/pgp-signature", body.getBodyPart(2).getMimeType()); }
@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()); }
@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()); }
Assert.assertEquals(3, body.getCount()); Assert.assertEquals("multipart/alternative", body.getBodyPart(0).getMimeType()); LocalBodyPart attachmentPart = (LocalBodyPart) body.getBodyPart(1); Assert.assertEquals("image/png", attachmentPart.getMimeType()); Assert.assertEquals("2", attachmentPart.getServerExtra()); Assert.assertEquals(MimeUtil.ENC_BINARY, attachmentBody.getEncoding()); Assert.assertEquals("application/whatevs", body.getBodyPart(2).getMimeType()); Assert.assertNull(body.getBodyPart(2).getBody());