Skip to content

Commit

Permalink
write attachment content-ID along when writing message to msg file. Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
lolo101 committed Sep 4, 2022
1 parent 00210fb commit 8f0a4eb
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

import javax.mail.*;
import javax.mail.Message.RecipientType;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimePart;
import javax.mail.internet.MimeUtility;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
Expand All @@ -20,6 +20,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.regex.Pattern;

public class JavaMailParser {
private static final Logger LOGGER = LogManager.getLogger(JavaMailParser.class);
Expand All @@ -29,6 +30,7 @@ public class JavaMailParser {
private static final RecipientHeader CC_PARSER = new CcHeader();
private static final RecipientHeader BCC_PARSER = new BccHeader();
private static final DateHeader DATE_PARSER = new DateHeader();
private static final Pattern CHARSET_PATTERN = Pattern.compile(".*;\\s*charset=.*");
private final Path file;

public JavaMailParser(Path file) {
Expand Down Expand Up @@ -104,7 +106,7 @@ private static void parse(Message msg, Part part) throws MessagingException, IOE
} else if (disp == null || disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE)) {
// many mailers don't include a Content-Disposition

MimeBodyPart mpart = (MimeBodyPart)part;
MimePart mpart = (MimePart) part;

FileAttachment att = new FileAttachment();
String filename = MimeUtility.decodeText(part.getFileName());
Expand Down Expand Up @@ -133,16 +135,15 @@ private static void parse(Message msg, Part part) throws MessagingException, IOE

private static String getCharset(String content)
{
if( content.matches(".*;\\s*charset=.*") )
{
if (CHARSET_PATTERN.matcher(content).matches()) {
int idx = content.indexOf('=');

String charset = content.substring(idx+1);
String charset = content.substring(idx + 1);

byte[] c = new byte[2];
c[0] = ' ';

charset = StringUtils.strip(charset,"\"");
charset = StringUtils.strip(charset, "\"");

try {
new String(c,charset);
Expand All @@ -157,16 +158,11 @@ private static String getCharset(String content)
return "ASCII";
}

private static byte[] getContent(Part mp) throws IOException, MessagingException
{
InputStream in = mp.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];

for (int len; (len = in.read(bytes)) > 0;) {
bos.write(bytes, 0, len);
private static byte[] getContent(Part mp) throws IOException, MessagingException {
ByteArrayOutputStream bos = new ByteArrayOutputStream(mp.getSize());
try (InputStream in = mp.getInputStream()) {
in.transferTo(bos);
}

return bos.toByteArray();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
import static org.apache.commons.lang3.StringUtils.isNotEmpty;

public class MsgContainer {
public static final String PROPERTY_STREAM = "__properties_version1.0";
public static final String NAMED_PROPERTY = "__nameid_version1.0";
private static final String PROPERTY_STREAM = "__properties_version1.0";
private static final String NAMED_PROPERTY = "__nameid_version1.0";

private final List<PropType> properties = new ArrayList<>();
private final List<SubStorageEntry> substg_streams = new ArrayList<>();
private final Collection<PropType> properties = new ArrayList<>();
private final Collection<SubStorageEntry> substg_streams = new ArrayList<>();

private final List<RecipientEntry> recipients = new ArrayList<>();
private final List<Attachment> attachments = new ArrayList<>();
Expand Down Expand Up @@ -218,7 +218,7 @@ private static void writeRecipientEntry(DirectoryEntry root, RecipientEntry rec,
entry.createEntry(rec_dir);
}

List<PropType> props = new ArrayList<>();
Collection<PropType> props = new ArrayList<>();
props.add(new PropPtypInteger32(PidTagRowid, id));
props.add(new PropPtypInteger32(PidTagRecipientType, rec.getType().getValue()));
for (SubStorageEntry entry : entries) {
Expand Down Expand Up @@ -246,7 +246,8 @@ private static void writeFileAttachment(FileAttachment attachment, DirectoryEntr
new StringUTF16SubstgEntry(PidTagAttachExtension, attachment.getExtension()),
new StringUTF16SubstgEntry(PidTagAttachFilename, attachment.getFilename()),
new StringUTF16SubstgEntry(PidTagAttachLongFilename, attachment.getLongFilename()),
new StringUTF16SubstgEntry(PidTagAttachMimeTag, attachment.getMimeTag())
new StringUTF16SubstgEntry(PidTagAttachMimeTag, attachment.getMimeTag()),
new StringUTF16SubstgEntry(PidTagAttachContentId, attachment.getContentId())
);

for (SubStorageEntry entry : entries) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,63 @@
import com.google.common.jimfs.Jimfs;
import net.sourceforge.MSGViewer.ModuleLauncher;
import net.sourceforge.MSGViewer.factory.MessageParser;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.junit.jupiter.api.Test;

import java.io.OutputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;

import static org.assertj.core.api.Assertions.assertThat;

class MsgWriterTest {

@Test
public void testWrite() throws Exception {
void testWrite() throws Exception {
ModuleLauncher.BaseConfigureLogging();

Path testOut = Jimfs.newFileSystem().getPath("test_out.mbox");
try (OutputStream outputStream = Files.newOutputStream(testOut)) {
Message msg = new MessageParser(Path.of("src/test/resources/danke.msg")).parseMessage();
new MsgWriter(msg).write(outputStream);
try (FileSystem fileSystem = Jimfs.newFileSystem()) {
Path testOut = fileSystem.getPath("test_out.msg");
try (OutputStream outputStream = Files.newOutputStream(testOut)) {
Message msg = givenMessage("/danke.msg");
new MsgWriter(msg).write(outputStream);
}
assertThat(Files.isRegularFile(testOut)).isTrue();
}
assertThat(Files.isRegularFile(testOut)).isTrue();
}

@Test
void issue129() throws Exception {
ModuleLauncher.BaseConfigureLogging();

try (FileSystem fileSystem = Jimfs.newFileSystem()) {
Path testOut = fileSystem.getPath("test_out.msg");
try (OutputStream outputStream = Files.newOutputStream(testOut)) {
Message msg = givenMessage("/issue129/test.eml");
new MsgWriter(msg).write(outputStream);
}

try (POIFSFileSystem fs = new POIFSFileSystem(Files.newInputStream(testOut))) {
DirectoryNode root = fs.getRoot();
DirectoryNode attachment = (DirectoryNode) root.getEntry("__attach_version1.0_#00000000");
DocumentEntry contentId = (DocumentEntry) attachment.getEntry("__substg1.0_3712001F");
try (DocumentInputStream stream = new DocumentInputStream(contentId)) {
String contentIdValue = new String(stream.readAllBytes(), StandardCharsets.UTF_16LE);
assertThat(contentIdValue).isEqualTo("part1.HRgTI02d.mjRZp5Gh@neuf.fr");
}
}
}
}

private static Message givenMessage(String name) throws Exception {
URI uri = Objects.requireNonNull(MsgWriterTest.class.getResource(name)).toURI();
return new MessageParser(Path.of(uri)).parseMessage();
}
}

0 comments on commit 8f0a4eb

Please # to comment.