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
This commit is contained in:
parent
03b0eabcf8
commit
20f6e280a5
@ -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<Attribute> attributes = new ArrayList<Attribute>();
|
||||
private final List<TNEFAttribute> attributes = new ArrayList<TNEFAttribute>();
|
||||
private final List<MAPIAttribute> mapiAttributes = new ArrayList<MAPIAttribute>();
|
||||
|
||||
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<Attribute> getAttributes() {
|
||||
public List<TNEFAttribute> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
@ -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<Integer, List<AttributeID>> attributes = new HashMap<Integer, List<AttributeID>>();
|
||||
|
||||
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<AttributeID>());
|
||||
}
|
||||
attributes.get(id).add(this);
|
||||
}
|
||||
public static AttributeID getBest(int id, int type) {
|
||||
List<AttributeID> 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;
|
||||
}
|
||||
}
|
@ -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<Attribute> messageAttributes = new ArrayList<Attribute>();
|
||||
private List<TNEFAttribute> messageAttributes = new ArrayList<TNEFAttribute>();
|
||||
private List<MAPIAttribute> mapiAttributes = new ArrayList<MAPIAttribute>();
|
||||
private List<Attachment> attachments = new ArrayList<Attachment>();
|
||||
|
||||
@ -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<Attribute> getMessageAttributes() {
|
||||
public List<TNEFAttribute> 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;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hmef;
|
||||
package org.apache.poi.hmef.attribute;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
@ -23,6 +23,8 @@ import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hmef.Attachment;
|
||||
import org.apache.poi.hmef.HMEFMessage;
|
||||
import org.apache.poi.hsmf.datatypes.MAPIProperty;
|
||||
import org.apache.poi.hsmf.datatypes.Types;
|
||||
import org.apache.poi.util.HexDump;
|
||||
@ -79,11 +81,11 @@ public class MAPIAttribute {
|
||||
* Parses a MAPI Properties TNEF Attribute, and returns
|
||||
* the list of MAPI Attributes contained within it
|
||||
*/
|
||||
public static List<MAPIAttribute> create(Attribute parent) throws IOException {
|
||||
if(parent.getId() != Attribute.ID_MAPIPROPERTIES) {
|
||||
public static List<MAPIAttribute> 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.getId() + " one"
|
||||
"instead received a " + parent.getProperty() + " one"
|
||||
);
|
||||
}
|
||||
ByteArrayInputStream inp = new ByteArrayInputStream(parent.getData());
|
@ -15,11 +15,14 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hmef;
|
||||
package org.apache.poi.hmef.attribute;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.hmef.Attachment;
|
||||
import org.apache.poi.hmef.CompressedRTF;
|
||||
import org.apache.poi.hmef.HMEFMessage;
|
||||
import org.apache.poi.hsmf.datatypes.MAPIProperty;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
@ -15,24 +15,15 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
package org.apache.poi.hmef;
|
||||
package org.apache.poi.hmef.attribute;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.util.HexDump;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
import org.apache.poi.hmef.Attribute.AttributeID;
|
||||
import org.apache.poi.hmef.Attachment;
|
||||
import org.apache.poi.hmef.HMEFMessage;
|
||||
import org.apache.poi.hsmf.datatypes.MAPIProperty;
|
||||
import org.apache.poi.hsmf.datatypes.Types;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
||||
/**
|
||||
* A pure-MAPI attribute holding a String, which applies
|
@ -0,0 +1,76 @@
|
||||
/* ====================================================================
|
||||
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.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 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
|
||||
*/
|
||||
public TNEFAttribute(InputStream inp) throws IOException {
|
||||
int id = LittleEndian.readUShort(inp);
|
||||
this.type = LittleEndian.readUShort(inp);
|
||||
int length = LittleEndian.readInt(inp);
|
||||
|
||||
property = TNEFProperty.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 TNEFProperty getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Attachment " + property.toString() + ", type=" + type +
|
||||
", data length=" + data.length;
|
||||
}
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
/* ====================================================================
|
||||
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.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds the list of TNEF Attributes, and allows lookup
|
||||
* by friendly name, ID and MAPI Property Name.
|
||||
*
|
||||
* Note - the types and IDs differ from standard Outlook/MAPI
|
||||
* ones, so we can't just re-use the HSMF ones.
|
||||
*/
|
||||
public final class TNEFProperty {
|
||||
private static Map<Integer, List<TNEFProperty>> properties = new HashMap<Integer, List<TNEFProperty>>();
|
||||
|
||||
// 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<TNEFProperty>());
|
||||
}
|
||||
properties.get(id).add(this);
|
||||
}
|
||||
|
||||
public static TNEFProperty getBest(int id, int type) {
|
||||
List<TNEFProperty> 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();
|
||||
}
|
||||
}
|
@ -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<MAPIAttribute> attrs = MAPIAttribute.create(attr);
|
||||
for(MAPIAttribute ma : attrs) {
|
||||
System.out.println(indent + indent + ma);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user