Bug 52400: fix handling some types of TNEF files, make HMEFMessage.HEADER_SIGNATURE int as it is handled as int everywhere, move .dat files to HMEF sample dir, cover some border cases in HMEFMessage, add another .dat sample file

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1538353 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Dominik Stadler 2013-11-03 12:43:42 +00:00
parent 19630f1a29
commit 7014abae83
7 changed files with 179 additions and 35 deletions

View File

@ -39,7 +39,7 @@ import org.apache.poi.util.LittleEndian;
* http://search.cpan.org/dist/Convert-TNEF/
*/
public final class HMEFMessage {
public static final long HEADER_SIGNATURE = 0x223e9f78;
public static final int HEADER_SIGNATURE = 0x223e9f78;
private int fileId;
private List<TNEFAttribute> messageAttributes = new ArrayList<TNEFAttribute>();
@ -48,7 +48,7 @@ public final class HMEFMessage {
public HMEFMessage(InputStream inp) throws IOException {
// Check the signature matches
long sig = LittleEndian.readInt(inp);
int sig = LittleEndian.readInt(inp);
if(sig != HEADER_SIGNATURE) {
throw new IllegalArgumentException(
"TNEF signature not detected in file, " +
@ -60,42 +60,59 @@ public final class HMEFMessage {
fileId = LittleEndian.readUShort(inp);
// Now begin processing the contents
process(inp, 0);
process(inp);
}
private void process(InputStream inp, int lastLevel) throws IOException {
// Fetch the level
int level = inp.read();
if(level == TNEFProperty.LEVEL_END_OF_FILE) {
return;
}
private void process(InputStream inp) throws IOException {
int level;
do {
// Fetch the level
level = inp.read();
// Decide what to attach it to, based on the levels and IDs
switch (level) {
case TNEFProperty.LEVEL_MESSAGE:
processMessage(inp);
break;
case TNEFProperty.LEVEL_ATTACHMENT:
processAttachment(inp);
break;
// ignore trailing newline
case '\r':
case '\n':
case TNEFProperty.LEVEL_END_OF_FILE:
break;
default:
throw new IllegalStateException("Unhandled level " + level);
}
} while (level != TNEFProperty.LEVEL_END_OF_FILE);
}
void processMessage(InputStream inp) throws IOException {
// Build the attribute
TNEFAttribute attr = TNEFAttribute.create(inp);
// Decide what to attach it to, based on the levels and IDs
if(level == TNEFProperty.LEVEL_MESSAGE) {
messageAttributes.add(attr);
if(attr instanceof TNEFMAPIAttribute) {
TNEFMAPIAttribute tnefMAPI = (TNEFMAPIAttribute)attr;
mapiAttributes.addAll( tnefMAPI.getMAPIAttributes() );
}
} else if(level == TNEFProperty.LEVEL_ATTACHMENT) {
// Previous attachment or a new one?
if(attachments.size() == 0 || attr.getProperty() == TNEFProperty.ID_ATTACHRENDERDATA) {
attachments.add(new Attachment());
}
// Save the attribute for it
Attachment attach = attachments.get(attachments.size()-1);
attach.addAttribute(attr);
} else {
throw new IllegalStateException("Unhandled level " + level);
messageAttributes.add(attr);
if (attr instanceof TNEFMAPIAttribute) {
TNEFMAPIAttribute tnefMAPI = (TNEFMAPIAttribute) attr;
mapiAttributes.addAll(tnefMAPI.getMAPIAttributes());
}
// Handle the next one down
process(inp, level);
}
void processAttachment(InputStream inp) throws IOException {
// Build the attribute
TNEFAttribute attr = TNEFAttribute.create(inp);
// Previous attachment or a new one?
if (attachments.isEmpty()
|| attr.getProperty() == TNEFProperty.ID_ATTACHRENDERDATA) {
attachments.add(new Attachment());
}
// Save the attribute for it
Attachment attach = attachments.get(attachments.size() - 1);
attach.addAttribute(attr);
}
/**

View File

@ -23,8 +23,8 @@ import java.io.InputStream;
import java.util.List;
import org.apache.poi.hmef.HMEFMessage;
import org.apache.poi.hmef.attribute.TNEFAttribute;
import org.apache.poi.hmef.attribute.MAPIAttribute;
import org.apache.poi.hmef.attribute.TNEFAttribute;
import org.apache.poi.hmef.attribute.TNEFDateAttribute;
import org.apache.poi.hmef.attribute.TNEFProperty;
import org.apache.poi.hmef.attribute.TNEFStringAttribute;
@ -62,7 +62,7 @@ public final class HMEFDumper {
this.inp = inp;
// Check the signature matches
long sig = LittleEndian.readInt(inp);
int sig = LittleEndian.readInt(inp);
if(sig != HMEFMessage.HEADER_SIGNATURE) {
throw new IllegalArgumentException(
"TNEF signature not detected in file, " +

View File

@ -0,0 +1,48 @@
package org.apache.poi.hmef;
import junit.framework.TestCase;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hmef.attribute.MAPIAttribute;
import org.apache.poi.hmef.attribute.TNEFAttribute;
import org.apache.poi.hmef.attribute.TNEFProperty;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
import org.apache.poi.util.LittleEndian;
public class TestBugs extends TestCase {
public void test52400ReadSimpleTNEF() throws Exception {
POIDataSamples samples = POIDataSamples.getHMEFInstance();
String testFile = "bug52400-winmail-simple.dat";
HMEFMessage tnefDat = new HMEFMessage(samples.openResourceAsStream(testFile));
MAPIAttribute bodyHtml = tnefDat.getMessageMAPIAttribute(MAPIProperty.BODY_HTML);
String bodyStr = new String(bodyHtml.getData(), getEncoding(tnefDat));
assertTrue(bodyStr.contains("This is the message body."));
}
public void test52400ReadAttachedTNEF() throws Exception {
POIDataSamples samples = POIDataSamples.getHMEFInstance();
String testFile = "bug52400-winmail-with-attachments.dat";
HMEFMessage tnefDat = new HMEFMessage(samples.openResourceAsStream(testFile));
MAPIAttribute bodyHtml = tnefDat.getMessageMAPIAttribute(MAPIProperty.BODY_HTML);
String bodyStr = new String(bodyHtml.getData(), getEncoding(tnefDat));
assertTrue(bodyStr.contains("There are also two attachments."));
assertEquals(2, tnefDat.getAttachments().size());
}
private String getEncoding(HMEFMessage tnefDat) {
TNEFAttribute oemCP = tnefDat.getMessageAttribute(TNEFProperty.ID_OEMCODEPAGE);
MAPIAttribute cpId = tnefDat.getMessageMAPIAttribute(MAPIProperty.INTERNET_CPID);
int codePage = 1252;
if (oemCP != null) {
codePage = LittleEndian.getInt(oemCP.getData());
} else if (cpId != null) {
codePage = LittleEndian.getInt(cpId.getData());
}
switch (codePage) {
// see http://en.wikipedia.org/wiki/Code_page for more
case 1252: return "Windows-1252";
case 20127: return "US-ASCII";
default: return "cp"+codePage;
}
}
}

View File

@ -17,6 +17,10 @@
package org.apache.poi.hmef;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import org.apache.poi.hmef.attribute.MAPIRtfAttribute;
import org.apache.poi.hmef.attribute.TNEFProperty;
import org.apache.poi.hsmf.datatypes.MAPIProperty;
@ -119,5 +123,80 @@ public final class TestHMEFMessage extends HMEFTest {
// It's all low bytes
byte[] contentsBytes = contents.getBytes("ASCII");
assertContents("message.rtf", contentsBytes);
// try to get a message id that does not exist
assertNull(msg.getMessageMAPIAttribute(MAPIProperty.AB_DEFAULT_DIR));
}
public void testMessageSample1() throws Exception {
HMEFMessage msg = new HMEFMessage(
_samples.openResourceAsStream("winmail-sample1.dat"));
// Firstly by byte
MAPIRtfAttribute rtf = (MAPIRtfAttribute) msg
.getMessageMAPIAttribute(MAPIProperty.RTF_COMPRESSED);
// assertContents("message.rtf", rtf.getData());
assertNotNull(rtf);
// Then by String
String contents = msg.getBody();
//System.out.println(contents);
// It's all low bytes
byte[] contentsBytes = contents.getBytes("ASCII");
// assertContents("message.rtf", contentsBytes);
assertNotNull(contentsBytes);
assertNotNull(msg.getSubject());
assertNotNull(msg.getBody());
}
public void testInvalidMessage() throws Exception {
InputStream str = new ByteArrayInputStream(new byte[] {0, 0, 0, 0});
try {
assertNotNull(new HMEFMessage(str));
fail("Should catch an exception here");
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains("TNEF signature not detected in file, expected 574529400 but got 0"));
}
}
public void testNoData() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Header
LittleEndian.putInt(HMEFMessage.HEADER_SIGNATURE, out);
// field
LittleEndian.putUShort(0, out);
byte[] bytes = out.toByteArray();
InputStream str = new ByteArrayInputStream(bytes);
HMEFMessage msg = new HMEFMessage(str);
assertNull(msg.getSubject());
assertNull(msg.getBody());
}
public void testInvalidLevel() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Header
LittleEndian.putInt(HMEFMessage.HEADER_SIGNATURE, out);
// field
LittleEndian.putUShort(0, out);
// invalid level
LittleEndian.putUShort(90, out);
byte[] bytes = out.toByteArray();
InputStream str = new ByteArrayInputStream(bytes);
try {
assertNotNull(new HMEFMessage(str));
fail("Should catch an exception here");
} catch (IllegalStateException e) {
assertTrue(e.getMessage().contains("Unhandled level 90"));
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.