mirror of https://github.com/moparisthebest/k-9
201 lines
6.5 KiB
Java
201 lines
6.5 KiB
Java
package com.fsck.k9.mailstore;
|
|
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.util.Stack;
|
|
|
|
import com.fsck.k9.mail.Body;
|
|
import com.fsck.k9.mail.BodyPart;
|
|
import com.fsck.k9.mail.Message;
|
|
import com.fsck.k9.mail.MessagingException;
|
|
import com.fsck.k9.mail.Multipart;
|
|
import com.fsck.k9.mail.Part;
|
|
import com.fsck.k9.mail.internet.MimeBodyPart;
|
|
import com.fsck.k9.mail.internet.MimeMessage;
|
|
import com.fsck.k9.mail.internet.MimeMultipart;
|
|
import com.fsck.k9.mail.internet.MimeUtility;
|
|
import org.apache.commons.io.IOUtils;
|
|
import org.apache.james.mime4j.MimeException;
|
|
import org.apache.james.mime4j.io.EOLConvertingInputStream;
|
|
import org.apache.james.mime4j.parser.ContentHandler;
|
|
import org.apache.james.mime4j.parser.MimeStreamParser;
|
|
import org.apache.james.mime4j.stream.BodyDescriptor;
|
|
import org.apache.james.mime4j.stream.Field;
|
|
import org.apache.james.mime4j.stream.MimeConfig;
|
|
|
|
|
|
public class DecryptStreamParser {
|
|
public static DecryptedBodyPart parse(Part multipartEncrypted, InputStream inputStream) throws MessagingException, IOException {
|
|
DecryptedBodyPart decryptedRootPart = new DecryptedBodyPart(multipartEncrypted);
|
|
|
|
MimeConfig parserConfig = new MimeConfig();
|
|
parserConfig.setMaxHeaderLen(-1);
|
|
parserConfig.setMaxLineLen(-1);
|
|
parserConfig.setMaxHeaderCount(-1);
|
|
|
|
MimeStreamParser parser = new MimeStreamParser(parserConfig);
|
|
parser.setContentHandler(new PartBuilder(multipartEncrypted, decryptedRootPart));
|
|
parser.setRecurse();
|
|
|
|
try {
|
|
parser.parse(new EOLConvertingInputStream(inputStream));
|
|
} catch (MimeException e) {
|
|
throw new MessagingException("Failed to parse decrypted content", e);
|
|
}
|
|
|
|
return decryptedRootPart;
|
|
}
|
|
|
|
private static Body createBody(InputStream inputStream, String transferEncoding) throws IOException {
|
|
//TODO: only read parts we're going to display into memory
|
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
try {
|
|
IOUtils.copy(inputStream, byteArrayOutputStream);
|
|
} finally {
|
|
byteArrayOutputStream.close();
|
|
}
|
|
|
|
byte[] data = byteArrayOutputStream.toByteArray();
|
|
|
|
return new BinaryMemoryBody(data, transferEncoding);
|
|
}
|
|
|
|
|
|
private static class PartBuilder implements ContentHandler {
|
|
private final Part multipartEncrypted;
|
|
private final DecryptedBodyPart decryptedRootPart;
|
|
private final Stack<Object> stack = new Stack<Object>();
|
|
|
|
public PartBuilder(Part multipartEncrypted, DecryptedBodyPart decryptedRootPart) throws MessagingException {
|
|
this.multipartEncrypted = multipartEncrypted;
|
|
this.decryptedRootPart = decryptedRootPart;
|
|
}
|
|
|
|
@Override
|
|
public void startMessage() throws MimeException {
|
|
if (stack.isEmpty()) {
|
|
stack.push(decryptedRootPart);
|
|
} else {
|
|
Part part = (Part) stack.peek();
|
|
|
|
Message innerMessage = new DecryptedMimeMessage(multipartEncrypted);
|
|
part.setBody(innerMessage);
|
|
|
|
stack.push(innerMessage);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void endMessage() throws MimeException {
|
|
stack.pop();
|
|
}
|
|
|
|
@Override
|
|
public void startBodyPart() throws MimeException {
|
|
try {
|
|
Multipart multipart = (Multipart) stack.peek();
|
|
|
|
BodyPart bodyPart = new DecryptedBodyPart(multipartEncrypted);
|
|
multipart.addBodyPart(bodyPart);
|
|
|
|
stack.push(bodyPart);
|
|
} catch (MessagingException e) {
|
|
throw new MimeException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void endBodyPart() throws MimeException {
|
|
stack.pop();
|
|
}
|
|
|
|
@Override
|
|
public void startHeader() throws MimeException {
|
|
// Do nothing
|
|
}
|
|
|
|
@Override
|
|
public void field(Field parsedField) throws MimeException {
|
|
try {
|
|
String name = parsedField.getName();
|
|
String raw = parsedField.getRaw().toString();
|
|
|
|
Part part = (Part) stack.peek();
|
|
part.addRawHeader(name, raw);
|
|
} catch (MessagingException e) {
|
|
throw new MimeException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void endHeader() throws MimeException {
|
|
// Do nothing
|
|
}
|
|
|
|
@Override
|
|
public void preamble(InputStream is) throws MimeException, IOException {
|
|
// Do nothing
|
|
}
|
|
|
|
@Override
|
|
public void epilogue(InputStream is) throws MimeException, IOException {
|
|
// Do nothing
|
|
}
|
|
|
|
@Override
|
|
public void startMultipart(BodyDescriptor bd) throws MimeException {
|
|
Part part = (Part) stack.peek();
|
|
try {
|
|
String contentType = part.getContentType();
|
|
String mimeType = MimeUtility.getHeaderParameter(contentType, null);
|
|
String boundary = MimeUtility.getHeaderParameter(contentType, "boundary");
|
|
|
|
MimeMultipart multipart = new MimeMultipart(mimeType, boundary);
|
|
part.setBody(multipart);
|
|
|
|
stack.push(multipart);
|
|
} catch (MessagingException e) {
|
|
throw new MimeException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void endMultipart() throws MimeException {
|
|
stack.pop();
|
|
}
|
|
|
|
@Override
|
|
public void body(BodyDescriptor bd, InputStream inputStream) throws MimeException, IOException {
|
|
Part part = (Part) stack.peek();
|
|
|
|
String transferEncoding = bd.getTransferEncoding();
|
|
Body body = createBody(inputStream, transferEncoding);
|
|
|
|
part.setBody(body);
|
|
}
|
|
|
|
@Override
|
|
public void raw(InputStream is) throws MimeException, IOException {
|
|
throw new IllegalStateException("Not implemented");
|
|
}
|
|
}
|
|
|
|
public static class DecryptedBodyPart extends MimeBodyPart {
|
|
private final Part multipartEncrypted;
|
|
|
|
public DecryptedBodyPart(Part multipartEncrypted) throws MessagingException {
|
|
this.multipartEncrypted = multipartEncrypted;
|
|
}
|
|
}
|
|
|
|
public static class DecryptedMimeMessage extends MimeMessage {
|
|
private final Part multipartEncrypted;
|
|
|
|
public DecryptedMimeMessage(Part multipartEncrypted) {
|
|
this.multipartEncrypted = multipartEncrypted;
|
|
}
|
|
}
|
|
}
|