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}
// MAPI property, grab the details of it
MAPIProperty prop = MAPIProperty.get(id);
if(id >= 0x8000 && id <= 0xFFFF) {
- // TODO
- System.err.println("Not yet implemented for id " + id);
- break;
+ 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 len = getLength(type, inp);
byte[] data = new byte[len];
IOUtils.readFully(inp, data);
+ skipToBoundary(len, inp);
// Create
MAPIAttribute attr;
attr = new MAPIAttribute(prop, type, data);
}
attrs.add(attr);
-
- // Data is always padded out to a 4 byte boundary
- if(len % 4 != 0) {
- byte[] padding = new byte[4 - (len % 4)];
- IOUtils.readFully(inp, padding);
- }
}
}
throw new IllegalArgumentException("Unknown type " + type);
}
}
+ private static void skipToBoundary(int length, InputStream inp) throws IOException {
+ // Data is always padded out to a 4 byte boundary
+ if(length % 4 != 0) {
+ int skip = 4 - (length % 4);
+ byte[] padding = new byte[skip];
+ IOUtils.readFully(inp, padding);
+ }
+ }
}
* http://msdn.microsoft.com/en-us/library/microsoft.exchange.data.contenttypes.tnef.tnefpropertyid%28v=EXCHG.140%29.aspx
* http://msdn.microsoft.com/en-us/library/ms526356%28v=exchg.10%29.aspx
*/
-public final class MAPIProperty {
+public class MAPIProperty {
private static Map<Integer, MAPIProperty> attributes = new HashMap<Integer, MAPIProperty>();
public static final MAPIProperty AB_DEFAULT_DIR =
new MAPIProperty(-1, -1, "Unknown", null);
// 0x8??? ones are outlook specific, and not standard MAPI
+ private static final int ID_FIRST_CUSTOM = 0x8000;
+ private static final int ID_LAST_CUSTOM = 0xFFFE;
/* --------------------------------------------------------------------- */
this.name = name;
this.mapiProperty = mapiProperty;
- // Store it for lookup
- if(attributes.containsKey(id)) {
- throw new IllegalArgumentException(
- "Duplicate MAPI Property with ID " + id + " : " +
- toString() + " vs " + attributes.get(id).toString()
- );
+ // If it isn't unknown or custom, store it for lookup
+ if(id == -1 || (id >= ID_FIRST_CUSTOM && id <= ID_LAST_CUSTOM)
+ || (this instanceof CustomMAPIProperty)) {
+ // Custom/Unknown, skip
+ } else {
+ if(attributes.containsKey(id)) {
+ throw new IllegalArgumentException(
+ "Duplicate MAPI Property with ID " + id + " : " +
+ toString() + " vs " + attributes.get(id).toString()
+ );
+ }
+ attributes.put(id, this);
}
- attributes.put(id, this);
}
public String toString() {
StringBuffer str = new StringBuffer();
}
return str.toString();
}
+
public static MAPIProperty get(int id) {
MAPIProperty attr = attributes.get(id);
if(attr != null) {
public static Collection<MAPIProperty> getAll() {
return Collections.unmodifiableCollection( attributes.values() );
}
+
+ public static MAPIProperty createCustom(int id, int type, String name) {
+ return new CustomMAPIProperty(id, type, name, null);
+ }
+
+ private static class CustomMAPIProperty extends MAPIProperty {
+ private CustomMAPIProperty(int id, int usualType, String name, String mapiProperty) {
+ super(id, usualType, name, mapiProperty);
+ }
+ }
}
--- /dev/null
+/* ====================================================================
+ 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.hsmf.datatypes;
+
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ * Checks various MAPIProperty related logic
+ */
+public final class TestMAPIProperty extends TestCase {
+ public void testGet() throws Exception {
+ assertEquals(MAPIProperty.DISPLAY_NAME, MAPIProperty.get(MAPIProperty.DISPLAY_NAME.id));
+ assertEquals(MAPIProperty.DISPLAY_BCC, MAPIProperty.get(MAPIProperty.DISPLAY_BCC.id));
+ assertNotSame(MAPIProperty.DISPLAY_BCC, MAPIProperty.get(MAPIProperty.DISPLAY_CC.id));
+ }
+
+ public void testGetAll() throws Exception {
+ Collection<MAPIProperty> all = MAPIProperty.getAll();
+ assertEquals(true, all.contains(MAPIProperty.DISPLAY_NAME));
+ assertEquals(true, all.contains(MAPIProperty.DISPLAY_CC));
+
+ // Won't contain custom
+ assertEquals(false, all.contains(MAPIProperty.createCustom(1, 1, "")));
+
+ // Won't contain unknown
+ assertEquals(false, all.contains(MAPIProperty.UNKNOWN));
+ }
+
+ public void testCustom() throws Exception {
+ MAPIProperty c1 = MAPIProperty.createCustom(1, 1, "");
+ MAPIProperty c2a = MAPIProperty.createCustom(2, 1, "2");
+ MAPIProperty c2b = MAPIProperty.createCustom(2, 1, "2");
+
+ // New object each time
+ assertNotSame(c1, c2a);
+ assertNotSame(c1, c2b);
+ assertNotSame(c2a, c2b);
+
+ // Won't be in all list
+ Collection<MAPIProperty> all = MAPIProperty.getAll();
+ assertEquals(false, all.contains(c1));
+ assertEquals(false, all.contains(c2a));
+ assertEquals(false, all.contains(c2b));
+ }
+}
assertEquals("0102", Types.asFileEnding(0x0102));
assertEquals("FEDC", Types.asFileEnding(0xfedc));
}
+
+ public void testName() {
+ assertEquals("ASCII String", Types.asName(Types.ASCII_STRING));
+ assertEquals("Boolean", Types.asName(Types.BOOLEAN));
+ }
}