Support fetching the message date from the submission id
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@897201 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1ae7d3f871
commit
ff94e5c61b
@ -22,6 +22,7 @@ import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.apache.poi.hsmf.datatypes.AttachmentChunks;
|
||||
import org.apache.poi.hsmf.datatypes.ChunkGroup;
|
||||
@ -192,6 +193,17 @@ public class MAPIMessage {
|
||||
public String getMessageClass() throws ChunkNotFoundException {
|
||||
return getStringFromChunk(mainChunks.messageClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date that the message was accepted by the
|
||||
* server on.
|
||||
*/
|
||||
public Calendar getMessageDate() throws ChunkNotFoundException {
|
||||
if(mainChunks.submissionChunk != null) {
|
||||
return mainChunks.submissionChunk.getAcceptedAtTime();
|
||||
}
|
||||
throw new ChunkNotFoundException();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -23,7 +23,11 @@ import java.io.OutputStream;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
|
||||
/**
|
||||
* A Chunk made up of a ByteArrayOutputStream.
|
||||
* A Chunk that holds binary data, normally
|
||||
* unparsed.
|
||||
* Generally as we know how to make sense of the
|
||||
* contents, we create a new Chunk class and add
|
||||
* a special case in the parser for them.
|
||||
*/
|
||||
|
||||
public class ByteChunk extends Chunk {
|
||||
|
@ -30,7 +30,9 @@ public final class Chunks implements ChunkGroup {
|
||||
/* String parts of Outlook Messages that are currently known */
|
||||
public static final int MESSAGE_CLASS = 0x001A;
|
||||
public static final int SUBJECT = 0x0037;
|
||||
public static final int DATE = 0x0047;
|
||||
// "PidTagMessageSubmissionId" as given by accepting server
|
||||
public static final int SUBMISSION_ID_DATE = 0x0047;
|
||||
// 0x0050 -> 0x006F seem to be routing info or similar
|
||||
public static final int CONVERSATION_TOPIC = 0x0070;
|
||||
public static final int SENT_BY_SERVER_TYPE = 0x0075;
|
||||
// RECEIVEDEMAIL = 76
|
||||
@ -39,7 +41,9 @@ public final class Chunks implements ChunkGroup {
|
||||
public static final int EMAIL_FROM = 0x0C1F;
|
||||
public static final int DISPLAY_CC = 0x0E03;
|
||||
public static final int DISPLAY_BCC = 0x0E02;
|
||||
// 0x0E1D seems a duplicate of 0x0070 !
|
||||
public static final int TEXT_BODY = 0x1000;
|
||||
public static final int MESSAGE_ID = 0x1035;
|
||||
|
||||
/** Holds all the chunks that were found. */
|
||||
private List<Chunk> allChunks = new ArrayList<Chunk>();
|
||||
@ -63,9 +67,11 @@ public final class Chunks implements ChunkGroup {
|
||||
/** Type of server that the message originated from (SMTP, etc). */
|
||||
public StringChunk sentByServerType;
|
||||
/** TODO */
|
||||
public ByteChunk dateChunk;
|
||||
public MessageSubmissionChunk submissionChunk;
|
||||
/** TODO */
|
||||
public StringChunk emailFromChunk;
|
||||
/** The message ID */
|
||||
public StringChunk messageId;
|
||||
|
||||
public Chunk[] getAll() {
|
||||
return allChunks.toArray(new Chunk[allChunks.size()]);
|
||||
@ -82,12 +88,15 @@ public final class Chunks implements ChunkGroup {
|
||||
case MESSAGE_CLASS:
|
||||
messageClass = (StringChunk)chunk;
|
||||
break;
|
||||
case MESSAGE_ID:
|
||||
messageId = (StringChunk)chunk;
|
||||
break;
|
||||
case SUBJECT:
|
||||
subjectChunk = (StringChunk)chunk;
|
||||
break;
|
||||
case DATE:
|
||||
case SUBMISSION_ID_DATE:
|
||||
// TODO - parse
|
||||
dateChunk = (ByteChunk)chunk;
|
||||
submissionChunk = (MessageSubmissionChunk)chunk;
|
||||
break;
|
||||
case CONVERSATION_TOPIC:
|
||||
conversationTopic = (StringChunk)chunk;
|
||||
|
@ -0,0 +1,121 @@
|
||||
/* ====================================================================
|
||||
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.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Calendar;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.poi.util.IOUtils;
|
||||
|
||||
/**
|
||||
* A Chunk that holds the details given back by the
|
||||
* server at submission time.
|
||||
* This includes the date the message was given to the
|
||||
* server, and an ID that's used if you want to cancel
|
||||
* a message or similar
|
||||
*/
|
||||
|
||||
public class MessageSubmissionChunk extends Chunk {
|
||||
private String rawId;
|
||||
private Calendar date;
|
||||
|
||||
private static final Pattern datePatern =
|
||||
Pattern.compile("(\\d\\d)(\\d\\d)(\\d\\d)(\\d\\d)(\\d\\d)(\\d\\d)Z?");
|
||||
|
||||
/**
|
||||
* Creates a Byte Chunk.
|
||||
*/
|
||||
public MessageSubmissionChunk(String entryName) {
|
||||
super(entryName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Byte Chunk, with the specified
|
||||
* type.
|
||||
*/
|
||||
public MessageSubmissionChunk(int chunkId, int type) {
|
||||
super(chunkId, type);
|
||||
}
|
||||
|
||||
public void readValue(InputStream value) throws IOException {
|
||||
// Stored in the file as us-ascii
|
||||
try {
|
||||
byte[] data = IOUtils.toByteArray(value);
|
||||
rawId = new String(data, "ASCII");
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Core encoding not found, JVM broken?", e);
|
||||
}
|
||||
|
||||
// Now process the date
|
||||
String[] parts = rawId.split(";");
|
||||
for(String part : parts) {
|
||||
if(part.startsWith("l=")) {
|
||||
// Format of this bit appears to be l=<id>-<time>-<number>
|
||||
if(part.indexOf('-') != -1 &&
|
||||
part.indexOf('-') != part.lastIndexOf('-')) {
|
||||
String dateS = part.substring(part.indexOf('-')+1, part.lastIndexOf('-'));
|
||||
|
||||
// Should be yymmddhhmmssZ
|
||||
Matcher m = datePatern.matcher(dateS);
|
||||
if(m.matches()) {
|
||||
date = Calendar.getInstance();
|
||||
date.set(Calendar.YEAR, Integer.parseInt(m.group(1)) + 2000);
|
||||
date.set(Calendar.MONTH, Integer.parseInt(m.group(2)) - 1); // Java is 0 based
|
||||
date.set(Calendar.DATE, Integer.parseInt(m.group(3)));
|
||||
date.set(Calendar.HOUR_OF_DAY, Integer.parseInt(m.group(4)));
|
||||
date.set(Calendar.MINUTE, Integer.parseInt(m.group(5)));
|
||||
date.set(Calendar.SECOND, Integer.parseInt(m.group(6)));
|
||||
date.set(Calendar.MILLISECOND, 0);
|
||||
} else {
|
||||
System.err.println("Warning - unable to make sense of date " + dateS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeValue(OutputStream out) throws IOException {
|
||||
try {
|
||||
byte[] data = rawId.getBytes("ASCII");
|
||||
out.write(data);
|
||||
} catch(UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("Core encoding not found, JVM broken?", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date that the server accepted the
|
||||
* message, as found from the message ID it generated.
|
||||
* @return
|
||||
*/
|
||||
public Calendar getAcceptedAtTime() {
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full ID that the server generated when
|
||||
* it accepted the message.
|
||||
*/
|
||||
public String getSubmissionId() {
|
||||
return rawId;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ import org.apache.poi.hsmf.datatypes.ByteChunk;
|
||||
import org.apache.poi.hsmf.datatypes.Chunk;
|
||||
import org.apache.poi.hsmf.datatypes.ChunkGroup;
|
||||
import org.apache.poi.hsmf.datatypes.Chunks;
|
||||
import org.apache.poi.hsmf.datatypes.MessageSubmissionChunk;
|
||||
import org.apache.poi.hsmf.datatypes.NameIdChunks;
|
||||
import org.apache.poi.hsmf.datatypes.RecipientChunks;
|
||||
import org.apache.poi.hsmf.datatypes.StringChunk;
|
||||
@ -111,19 +112,31 @@ public final class POIFSChunkParser {
|
||||
}
|
||||
|
||||
// See if we can get a type for it
|
||||
String ending = entry.getName().substring(entry.getName().length()-4);
|
||||
String idType = entry.getName().substring(entry.getName().length()-8);
|
||||
String idS = idType.substring(0, 4);
|
||||
String typeS = idType.substring(4);
|
||||
try {
|
||||
int type = Integer.parseInt(ending, 16);
|
||||
int id = Integer.parseInt(idS, 16);
|
||||
int type = Integer.parseInt(typeS, 16);
|
||||
Chunk chunk = null;
|
||||
|
||||
switch(type) {
|
||||
case Types.BINARY:
|
||||
chunk = new ByteChunk(entry.getName());
|
||||
break;
|
||||
case Types.ASCII_STRING:
|
||||
case Types.UNICODE_STRING:
|
||||
chunk = new StringChunk(entry.getName());
|
||||
// Special cases based on the ID
|
||||
switch(id) {
|
||||
case Chunks.SUBMISSION_ID_DATE:
|
||||
chunk = new MessageSubmissionChunk(entry.getName());
|
||||
break;
|
||||
default:
|
||||
// Nothing special about this ID
|
||||
// So, do the usual thing which is by type
|
||||
switch(type) {
|
||||
case Types.BINARY:
|
||||
chunk = new ByteChunk(entry.getName());
|
||||
break;
|
||||
case Types.ASCII_STRING:
|
||||
case Types.UNICODE_STRING:
|
||||
chunk = new StringChunk(entry.getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(chunk != null) {
|
||||
|
@ -20,6 +20,8 @@ package org.apache.poi.hsmf.parsers;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.apache.poi.hsmf.MAPIMessage;
|
||||
import org.apache.poi.hsmf.datatypes.AttachmentChunks;
|
||||
@ -67,6 +69,16 @@ public final class TestPOIFSChunkParser extends TestCase {
|
||||
} catch(ChunkNotFoundException e) {
|
||||
fail();
|
||||
}
|
||||
|
||||
// Check date too
|
||||
try {
|
||||
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
Calendar c = msg.getMessageDate();
|
||||
assertEquals( "2007-06-14 09:42:55", f.format(c.getTime()) );
|
||||
} catch(ChunkNotFoundException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
public void testFindsRecips() throws IOException {
|
||||
|
Loading…
Reference in New Issue
Block a user