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:
Nick Burch 2010-01-08 13:42:53 +00:00
parent 1ae7d3f871
commit ff94e5c61b
6 changed files with 185 additions and 14 deletions

View File

@ -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();
}
/**

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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 {