From: Nick Burch Date: Wed, 2 Mar 2011 15:25:35 +0000 (+0000) Subject: Refactor the TNEF Attributes to better match the MAPI ones, and move both into their... X-Git-Tag: REL_3_8_BETA2~55 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ff0cd1cc2ee066136d7018d3a2cad78f153f9b58;p=poi.git Refactor the TNEF Attributes to better match the MAPI ones, and move both into their own package git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1076251 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/scratchpad/src/org/apache/poi/hmef/Attachment.java b/src/scratchpad/src/org/apache/poi/hmef/Attachment.java index a7c4d71f16..1592941c5d 100644 --- a/src/scratchpad/src/org/apache/poi/hmef/Attachment.java +++ b/src/scratchpad/src/org/apache/poi/hmef/Attachment.java @@ -20,15 +20,22 @@ 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; + /** - * An attachment within a {@link HMEFMessage} + * An attachment within a {@link HMEFMessage}. Provides both helper + * methods to get at common parts and attributes of the attachment, + * and list methods to get all of them. */ public final class Attachment { - private final List attributes = new ArrayList(); + private final List attributes = new ArrayList(); private final List mapiAttributes = new ArrayList(); - protected void addAttribute(Attribute attr) { + + + protected void addAttribute(TNEFAttribute attr) { attributes.add(attr); } @@ -36,7 +43,7 @@ public final class Attachment { mapiAttributes.add(attr); } - public List getAttributes() { + public List getAttributes() { return attributes; } diff --git a/src/scratchpad/src/org/apache/poi/hmef/Attribute.java b/src/scratchpad/src/org/apache/poi/hmef/Attribute.java deleted file mode 100644 index 8f7372ef1e..0000000000 --- a/src/scratchpad/src/org/apache/poi/hmef/Attribute.java +++ /dev/null @@ -1,262 +0,0 @@ -/* ==================================================================== - 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 java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.poi.util.IOUtils; -import org.apache.poi.util.LittleEndian; - - -/** - * An attribute which applies to a {@link HMEFMessage} - * or one of its {@link Attachment}s. - * Note - the types and IDs differ from standard Outlook/MAPI - * ones, so we can't just re-use the HSMF ones. - */ -public final class Attribute { - // Types taken from http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefattributetype%28v=EXCHG.140%29.aspx - public static final int TYPE_TRIPLES = 0x0000; - public static final int TYPE_STRING = 0x0001; - public static final int TYPE_TEXT = 0x0002; - public static final int TYPE_DATE = 0x0003; - public static final int TYPE_SHORT = 0x0004; - public static final int TYPE_LONG = 0x0005; - public static final int TYPE_BYTE = 0x0006; - public static final int TYPE_WORD = 0x0007; - public static final int TYPE_DWORD = 0x0008; - public static final int TYPE_MAX = 0x0009; - - // Types taken from http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefpropertytype%28v=EXCHG.140%29.aspx - /** AppTime - application time value */ - public static final int PTYPE_APPTIME = 0x0007; - /** Binary - counted byte array */ - public static final int PTYPE_BINARY = 0x0102; - /** Boolean - 16-bit Boolean value. '0' is false. Non-zero is true */ - public static final int PTYPE_BOOLEAN = 0x000B; - /** ClassId - OLE GUID */ - public static final int PTYPE_CLASSID = 0x0048; - /** Currency - signed 64-bit integer that represents a base ten decimal with four digits to the right of the decimal point */ - public static final int PTYPE_CURRENCY = 0x0006; - /** Double - floating point double */ - public static final int PTYPE_DOUBLE = 0x0005; - /** Error - 32-bit error value */ - public static final int PTYPE_ERROR = 0x000A; - /** I2 - signed 16-bit value */ - public static final int PTYPE_I2 = 0x0002; - /** I8 - 8-byte signed integer */ - public static final int PTYPE_I8 = 0x0014; - /** Long - signed 32-bit value */ - public static final int PTYPE_LONG = 0x0003; - /** MultiValued - Value part contains multiple values */ - public static final int PTYPE_MULTIVALUED = 0x1000; - /** Null - NULL property value */ - public static final int PTYPE_NULL = 0x0001; - /** Object - embedded object in a property */ - public static final int PTYPE_OBJECT = 0x000D; - /** R4 - 4-byte floating point value */ - public static final int PTYPE_R4 = 0x0004; - /** String8 - null-terminated 8-bit character string */ - public static final int PTYPE_STRING8 = 0x001E; - /** SysTime - FILETIME 64-bit integer specifying the number of 100ns periods since Jan 1, 1601 */ - public static final int PTYPE_SYSTIME = 0x0040; - /** Unicode - null-terminated Unicode string */ - public static final int PTYPE_UNICODE = 0x001F; - /** Unspecified */ - public static final int PTYPE_UNSPECIFIED = 0x0000; - - - // Levels taken from http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefattributelevel%28v=EXCHG.140%29.aspx - public static final int LEVEL_MESSAGE = 0x01; - public static final int LEVEL_ATTACHMENT = 0x02; - public static final int LEVEL_END_OF_FILE = -0x01; - - // ID information taken from http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefattributetag%28v=EXCHG.140%29.aspx - public static final AttributeID ID_AIDOWNER = - new AttributeID(0x0008, TYPE_LONG, "AidOwner", "PR_OWNER_APPT_ID"); - public static final AttributeID ID_ATTACHCREATEDATE = - new AttributeID(0x8012, TYPE_DATE, "AttachCreateDate", "PR_CREATION_TIME"); - public static final AttributeID ID_ATTACHDATA = - new AttributeID(0x800F, TYPE_BYTE, "AttachData", "PR_ATTACH_DATA_BIN"); - public static final AttributeID ID_ATTACHMENT = - new AttributeID(0x9005, TYPE_BYTE, "Attachment", null); - public static final AttributeID ID_ATTACHMETAFILE = - new AttributeID(0x8011, TYPE_BYTE, "AttachMetaFile", "PR_ATTACH_RENDERING"); - public static final AttributeID ID_ATTACHMODIFYDATE = - new AttributeID(0x8013, TYPE_DATE, "AttachModifyDate", "PR_LAST_MODIFICATION_TIME"); - public static final AttributeID ID_ATTACHRENDERDATA = - new AttributeID(0x9002, TYPE_BYTE, "AttachRenderData", "attAttachRenddata"); - public static final AttributeID ID_ATTACHTITLE = - new AttributeID(0x8010, TYPE_STRING, "AttachTitle", "PR_ATTACH_FILENAME"); - public static final AttributeID ID_ATTACHTRANSPORTFILENAME = - new AttributeID(0x9001, TYPE_BYTE, "AttachTransportFilename", "PR_ATTACH_TRANSPORT_NAME"); - public static final AttributeID ID_BODY = - new AttributeID(0x800C, TYPE_TEXT, "Body", "PR_BODY"); - public static final AttributeID ID_CONVERSATIONID = - new AttributeID(0x800B, TYPE_STRING, "ConversationId", "PR_CONVERSATION_KEY"); - public static final AttributeID ID_DATEEND = - new AttributeID(0x0007, TYPE_DATE, "DateEnd", "PR_END_DATE"); - public static final AttributeID ID_DATEMODIFIED = - new AttributeID(0x8020, TYPE_DATE, "DateModified", "PR_LAST_MODIFICATION_TIME "); - public static final AttributeID ID_DATERECEIVED = - new AttributeID(0x8006, TYPE_DATE, "DateReceived", "PR_MESSAGE_DELIVERY_TIME "); - public static final AttributeID ID_DATESENT = - new AttributeID(0x8005, TYPE_DATE, "DateSent", "PR_CLIENT_SUBMIT_TIME "); - public static final AttributeID ID_DATESTART = - new AttributeID(0x0006, TYPE_DATE, "DateStart", "PR_START_DATE "); - public static final AttributeID ID_DELEGATE = - new AttributeID(0x0002, TYPE_BYTE, "Delegate", "PR_RCVD_REPRESENTING_xxx "); - public static final AttributeID ID_FROM = - new AttributeID(0x8000, TYPE_STRING, "From", "PR_SENDER_ENTRYID"); - public static final AttributeID ID_MAPIPROPERTIES = - new AttributeID(0x9003, TYPE_BYTE, "MapiProperties", null); - public static final AttributeID ID_MESSAGECLASS = - new AttributeID(0x8008, TYPE_WORD, "MessageClass", "PR_MESSAGE_CLASS "); - public static final AttributeID ID_MESSAGEID = - new AttributeID(0x8009, TYPE_STRING, "MessageId", "PR_SEARCH_KEY"); - public static final AttributeID ID_MESSAGESTATUS = - new AttributeID(0x8007, TYPE_BYTE, "MessageStatus", "PR_MESSAGE_FLAGS"); - public static final AttributeID ID_NULL = - new AttributeID(0x0000, -1, "Null", null); - public static final AttributeID ID_OEMCODEPAGE = - new AttributeID(0x9007, TYPE_BYTE, "OemCodepage", "AttOemCodepage"); - public static final AttributeID ID_ORIGINALMESSAGECLASS = - new AttributeID(0x0006, TYPE_WORD, "OriginalMessageClass", "PR_ORIG_MESSAGE_CLASS"); - public static final AttributeID ID_OWNER = - new AttributeID(0x0000, TYPE_BYTE, "Owner", "PR_RCVD_REPRESENTING_xxx"); - public static final AttributeID ID_PARENTID = - new AttributeID(0x800A, TYPE_STRING, "ParentId", "PR_PARENT_KEY"); - public static final AttributeID ID_PRIORITY = - new AttributeID(0x800D, TYPE_SHORT, "Priority", "PR_IMPORTANCE"); - public static final AttributeID ID_RECIPIENTTABLE = - new AttributeID(0x9004, TYPE_BYTE, "RecipientTable", "PR_MESSAGE_RECIPIENTS"); - public static final AttributeID ID_REQUESTRESPONSE = - new AttributeID(0x009, TYPE_SHORT, "RequestResponse", "PR_RESPONSE_REQUESTED"); - public static final AttributeID ID_SENTFOR = - new AttributeID(0x0001, TYPE_BYTE, "SentFor", "PR_SENT_REPRESENTING_xxx"); - public static final AttributeID ID_SUBJECT = - new AttributeID(0x8004, TYPE_STRING, "Subject", "PR_SUBJECT"); - public static final AttributeID ID_TNEFVERSION = - new AttributeID(0x9006, TYPE_DWORD, "TnefVersion", "attTnefVersion"); - public static final AttributeID ID_UNKNOWN = - new AttributeID(-1, -1, "Unknown", null); - - /** - * Holds information on one potential ID of an - * attribute, and provides handy lookups for it. - */ - public static class AttributeID { - private static Map> attributes = new HashMap>(); - - public final int id; - public final int usualType; - public final String name; - public final String mapiProperty; - - private AttributeID(int id, int usualType, String name, String mapiProperty) { - this.id = id; - this.usualType = usualType; - this.name = name; - this.mapiProperty = mapiProperty; - - // Store it for lookup - if(! attributes.containsKey(id)) { - attributes.put(id, new ArrayList()); - } - attributes.get(id).add(this); - } - public static AttributeID getBest(int id, int type) { - List attrs = attributes.get(id); - if(attrs == null) { - return ID_UNKNOWN; - } - - // If there's only one, it's easy - if(attrs.size() == 1) { - return attrs.get(0); - } - - // Try by type - for(AttributeID attr : attrs) { - if(attr.usualType == type) return attr; - } - - // Go for the first if we can't otherwise decide... - return attrs.get(0); - } - public String toString() { - StringBuffer str = new StringBuffer(); - str.append(name); - str.append(" ["); - str.append(id); - str.append("]"); - if(mapiProperty != null) { - str.append(" ("); - str.append(mapiProperty); - str.append(")"); - } - return str.toString(); - } - } - - private final AttributeID id; - private final int type; - private final byte[] data; - private final int checksum; - - /** - * Constructs a single new attribute from - * the contents of the stream - */ - public Attribute(InputStream inp) throws IOException { - int id = LittleEndian.readUShort(inp); - this.type = LittleEndian.readUShort(inp); - int length = LittleEndian.readInt(inp); - - this.id = AttributeID.getBest(id, type); - data = new byte[length]; - IOUtils.readFully(inp, data); - - checksum = LittleEndian.readUShort(inp); - - // TODO Handle the MapiProperties attribute in - // a different way, as we need to recurse into it - } - - public AttributeID getId() { - return id; - } - - public int getType() { - return type; - } - - public byte[] getData() { - return data; - } - - public String toString() { - return "Attachment " + getId().toString() + ", type=" + type + - ", data length=" + data.length; - } -} diff --git a/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java b/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java index d74bcbefae..7b108b9df9 100644 --- a/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java +++ b/src/scratchpad/src/org/apache/poi/hmef/HMEFMessage.java @@ -22,7 +22,9 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; -import org.apache.poi.hmef.Attribute.AttributeID; +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; @@ -38,7 +40,7 @@ public final class HMEFMessage { public static final long HEADER_SIGNATURE = 0x223e9f78; private int fileId; - private List messageAttributes = new ArrayList(); + private List messageAttributes = new ArrayList(); private List mapiAttributes = new ArrayList(); private List attachments = new ArrayList(); @@ -59,16 +61,16 @@ public final class HMEFMessage { process(inp, 0); // Finally expand out the MAPI Attributes - for(Attribute attr : messageAttributes) { - if(attr.getId() == Attribute.ID_MAPIPROPERTIES) { + for(TNEFAttribute attr : messageAttributes) { + if(attr.getProperty() == TNEFProperty.ID_MAPIPROPERTIES) { mapiAttributes.addAll( MAPIAttribute.create(attr) ); } } for(Attachment attachment : attachments) { - for(Attribute attr : attachment.getAttributes()) { - if(attr.getId() == Attribute.ID_MAPIPROPERTIES) { + for(TNEFAttribute attr : attachment.getAttributes()) { + if(attr.getProperty()== TNEFProperty.ID_MAPIPROPERTIES) { attachment.getMAPIAttributes().addAll( MAPIAttribute.create(attr) ); @@ -80,19 +82,19 @@ public final class HMEFMessage { private void process(InputStream inp, int lastLevel) throws IOException { // Fetch the level int level = inp.read(); - if(level == Attribute.LEVEL_END_OF_FILE) { + if(level == TNEFProperty.LEVEL_END_OF_FILE) { return; } // Build the attribute - Attribute attr = new Attribute(inp); + TNEFAttribute attr = new TNEFAttribute(inp); // Decide what to attach it to, based on the levels and IDs - if(level == Attribute.LEVEL_MESSAGE) { + if(level == TNEFProperty.LEVEL_MESSAGE) { messageAttributes.add(attr); - } else if(level == Attribute.LEVEL_ATTACHMENT) { + } else if(level == TNEFProperty.LEVEL_ATTACHMENT) { // Previous attachment or a new one? - if(attachments.size() == 0 || attr.getId() == Attribute.ID_ATTACHRENDERDATA) { + if(attachments.size() == 0 || attr.getProperty() == TNEFProperty.ID_ATTACHRENDERDATA) { attachments.add(new Attachment()); } @@ -111,7 +113,7 @@ public final class HMEFMessage { * Note - In a typical message, most of the interesting properties * are stored as {@link MAPIAttribute}s - see {@link #getMessageMAPIAttributes()} */ - public List getMessageAttributes() { + public List getMessageAttributes() { return messageAttributes; } @@ -135,9 +137,9 @@ public final class HMEFMessage { * Return the message attribute with the given ID, * or null if there isn't one. */ - public Attribute getMessageAttribute(AttributeID id) { - for(Attribute attr : messageAttributes) { - if(attr.getId() == id) { + public TNEFAttribute getMessageAttribute(TNEFProperty id) { + for(TNEFAttribute attr : messageAttributes) { + if(attr.getProperty() == id) { return attr; } } diff --git a/src/scratchpad/src/org/apache/poi/hmef/MAPIAttribute.java b/src/scratchpad/src/org/apache/poi/hmef/MAPIAttribute.java deleted file mode 100644 index d8922213b1..0000000000 --- a/src/scratchpad/src/org/apache/poi/hmef/MAPIAttribute.java +++ /dev/null @@ -1,208 +0,0 @@ -/* ==================================================================== - 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 java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -import org.apache.poi.hsmf.datatypes.MAPIProperty; -import org.apache.poi.hsmf.datatypes.Types; -import org.apache.poi.util.HexDump; -import org.apache.poi.util.IOUtils; -import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.StringUtil; - -/** - * A pure-MAPI attribute which applies to a {@link HMEFMessage} - * or one of its {@link Attachment}s. - */ -public class MAPIAttribute { - private final MAPIProperty property; - private final int type; - private final byte[] data; - - /** - * Constructs a single new attribute from - * the contents of the stream - */ - public MAPIAttribute(MAPIProperty property, int type, byte[] data) { - this.property = property; - this.type = type; - this.data = data; - } - - public MAPIProperty getProperty() { - return property; - } - - public int getType() { - return type; - } - - public byte[] getData() { - return data; - } - - public String toString() { - String hex; - if(data.length <= 16) { - hex = HexDump.toHex(data); - } else { - byte[] d = new byte[16]; - System.arraycopy(data, 0, d, 0, 16); - hex = HexDump.toHex(d); - hex = hex.substring(0, hex.length()-1) + ", ....]"; - } - - return property.toString() + " " + hex; - } - - /** - * Parses a MAPI Properties TNEF Attribute, and returns - * the list of MAPI Attributes contained within it - */ - public static List create(Attribute parent) throws IOException { - if(parent.getId() != Attribute.ID_MAPIPROPERTIES) { - throw new IllegalArgumentException( - "Can only create from a MAPIProperty attribute, " + - "instead received a " + parent.getId() + " one" - ); - } - ByteArrayInputStream inp = new ByteArrayInputStream(parent.getData()); - - // First up, get the number of attributes - int count = LittleEndian.readInt(inp); - List attrs = new ArrayList(); - - // Now, read each one in in turn - for(int i=0; i 0 ) { - isMV = true; - type -= Types.MULTIVALUED_FLAG; - } - if(type == Types.ASCII_STRING || type == Types.UNICODE_STRING || - type == Types.BINARY || type == Types.DIRECTORY) { - isVL = true; - } - - // If it's a named property, rather than a standard - // MAPI property, grab the details of it - MAPIProperty prop = MAPIProperty.get(id); - if(id >= 0x8000 && id <= 0xFFFF) { - byte[] guid = new byte[16]; - IOUtils.readFully(inp, guid); - int mptype = LittleEndian.readInt(inp); - - // Get the name of it - String name; - if(mptype == 0) { - // It's based on a normal one - int mpid = LittleEndian.readInt(inp); - MAPIProperty base = MAPIProperty.get(mpid); - name = base.name; - } else { - // Custom name was stored - int mplen = LittleEndian.readInt(inp); - byte[] mpdata = new byte[mplen]; - IOUtils.readFully(inp, mpdata); - name = StringUtil.getFromUnicodeLE(mpdata, 0, (mplen/2)-1); - skipToBoundary(mplen, inp); - } - - // Now create - prop = MAPIProperty.createCustom(id, type, name); - } - if(prop == MAPIProperty.UNKNOWN) { - prop = MAPIProperty.createCustom(id, type, "(unknown " + Integer.toHexString(id) + ")"); - } - - // Now read in the value(s) - int values = 1; - if(isMV || isVL) { - values = LittleEndian.readInt(inp); - } - for(int j=0; j create(TNEFAttribute parent) throws IOException { + if(parent.getProperty() != TNEFProperty.ID_MAPIPROPERTIES) { + throw new IllegalArgumentException( + "Can only create from a MAPIProperty attribute, " + + "instead received a " + parent.getProperty() + " one" + ); + } + ByteArrayInputStream inp = new ByteArrayInputStream(parent.getData()); + + // First up, get the number of attributes + int count = LittleEndian.readInt(inp); + List attrs = new ArrayList(); + + // Now, read each one in in turn + for(int i=0; i 0 ) { + isMV = true; + type -= Types.MULTIVALUED_FLAG; + } + if(type == Types.ASCII_STRING || type == Types.UNICODE_STRING || + type == Types.BINARY || type == Types.DIRECTORY) { + isVL = true; + } + + // If it's a named property, rather than a standard + // MAPI property, grab the details of it + MAPIProperty prop = MAPIProperty.get(id); + if(id >= 0x8000 && id <= 0xFFFF) { + byte[] guid = new byte[16]; + IOUtils.readFully(inp, guid); + int mptype = LittleEndian.readInt(inp); + + // Get the name of it + String name; + if(mptype == 0) { + // It's based on a normal one + int mpid = LittleEndian.readInt(inp); + MAPIProperty base = MAPIProperty.get(mpid); + name = base.name; + } else { + // Custom name was stored + int mplen = LittleEndian.readInt(inp); + byte[] mpdata = new byte[mplen]; + IOUtils.readFully(inp, mpdata); + name = StringUtil.getFromUnicodeLE(mpdata, 0, (mplen/2)-1); + skipToBoundary(mplen, inp); + } + + // Now create + prop = MAPIProperty.createCustom(id, type, name); + } + if(prop == MAPIProperty.UNKNOWN) { + prop = MAPIProperty.createCustom(id, type, "(unknown " + Integer.toHexString(id) + ")"); + } + + // Now read in the value(s) + int values = 1; + if(isMV || isVL) { + values = LittleEndian.readInt(inp); + } + for(int j=0; j> properties = new HashMap>(); + + // Types taken from http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefattributetype%28v=EXCHG.140%29.aspx + public static final int TYPE_TRIPLES = 0x0000; + public static final int TYPE_STRING = 0x0001; + public static final int TYPE_TEXT = 0x0002; + public static final int TYPE_DATE = 0x0003; + public static final int TYPE_SHORT = 0x0004; + public static final int TYPE_LONG = 0x0005; + public static final int TYPE_BYTE = 0x0006; + public static final int TYPE_WORD = 0x0007; + public static final int TYPE_DWORD = 0x0008; + public static final int TYPE_MAX = 0x0009; + + // Types taken from http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefpropertytype%28v=EXCHG.140%29.aspx + /** AppTime - application time value */ + public static final int PTYPE_APPTIME = 0x0007; + /** Binary - counted byte array */ + public static final int PTYPE_BINARY = 0x0102; + /** Boolean - 16-bit Boolean value. '0' is false. Non-zero is true */ + public static final int PTYPE_BOOLEAN = 0x000B; + /** ClassId - OLE GUID */ + public static final int PTYPE_CLASSID = 0x0048; + /** Currency - signed 64-bit integer that represents a base ten decimal with four digits to the right of the decimal point */ + public static final int PTYPE_CURRENCY = 0x0006; + /** Double - floating point double */ + public static final int PTYPE_DOUBLE = 0x0005; + /** Error - 32-bit error value */ + public static final int PTYPE_ERROR = 0x000A; + /** I2 - signed 16-bit value */ + public static final int PTYPE_I2 = 0x0002; + /** I8 - 8-byte signed integer */ + public static final int PTYPE_I8 = 0x0014; + /** Long - signed 32-bit value */ + public static final int PTYPE_LONG = 0x0003; + /** MultiValued - Value part contains multiple values */ + public static final int PTYPE_MULTIVALUED = 0x1000; + /** Null - NULL property value */ + public static final int PTYPE_NULL = 0x0001; + /** Object - embedded object in a property */ + public static final int PTYPE_OBJECT = 0x000D; + /** R4 - 4-byte floating point value */ + public static final int PTYPE_R4 = 0x0004; + /** String8 - null-terminated 8-bit character string */ + public static final int PTYPE_STRING8 = 0x001E; + /** SysTime - FILETIME 64-bit integer specifying the number of 100ns periods since Jan 1, 1601 */ + public static final int PTYPE_SYSTIME = 0x0040; + /** Unicode - null-terminated Unicode string */ + public static final int PTYPE_UNICODE = 0x001F; + /** Unspecified */ + public static final int PTYPE_UNSPECIFIED = 0x0000; + + + // Levels taken from http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefattributelevel%28v=EXCHG.140%29.aspx + public static final int LEVEL_MESSAGE = 0x01; + public static final int LEVEL_ATTACHMENT = 0x02; + public static final int LEVEL_END_OF_FILE = -0x01; + + // ID information taken from http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefattributetag%28v=EXCHG.140%29.aspx + public static final TNEFProperty ID_AIDOWNER = + new TNEFProperty(0x0008, TYPE_LONG, "AidOwner", "PR_OWNER_APPT_ID"); + public static final TNEFProperty ID_ATTACHCREATEDATE = + new TNEFProperty(0x8012, TYPE_DATE, "AttachCreateDate", "PR_CREATION_TIME"); + public static final TNEFProperty ID_ATTACHDATA = + new TNEFProperty(0x800F, TYPE_BYTE, "AttachData", "PR_ATTACH_DATA_BIN"); + public static final TNEFProperty ID_ATTACHMENT = + new TNEFProperty(0x9005, TYPE_BYTE, "Attachment", null); + public static final TNEFProperty ID_ATTACHMETAFILE = + new TNEFProperty(0x8011, TYPE_BYTE, "AttachMetaFile", "PR_ATTACH_RENDERING"); + public static final TNEFProperty ID_ATTACHMODIFYDATE = + new TNEFProperty(0x8013, TYPE_DATE, "AttachModifyDate", "PR_LAST_MODIFICATION_TIME"); + public static final TNEFProperty ID_ATTACHRENDERDATA = + new TNEFProperty(0x9002, TYPE_BYTE, "AttachRenderData", "attAttachRenddata"); + public static final TNEFProperty ID_ATTACHTITLE = + new TNEFProperty(0x8010, TYPE_STRING, "AttachTitle", "PR_ATTACH_FILENAME"); + public static final TNEFProperty ID_ATTACHTRANSPORTFILENAME = + new TNEFProperty(0x9001, TYPE_BYTE, "AttachTransportFilename", "PR_ATTACH_TRANSPORT_NAME"); + public static final TNEFProperty ID_BODY = + new TNEFProperty(0x800C, TYPE_TEXT, "Body", "PR_BODY"); + public static final TNEFProperty ID_CONVERSATIONID = + new TNEFProperty(0x800B, TYPE_STRING, "ConversationId", "PR_CONVERSATION_KEY"); + public static final TNEFProperty ID_DATEEND = + new TNEFProperty(0x0007, TYPE_DATE, "DateEnd", "PR_END_DATE"); + public static final TNEFProperty ID_DATEMODIFIED = + new TNEFProperty(0x8020, TYPE_DATE, "DateModified", "PR_LAST_MODIFICATION_TIME "); + public static final TNEFProperty ID_DATERECEIVED = + new TNEFProperty(0x8006, TYPE_DATE, "DateReceived", "PR_MESSAGE_DELIVERY_TIME "); + public static final TNEFProperty ID_DATESENT = + new TNEFProperty(0x8005, TYPE_DATE, "DateSent", "PR_CLIENT_SUBMIT_TIME "); + public static final TNEFProperty ID_DATESTART = + new TNEFProperty(0x0006, TYPE_DATE, "DateStart", "PR_START_DATE "); + public static final TNEFProperty ID_DELEGATE = + new TNEFProperty(0x0002, TYPE_BYTE, "Delegate", "PR_RCVD_REPRESENTING_xxx "); + public static final TNEFProperty ID_FROM = + new TNEFProperty(0x8000, TYPE_STRING, "From", "PR_SENDER_ENTRYID"); + public static final TNEFProperty ID_MAPIPROPERTIES = + new TNEFProperty(0x9003, TYPE_BYTE, "MapiProperties", null); + public static final TNEFProperty ID_MESSAGECLASS = + new TNEFProperty(0x8008, TYPE_WORD, "MessageClass", "PR_MESSAGE_CLASS "); + public static final TNEFProperty ID_MESSAGEID = + new TNEFProperty(0x8009, TYPE_STRING, "MessageId", "PR_SEARCH_KEY"); + public static final TNEFProperty ID_MESSAGESTATUS = + new TNEFProperty(0x8007, TYPE_BYTE, "MessageStatus", "PR_MESSAGE_FLAGS"); + public static final TNEFProperty ID_NULL = + new TNEFProperty(0x0000, -1, "Null", null); + public static final TNEFProperty ID_OEMCODEPAGE = + new TNEFProperty(0x9007, TYPE_BYTE, "OemCodepage", "AttOemCodepage"); + public static final TNEFProperty ID_ORIGINALMESSAGECLASS = + new TNEFProperty(0x0006, TYPE_WORD, "OriginalMessageClass", "PR_ORIG_MESSAGE_CLASS"); + public static final TNEFProperty ID_OWNER = + new TNEFProperty(0x0000, TYPE_BYTE, "Owner", "PR_RCVD_REPRESENTING_xxx"); + public static final TNEFProperty ID_PARENTID = + new TNEFProperty(0x800A, TYPE_STRING, "ParentId", "PR_PARENT_KEY"); + public static final TNEFProperty ID_PRIORITY = + new TNEFProperty(0x800D, TYPE_SHORT, "Priority", "PR_IMPORTANCE"); + public static final TNEFProperty ID_RECIPIENTTABLE = + new TNEFProperty(0x9004, TYPE_BYTE, "RecipientTable", "PR_MESSAGE_RECIPIENTS"); + public static final TNEFProperty ID_REQUESTRESPONSE = + new TNEFProperty(0x009, TYPE_SHORT, "RequestResponse", "PR_RESPONSE_REQUESTED"); + public static final TNEFProperty ID_SENTFOR = + new TNEFProperty(0x0001, TYPE_BYTE, "SentFor", "PR_SENT_REPRESENTING_xxx"); + public static final TNEFProperty ID_SUBJECT = + new TNEFProperty(0x8004, TYPE_STRING, "Subject", "PR_SUBJECT"); + public static final TNEFProperty ID_TNEFVERSION = + new TNEFProperty(0x9006, TYPE_DWORD, "TnefVersion", "attTnefVersion"); + public static final TNEFProperty ID_UNKNOWN = + new TNEFProperty(-1, -1, "Unknown", null); + + /** The TNEF Property ID */ + public final int id; + /** Usual Type */ + public final int usualType; + /** Property Name */ + public final String name; + /** Equivalent MAPI Property */ + public final String mapiProperty; + + private TNEFProperty(int id, int usualType, String name, String mapiProperty) { + this.id = id; + this.usualType = usualType; + this.name = name; + this.mapiProperty = mapiProperty; + + // Store it for lookup + if(! properties.containsKey(id)) { + properties.put(id, new ArrayList()); + } + properties.get(id).add(this); + } + + public static TNEFProperty getBest(int id, int type) { + List attrs = properties.get(id); + if(attrs == null) { + return ID_UNKNOWN; + } + + // If there's only one, it's easy + if(attrs.size() == 1) { + return attrs.get(0); + } + + // Try by type + for(TNEFProperty attr : attrs) { + if(attr.usualType == type) return attr; + } + + // Go for the first if we can't otherwise decide... + return attrs.get(0); + } + + public String toString() { + StringBuffer str = new StringBuffer(); + str.append(name); + str.append(" ["); + str.append(id); + str.append("]"); + if(mapiProperty != null) { + str.append(" ("); + str.append(mapiProperty); + str.append(")"); + } + return str.toString(); + } +} 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 a64a558a17..26ecbf5239 100644 --- a/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java +++ b/src/scratchpad/src/org/apache/poi/hmef/dev/HMEFDumper.java @@ -22,9 +22,10 @@ import java.io.IOException; import java.io.InputStream; import java.util.List; -import org.apache.poi.hmef.Attribute; import org.apache.poi.hmef.HMEFMessage; -import org.apache.poi.hmef.MAPIAttribute; +import org.apache.poi.hmef.attribute.TNEFAttribute; +import org.apache.poi.hmef.attribute.MAPIAttribute; +import org.apache.poi.hmef.attribute.TNEFProperty; import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; @@ -82,17 +83,17 @@ public final class HMEFDumper { while(true) { // Fetch the level level = inp.read(); - if(level == Attribute.LEVEL_END_OF_FILE) { + if(level == TNEFProperty.LEVEL_END_OF_FILE) { break; } // Build the attribute - Attribute attr = new Attribute(inp); + TNEFAttribute attr = new TNEFAttribute(inp); // Print the attribute into System.out.println( "Level " + level + " : Type " + attr.getType() + - " : ID " + attr.getId().toString() + " : ID " + attr.getProperty().toString() ); // Print the contents @@ -124,7 +125,7 @@ public final class HMEFDumper { } System.out.println(); - if(attr.getId() == Attribute.ID_MAPIPROPERTIES) { + if(attr.getProperty() == TNEFProperty.ID_MAPIPROPERTIES) { 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/TestCompressedRTF.java b/src/scratchpad/testcases/org/apache/poi/hmef/TestCompressedRTF.java index f9cc09c37a..e6a8d6ca37 100644 --- a/src/scratchpad/testcases/org/apache/poi/hmef/TestCompressedRTF.java +++ b/src/scratchpad/testcases/org/apache/poi/hmef/TestCompressedRTF.java @@ -22,7 +22,8 @@ import java.io.ByteArrayInputStream; import junit.framework.TestCase; import org.apache.poi.POIDataSamples; -import org.apache.poi.hmef.Attribute.AttributeID; +import org.apache.poi.hmef.attribute.MAPIAttribute; +import org.apache.poi.hmef.attribute.MAPIRtfAttribute; import org.apache.poi.hsmf.datatypes.MAPIProperty; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.StringUtil; diff --git a/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java b/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java index 33e1edbbe3..b4542d4316 100644 --- a/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java +++ b/src/scratchpad/testcases/org/apache/poi/hmef/TestHMEFMessage.java @@ -20,6 +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; public final class TestHMEFMessage extends TestCase { private static final POIDataSamples _samples = POIDataSamples.getHMEFInstance(); @@ -70,20 +72,20 @@ public final class TestHMEFMessage extends TestCase { // Should have version, codepage, class and MAPI assertEquals(4, msg.getMessageAttributes().size()); - assertNotNull(msg.getMessageAttribute(Attribute.ID_TNEFVERSION)); - assertNotNull(msg.getMessageAttribute(Attribute.ID_OEMCODEPAGE)); - assertNotNull(msg.getMessageAttribute(Attribute.ID_MESSAGECLASS)); - assertNotNull(msg.getMessageAttribute(Attribute.ID_MAPIPROPERTIES)); + assertNotNull(msg.getMessageAttribute(TNEFProperty.ID_TNEFVERSION)); + assertNotNull(msg.getMessageAttribute(TNEFProperty.ID_OEMCODEPAGE)); + assertNotNull(msg.getMessageAttribute(TNEFProperty.ID_MESSAGECLASS)); + assertNotNull(msg.getMessageAttribute(TNEFProperty.ID_MAPIPROPERTIES)); // Check the order - assertEquals(Attribute.ID_TNEFVERSION, msg.getMessageAttributes().get(0).getId()); - assertEquals(Attribute.ID_OEMCODEPAGE, msg.getMessageAttributes().get(1).getId()); - assertEquals(Attribute.ID_MESSAGECLASS, msg.getMessageAttributes().get(2).getId()); - assertEquals(Attribute.ID_MAPIPROPERTIES, msg.getMessageAttributes().get(3).getId()); + assertEquals(TNEFProperty.ID_TNEFVERSION, msg.getMessageAttributes().get(0).getProperty()); + assertEquals(TNEFProperty.ID_OEMCODEPAGE, msg.getMessageAttributes().get(1).getProperty()); + assertEquals(TNEFProperty.ID_MESSAGECLASS, msg.getMessageAttributes().get(2).getProperty()); + assertEquals(TNEFProperty.ID_MAPIPROPERTIES, msg.getMessageAttributes().get(3).getProperty()); // Check some that aren't there - assertNull(msg.getMessageAttribute(Attribute.ID_AIDOWNER)); - assertNull(msg.getMessageAttribute(Attribute.ID_ATTACHDATA)); + assertNull(msg.getMessageAttribute(TNEFProperty.ID_AIDOWNER)); + assertNull(msg.getMessageAttribute(TNEFProperty.ID_ATTACHDATA)); // Now check the details of one or two // TODO