From fd77fc1d74719d438e1260695605626b7bcd2daf Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Wed, 2 Mar 2011 17:52:12 +0000 Subject: [PATCH] Switch HMEF attributes to a factory scheme for creation, then add subtypes for cleaner code. Also adds a few more tests git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1076310 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/org/apache/poi/hmef/Attachment.java | 51 ++++++++++++-- .../src/org/apache/poi/hmef/HMEFMessage.java | 67 +++++++++++++------ .../poi/hmef/attribute/MAPIAttribute.java | 9 ++- .../poi/hmef/attribute/TNEFAttribute.java | 34 +++++++--- .../poi/hmef/attribute/TNEFMAPIAttribute.java | 52 ++++++++++++++ .../hmef/attribute/TNEFStringAttribute.java | 55 +++++++++++++++ .../org/apache/poi/hmef/dev/HMEFDumper.java | 15 ++++- .../org/apache/poi/hmef/TestAttachments.java | 60 +++++++++++++++++ .../org/apache/poi/hmef/TestHMEFMessage.java | 34 +++++----- .../hmef/attribute/TestMAPIAttributes.java | 42 ++++++++++++ .../hmef/attribute/TestTNEFAttributes.java | 43 ++++++++++++ 11 files changed, 408 insertions(+), 54 deletions(-) create mode 100644 src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFMAPIAttribute.java create mode 100644 src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFStringAttribute.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hmef/TestAttachments.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestMAPIAttributes.java create mode 100644 src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestTNEFAttributes.java diff --git a/src/scratchpad/src/org/apache/poi/hmef/Attachment.java b/src/scratchpad/src/org/apache/poi/hmef/Attachment.java index 1592941c5d..1d74ccc749 100644 --- a/src/scratchpad/src/org/apache/poi/hmef/Attachment.java +++ b/src/scratchpad/src/org/apache/poi/hmef/Attachment.java @@ -20,8 +20,11 @@ package org.apache.poi.hmef; import java.util.ArrayList; import java.util.List; -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.TNEFMAPIAttribute; +import org.apache.poi.hmef.attribute.TNEFProperty; +import org.apache.poi.hsmf.datatypes.MAPIProperty; /** @@ -33,21 +36,59 @@ public final class Attachment { private final List attributes = new ArrayList(); private final List mapiAttributes = new ArrayList(); - - protected void addAttribute(TNEFAttribute attr) { attributes.add(attr); + + if(attr instanceof TNEFMAPIAttribute) { + TNEFMAPIAttribute tnefMAPI = (TNEFMAPIAttribute)attr; + mapiAttributes.addAll( tnefMAPI.getMAPIAttributes() ); + } } - protected void addAttribute(MAPIAttribute attr) { - mapiAttributes.add(attr); + /** + * Return the attachment attribute with the given ID, + * or null if there isn't one. + */ + public TNEFAttribute getMessageAttribute(TNEFProperty id) { + for(TNEFAttribute attr : attributes) { + if(attr.getProperty() == id) { + return attr; + } + } + return null; } + /** + * Return the attachment MAPI Attribute with the given ID, + * or null if there isn't one. + */ + public MAPIAttribute getMessageMAPIAttribute(MAPIProperty id) { + for(MAPIAttribute attr : mapiAttributes) { + if(attr.getProperty() == id) { + return attr; + } + } + return null; + } + + /** + * Returns all HMEF/TNEF attributes of the attachment, + * such as filename, icon and contents + */ public List getAttributes() { return attributes; } + /** + * Returns all MAPI attributes of the attachment, + * such as extension, encoding, size and position + */ public List getMAPIAttributes() { return mapiAttributes; } + + public String getFilename() { + TNEFAttribute attr = null; + return null; + } } diff --git a/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java b/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java index 7b108b9df9..c23718ee68 100644 --- a/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java +++ b/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java @@ -23,7 +23,10 @@ import java.util.ArrayList; import java.util.List; import org.apache.poi.hmef.attribute.MAPIAttribute; +import org.apache.poi.hmef.attribute.MAPIRtfAttribute; +import org.apache.poi.hmef.attribute.MAPIStringAttribute; import org.apache.poi.hmef.attribute.TNEFAttribute; +import org.apache.poi.hmef.attribute.TNEFMAPIAttribute; import org.apache.poi.hmef.attribute.TNEFProperty; import org.apache.poi.hsmf.datatypes.MAPIProperty; import org.apache.poi.util.LittleEndian; @@ -59,24 +62,6 @@ public final class HMEFMessage { // Now begin processing the contents process(inp, 0); - - // Finally expand out the MAPI Attributes - for(TNEFAttribute attr : messageAttributes) { - if(attr.getProperty() == TNEFProperty.ID_MAPIPROPERTIES) { - mapiAttributes.addAll( - MAPIAttribute.create(attr) - ); - } - } - for(Attachment attachment : attachments) { - for(TNEFAttribute attr : attachment.getAttributes()) { - if(attr.getProperty()== TNEFProperty.ID_MAPIPROPERTIES) { - attachment.getMAPIAttributes().addAll( - MAPIAttribute.create(attr) - ); - } - } - } } private void process(InputStream inp, int lastLevel) throws IOException { @@ -87,11 +72,16 @@ public final class HMEFMessage { } // Build the attribute - TNEFAttribute attr = new TNEFAttribute(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) { @@ -99,7 +89,8 @@ public final class HMEFMessage { } // Save the attribute for it - attachments.get(attachments.size()-1).addAttribute(attr); + Attachment attach = attachments.get(attachments.size()-1); + attach.addAttribute(attr); } else { throw new IllegalStateException("Unhandled level " + level); } @@ -158,4 +149,40 @@ public final class HMEFMessage { } return null; } + + /** + * Return the string value of the mapi property, or null + * if it isn't set + */ + private String getString(MAPIProperty id) { + MAPIAttribute attr = getMessageMAPIAttribute(id); + if(id == null) { + return null; + } + if(attr instanceof MAPIStringAttribute) { + return ((MAPIStringAttribute)attr).getDataString(); + } + if(attr instanceof MAPIRtfAttribute) { + return ((MAPIRtfAttribute)attr).getDataString(); + } + + System.err.println("Warning, no string property found: " + attr.toString()); + return null; + } + + /** + * Returns the Message Subject, or null if the mapi property + * for this isn't set + */ + public String getSubject() { + return getString(MAPIProperty.CONVERSATION_TOPIC); + } + + /** + * Returns the Message Body, as RTF, or null if the mapi property + * for this isn't set + */ + public String getBody() { + return getString(MAPIProperty.RTF_COMPRESSED); + } } diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIAttribute.java index 4b1e3f732c..1ebd121144 100644 --- a/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIAttribute.java +++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/MAPIAttribute.java @@ -82,7 +82,14 @@ public class MAPIAttribute { * the list of MAPI Attributes contained within it */ public static List create(TNEFAttribute parent) throws IOException { - if(parent.getProperty() != TNEFProperty.ID_MAPIPROPERTIES) { + if(parent.getProperty() == TNEFProperty.ID_MAPIPROPERTIES) { + // Regular MAPI Properties, normally on the message + } + else if(parent.getProperty() == TNEFProperty.ID_ATTACHMENT) { + // MAPI Properties for an attachment + } + else { + // Something else, oh dear... throw new IllegalArgumentException( "Can only create from a MAPIProperty attribute, " + "instead received a " + parent.getProperty() + " one" diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFAttribute.java index 2ba783d232..b2152a5e34 100644 --- a/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFAttribute.java +++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFAttribute.java @@ -32,19 +32,18 @@ import org.apache.poi.util.LittleEndian; * Note - the types and IDs differ from standard Outlook/MAPI * ones, so we can't just re-use the HSMF ones. */ -public final class TNEFAttribute { +public class TNEFAttribute { private final TNEFProperty property; private final int type; private final byte[] data; private final int checksum; /** - * Constructs a single new attribute from - * the contents of the stream + * Constructs a single new attribute from the id, type, + * and the contents of the stream */ - public TNEFAttribute(InputStream inp) throws IOException { - int id = LittleEndian.readUShort(inp); - this.type = LittleEndian.readUShort(inp); + protected TNEFAttribute(int id, int type, InputStream inp) throws IOException { + this.type = type; int length = LittleEndian.readInt(inp); property = TNEFProperty.getBest(id, type); @@ -52,9 +51,26 @@ public final class TNEFAttribute { IOUtils.readFully(inp, data); checksum = LittleEndian.readUShort(inp); + } + + /** + * Creates a new TNEF Attribute by reading data from + * the stream within a {@link HMEFMessage} + */ + public static TNEFAttribute create(InputStream inp) throws IOException { + int id = LittleEndian.readUShort(inp); + int type = LittleEndian.readUShort(inp); - // TODO Handle the MapiProperties attribute in - // a different way, as we need to recurse into it + // Create as appropriate + if(id == TNEFProperty.ID_MAPIPROPERTIES.id || + id == TNEFProperty.ID_ATTACHMENT.id) { + return new TNEFMAPIAttribute(id, type, inp); + } + if(type == TNEFProperty.TYPE_STRING || + type == TNEFProperty.TYPE_TEXT) { + return new TNEFStringAttribute(id, type, inp); + } + return new TNEFAttribute(id, type, inp); } public TNEFProperty getProperty() { @@ -70,7 +86,7 @@ public final class TNEFAttribute { } public String toString() { - return "Attachment " + property.toString() + ", type=" + type + + return "Attribute " + property.toString() + ", type=" + type + ", data length=" + data.length; } } diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFMAPIAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFMAPIAttribute.java new file mode 100644 index 0000000000..3144981fee --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFMAPIAttribute.java @@ -0,0 +1,52 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hmef.attribute; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import org.apache.poi.hmef.Attachment; +import org.apache.poi.hmef.HMEFMessage; + +/** + * A TNEF Attribute holding MAPI Attributes, which applies to a + * {@link HMEFMessage} or one of its {@link Attachment}s. + */ +public final class TNEFMAPIAttribute extends TNEFAttribute { + private final List attributes; + + /** + * Constructs a single new mapi containing attribute from the + * id, type, and the contents of the stream + */ + protected TNEFMAPIAttribute(int id, int type, InputStream inp) throws IOException { + super(id, type, inp); + + attributes = MAPIAttribute.create(this); + } + + public List getMAPIAttributes() { + return attributes; + } + + public String toString() { + return "Attribute " + getProperty().toString() + ", type=" + getType() + + ", " + attributes.size() + " MAPI Attributes"; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFStringAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFStringAttribute.java new file mode 100644 index 0000000000..6063c5e2c0 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hmef/attribute/TNEFStringAttribute.java @@ -0,0 +1,55 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hmef.attribute; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.poi.hmef.Attachment; +import org.apache.poi.hmef.HMEFMessage; +import org.apache.poi.util.StringUtil; + +/** + * An String attribute which applies to a {@link HMEFMessage} + * or one of its {@link Attachment}s. + */ +public final class TNEFStringAttribute extends TNEFAttribute { + /** + * Constructs a single new string attribute from the id, type, + * and the contents of the stream + */ + protected TNEFStringAttribute(int id, int type, InputStream inp) throws IOException { + super(id, type, inp); + } + + public String getString() { + byte[] data = getData(); + // TODO Verify if these are the right way around + if(getType() == TNEFProperty.TYPE_TEXT) { + return StringUtil.getFromUnicodeLE(data); + } + return StringUtil.getFromCompressedUnicode( + data, 0, data.length + ); + } + + public String toString() { + return "Attribute " + getProperty().toString() + ", type=" + getType() + + ", data=" + getString(); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java b/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java index 26ecbf5239..e1ad196ee8 100644 --- a/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java +++ b/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java @@ -79,6 +79,7 @@ public final class HMEFDumper { private void dump() throws IOException { int level; + int attachments = 0; while(true) { // Fetch the level @@ -88,7 +89,16 @@ public final class HMEFDumper { } // Build the attribute - TNEFAttribute attr = new TNEFAttribute(inp); + TNEFAttribute attr = TNEFAttribute.create(inp); + + // Is it a new attachment? + if(level == TNEFProperty.LEVEL_ATTACHMENT && + attr.getProperty() == TNEFProperty.ID_ATTACHRENDERDATA) { + attachments++; + System.out.println(); + System.out.println("Attachment # " + attachments); + System.out.println(); + } // Print the attribute into System.out.println( @@ -125,7 +135,8 @@ public final class HMEFDumper { } System.out.println(); - if(attr.getProperty() == TNEFProperty.ID_MAPIPROPERTIES) { + if(attr.getProperty() == TNEFProperty.ID_MAPIPROPERTIES || + attr.getProperty() == TNEFProperty.ID_ATTACHMENT) { List attrs = MAPIAttribute.create(attr); for(MAPIAttribute ma : attrs) { System.out.println(indent + indent + ma); diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/TestAttachments.java b/src/scratchpad/testcases/org/apache/poi/hmef/TestAttachments.java new file mode 100644 index 0000000000..f5ddb8aeb0 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hmef/TestAttachments.java @@ -0,0 +1,60 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hmef; + +import junit.framework.TestCase; + +import org.apache.poi.POIDataSamples; + +public final class TestAttachments extends TestCase { + private static final POIDataSamples _samples = POIDataSamples.getHMEFInstance(); + + /** + * Check the file is as we expect + */ + public void testCounts() throws Exception { + HMEFMessage msg = new HMEFMessage( + _samples.openResourceAsStream("quick-winmail.dat") + ); + + // Should have 5 attachments + assertEquals(5, msg.getAttachments().size()); + } + + /** + * Check some basic bits about the attachments + */ + public void testBasicAttachments() throws Exception { + // TODO + } + + /** + * Query the attachments in detail, and check we see + * the right values for key things + */ + public void testAttachmentDetails() throws Exception { + // TODO + } + + /** + * Ensure the attachment contents come back as they should do + */ + public void testAttachmentContents() throws Exception { + // TODO + } +} diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java b/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java index b4542d4316..449b2722e0 100644 --- a/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java +++ b/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java @@ -20,8 +20,8 @@ package org.apache.poi.hmef; import junit.framework.TestCase; import org.apache.poi.POIDataSamples; -import org.apache.poi.hmef.attribute.TNEFAttribute; import org.apache.poi.hmef.attribute.TNEFProperty; +import org.apache.poi.util.LittleEndian; public final class TestHMEFMessage extends TestCase { private static final POIDataSamples _samples = POIDataSamples.getHMEFInstance(); @@ -56,13 +56,9 @@ public final class TestHMEFMessage extends TestCase { int mapiAttrCount = attach.getMAPIAttributes().size(); assertEquals(6, attrCount); - // TODO -// assertTrue("Should be 3-4 attributes, found " + mapiAttrCount, mapiAttrCount >= 20); -// assertTrue("Should be 3-4 attributes, found " + mapiAttrCount, mapiAttrCount <= 25); + assertTrue("Should be 20-25 mapi attributes, found " + mapiAttrCount, mapiAttrCount >= 20); + assertTrue("Should be 20-25 mapi attributes, found " + mapiAttrCount, mapiAttrCount <= 25); } - - - // TODO } public void testBasicMessageAttributes() throws Exception { @@ -88,18 +84,22 @@ public final class TestHMEFMessage extends TestCase { assertNull(msg.getMessageAttribute(TNEFProperty.ID_ATTACHDATA)); // Now check the details of one or two - // TODO + assertEquals( + 0x010000, + LittleEndian.getInt( msg.getMessageAttribute(TNEFProperty.ID_TNEFVERSION).getData() ) + ); + assertEquals( + "IPM.Microsoft Mail.Note\0", + new String(msg.getMessageAttribute(TNEFProperty.ID_MESSAGECLASS).getData(), "ASCII") + ); } public void testBasicMessageMAPIAttributes() throws Exception { - // TODO - } - - public void testBasicAttachments() throws Exception { - // TODO - } - - public void testMessageAttributeDetails() throws Exception { - // TODO + HMEFMessage msg = new HMEFMessage( + _samples.openResourceAsStream("quick-winmail.dat") + ); + + assertEquals("This is a test message", msg.getSubject()); + assertEquals("{\\rtf1", msg.getBody().substring(0, 6)); } } diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestMAPIAttributes.java b/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestMAPIAttributes.java new file mode 100644 index 0000000000..8ed7ba5b49 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestMAPIAttributes.java @@ -0,0 +1,42 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hmef.attribute; + +import junit.framework.TestCase; + +import org.apache.poi.POIDataSamples; +import org.apache.poi.hmef.HMEFMessage; + +public final class TestMAPIAttributes extends TestCase { + private static final POIDataSamples _samples = POIDataSamples.getHMEFInstance(); + + public void testOpen() throws Exception { + HMEFMessage msg = new HMEFMessage( + _samples.openResourceAsStream("quick-winmail.dat") + ); + + assertNotNull(msg); + } + + // Test basics + // Test counts + + // Check untyped + // Check typed + // Check common +} diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestTNEFAttributes.java b/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestTNEFAttributes.java new file mode 100644 index 0000000000..6096ba3f1b --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hmef/attribute/TestTNEFAttributes.java @@ -0,0 +1,43 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hmef.attribute; + +import junit.framework.TestCase; + +import org.apache.poi.POIDataSamples; +import org.apache.poi.hmef.HMEFMessage; + +public final class TestTNEFAttributes extends TestCase { + private static final POIDataSamples _samples = POIDataSamples.getHMEFInstance(); + + public void testOpen() throws Exception { + HMEFMessage msg = new HMEFMessage( + _samples.openResourceAsStream("quick-winmail.dat") + ); + + assertNotNull(msg); + } + + // Test counts + + // Test basics + + // Test string + + // Test a bit of mapi +} -- 2.39.5