git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1538353 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_10_FINAL
* http://search.cpan.org/dist/Convert-TNEF/ | * http://search.cpan.org/dist/Convert-TNEF/ | ||||
*/ | */ | ||||
public final class HMEFMessage { | public final class HMEFMessage { | ||||
public static final long HEADER_SIGNATURE = 0x223e9f78; | |||||
public static final int HEADER_SIGNATURE = 0x223e9f78; | |||||
private int fileId; | private int fileId; | ||||
private List<TNEFAttribute> messageAttributes = new ArrayList<TNEFAttribute>(); | private List<TNEFAttribute> messageAttributes = new ArrayList<TNEFAttribute>(); | ||||
public HMEFMessage(InputStream inp) throws IOException { | public HMEFMessage(InputStream inp) throws IOException { | ||||
// Check the signature matches | // Check the signature matches | ||||
long sig = LittleEndian.readInt(inp); | |||||
int sig = LittleEndian.readInt(inp); | |||||
if(sig != HEADER_SIGNATURE) { | if(sig != HEADER_SIGNATURE) { | ||||
throw new IllegalArgumentException( | throw new IllegalArgumentException( | ||||
"TNEF signature not detected in file, " + | "TNEF signature not detected in file, " + | ||||
fileId = LittleEndian.readUShort(inp); | fileId = LittleEndian.readUShort(inp); | ||||
// Now begin processing the contents | // 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); | |||||
messageAttributes.add(attr); | |||||
if (attr instanceof TNEFMAPIAttribute) { | |||||
TNEFMAPIAttribute tnefMAPI = (TNEFMAPIAttribute) attr; | |||||
mapiAttributes.addAll(tnefMAPI.getMAPIAttributes()); | |||||
} | } | ||||
} | |||||
void processAttachment(InputStream inp) throws IOException { | |||||
// Build the attribute | // Build the attribute | ||||
TNEFAttribute attr = TNEFAttribute.create(inp); | 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); | |||||
// Previous attachment or a new one? | |||||
if (attachments.isEmpty() | |||||
|| attr.getProperty() == TNEFProperty.ID_ATTACHRENDERDATA) { | |||||
attachments.add(new Attachment()); | |||||
} | } | ||||
// Handle the next one down | |||||
process(inp, level); | |||||
// Save the attribute for it | |||||
Attachment attach = attachments.get(attachments.size() - 1); | |||||
attach.addAttribute(attr); | |||||
} | } | ||||
/** | /** |
import java.util.List; | import java.util.List; | ||||
import org.apache.poi.hmef.HMEFMessage; | 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.MAPIAttribute; | ||||
import org.apache.poi.hmef.attribute.TNEFAttribute; | |||||
import org.apache.poi.hmef.attribute.TNEFDateAttribute; | import org.apache.poi.hmef.attribute.TNEFDateAttribute; | ||||
import org.apache.poi.hmef.attribute.TNEFProperty; | import org.apache.poi.hmef.attribute.TNEFProperty; | ||||
import org.apache.poi.hmef.attribute.TNEFStringAttribute; | import org.apache.poi.hmef.attribute.TNEFStringAttribute; | ||||
this.inp = inp; | this.inp = inp; | ||||
// Check the signature matches | // Check the signature matches | ||||
long sig = LittleEndian.readInt(inp); | |||||
int sig = LittleEndian.readInt(inp); | |||||
if(sig != HMEFMessage.HEADER_SIGNATURE) { | if(sig != HMEFMessage.HEADER_SIGNATURE) { | ||||
throw new IllegalArgumentException( | throw new IllegalArgumentException( | ||||
"TNEF signature not detected in file, " + | "TNEF signature not detected in file, " + |
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; | |||||
} | |||||
} | |||||
} |
package org.apache.poi.hmef; | 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.MAPIRtfAttribute; | ||||
import org.apache.poi.hmef.attribute.TNEFProperty; | import org.apache.poi.hmef.attribute.TNEFProperty; | ||||
import org.apache.poi.hsmf.datatypes.MAPIProperty; | import org.apache.poi.hsmf.datatypes.MAPIProperty; | ||||
// It's all low bytes | // It's all low bytes | ||||
byte[] contentsBytes = contents.getBytes("ASCII"); | byte[] contentsBytes = contents.getBytes("ASCII"); | ||||
assertContents("message.rtf", contentsBytes); | 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")); | |||||
} | |||||
} | } | ||||
} | } | ||||