Fix bug #47990 - Support for .msg attachments within a MAPIMessage .msg
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@982331 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3c4946472b
commit
514e6be1fe
@ -34,6 +34,7 @@
|
||||
|
||||
<changes>
|
||||
<release version="3.7-beta2" date="2010-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">47990 - Support for .msg attachments within a MAPIMessage .msg</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">Improve handling and warnings when closing OPCPackage objects</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">49702 - Correct XSSFWorkbook.getNumCellStyles to check the right styles list</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">49690 - Add WorkbookUtil, which provies a way of generating valid sheet names</action>
|
||||
|
@ -110,6 +110,15 @@ public class DirectoryNode
|
||||
return _path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the filesystem that this belongs to
|
||||
*/
|
||||
|
||||
public POIFSFileSystem getFileSystem()
|
||||
{
|
||||
return _filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* open a document in the directory's entry's list of entries
|
||||
*
|
||||
|
@ -42,6 +42,8 @@ public class AttachmentChunks implements ChunkGroup {
|
||||
public StringChunk attachFileName;
|
||||
public StringChunk attachLongFileName;
|
||||
public StringChunk attachMimeTag;
|
||||
public DirectoryChunk attachmentDirectory;
|
||||
|
||||
/**
|
||||
* This is in WMF Format. You'll probably want to pass it
|
||||
* to Apache Batik to turn it into a SVG that you can
|
||||
@ -79,7 +81,13 @@ public class AttachmentChunks implements ChunkGroup {
|
||||
public void record(Chunk chunk) {
|
||||
switch(chunk.getChunkId()) {
|
||||
case ATTACH_DATA:
|
||||
if(chunk instanceof ByteChunk) {
|
||||
attachData = (ByteChunk)chunk;
|
||||
} else if(chunk instanceof DirectoryChunk) {
|
||||
attachmentDirectory = (DirectoryChunk)chunk;
|
||||
} else {
|
||||
System.err.println("Unexpected data chunk of type " + chunk);
|
||||
}
|
||||
break;
|
||||
case ATTACH_EXTENSION:
|
||||
attachExtension = (StringChunk)chunk;
|
||||
|
@ -0,0 +1,68 @@
|
||||
/* ====================================================================
|
||||
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 org.apache.poi.hsmf.MAPIMessage;
|
||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||
|
||||
/**
|
||||
* A Chunk that is just a placeholder in the
|
||||
* MAPIMessage directory structure, which
|
||||
* contains children.
|
||||
* This is most commonly used with nested
|
||||
* MAPIMessages
|
||||
*/
|
||||
public class DirectoryChunk extends Chunk {
|
||||
private DirectoryNode dir;
|
||||
|
||||
public DirectoryChunk(DirectoryNode dir, String namePrefix, int chunkId, int type) {
|
||||
super(namePrefix, chunkId, type);
|
||||
this.dir = dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory entry for this chunk.
|
||||
* You can then use standard POIFS methods to
|
||||
* enumerate the entries in it.
|
||||
*/
|
||||
public DirectoryNode getDirectory() {
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Treats the directory as an embeded MAPIMessage
|
||||
* (it normally is one), and returns a MAPIMessage
|
||||
* object to process it with.
|
||||
*/
|
||||
public MAPIMessage getAsEmbededMessage() throws IOException {
|
||||
return new MAPIMessage(dir, dir.getFileSystem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readValue(InputStream value) {
|
||||
// DirectoryChunks have 0 byte contents
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeValue(OutputStream out) {
|
||||
// DirectoryChunks have 0 byte contents
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ public final class Types {
|
||||
public static final int LONG = 0x0003;
|
||||
public static final int TIME = 0x0040;
|
||||
public static final int BOOLEAN = 0x000B;
|
||||
public static final int DIRECTORY = 0x000D;
|
||||
|
||||
public static String asFileEnding(int type) {
|
||||
String str = Integer.toHexString(type).toUpperCase();
|
||||
|
@ -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.DirectoryChunk;
|
||||
import org.apache.poi.hsmf.datatypes.MessageSubmissionChunk;
|
||||
import org.apache.poi.hsmf.datatypes.NameIdChunks;
|
||||
import org.apache.poi.hsmf.datatypes.RecipientChunks;
|
||||
@ -93,7 +94,11 @@ public final class POIFSChunkParser {
|
||||
protected static void processChunks(DirectoryNode node, ChunkGroup grouping) {
|
||||
for(Entry entry : node) {
|
||||
if(entry instanceof DocumentNode) {
|
||||
process((DocumentNode)entry, grouping);
|
||||
process(entry, grouping);
|
||||
} else if(entry instanceof DirectoryNode) {
|
||||
if(entry.getName().endsWith(Types.asFileEnding(Types.DIRECTORY))) {
|
||||
process(entry, grouping);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -101,7 +106,7 @@ public final class POIFSChunkParser {
|
||||
/**
|
||||
* Creates a chunk, and gives it to its parent group
|
||||
*/
|
||||
protected static void process(DocumentNode entry, ChunkGroup grouping) {
|
||||
protected static void process(Entry entry, ChunkGroup grouping) {
|
||||
String entryName = entry.getName();
|
||||
|
||||
if(entryName.length() < 9) {
|
||||
@ -140,6 +145,11 @@ public final class POIFSChunkParser {
|
||||
case Types.BINARY:
|
||||
chunk = new ByteChunk(namePrefix, chunkId, type);
|
||||
break;
|
||||
case Types.DIRECTORY:
|
||||
if(entry instanceof DirectoryNode) {
|
||||
chunk = new DirectoryChunk((DirectoryNode)entry, namePrefix, chunkId, type);
|
||||
}
|
||||
break;
|
||||
case Types.ASCII_STRING:
|
||||
case Types.UNICODE_STRING:
|
||||
chunk = new StringChunk(namePrefix, chunkId, type);
|
||||
@ -148,13 +158,17 @@ public final class POIFSChunkParser {
|
||||
}
|
||||
|
||||
if(chunk != null) {
|
||||
if(entry instanceof DocumentNode) {
|
||||
try {
|
||||
DocumentInputStream inp = new DocumentInputStream(entry);
|
||||
DocumentInputStream inp = new DocumentInputStream((DocumentNode)entry);
|
||||
chunk.readValue(inp);
|
||||
grouping.record(chunk);
|
||||
} catch(IOException e) {
|
||||
System.err.println("Error reading from part " + entry.getName() + " - " + e.toString());
|
||||
}
|
||||
} else {
|
||||
grouping.record(chunk);
|
||||
}
|
||||
}
|
||||
} catch(NumberFormatException e) {
|
||||
// Name in the wrong format
|
||||
|
@ -31,7 +31,8 @@ import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
|
||||
* @author Nicolas Bureau
|
||||
*/
|
||||
public class TestFileWithAttachmentsRead extends TestCase {
|
||||
private MAPIMessage mapiMessage;
|
||||
private MAPIMessage twoSimpleAttachments;
|
||||
private MAPIMessage pdfMsgAttachments;
|
||||
|
||||
/**
|
||||
* Initialize this test, load up the attachment_test_msg.msg mapi message.
|
||||
@ -40,7 +41,8 @@ public class TestFileWithAttachmentsRead extends TestCase {
|
||||
*/
|
||||
public TestFileWithAttachmentsRead() throws IOException {
|
||||
POIDataSamples samples = POIDataSamples.getHSMFInstance();
|
||||
this.mapiMessage = new MAPIMessage(samples.openResourceAsStream("attachment_test_msg.msg"));
|
||||
this.twoSimpleAttachments = new MAPIMessage(samples.openResourceAsStream("attachment_test_msg.msg"));
|
||||
this.pdfMsgAttachments = new MAPIMessage(samples.openResourceAsStream("attachment_msg_pdf.msg"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,18 +52,20 @@ public class TestFileWithAttachmentsRead extends TestCase {
|
||||
*
|
||||
*/
|
||||
public void testRetrieveAttachments() {
|
||||
AttachmentChunks[] attachments = mapiMessage.getAttachmentFiles();
|
||||
int obtained = attachments.length;
|
||||
int expected = 2;
|
||||
// Simple file
|
||||
AttachmentChunks[] attachments = twoSimpleAttachments.getAttachmentFiles();
|
||||
assertEquals(2, attachments.length);
|
||||
|
||||
TestCase.assertEquals(obtained, expected);
|
||||
// Other file
|
||||
attachments = pdfMsgAttachments.getAttachmentFiles();
|
||||
assertEquals(2, attachments.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if attachments are not empty.
|
||||
*/
|
||||
public void testReadAttachments() throws IOException {
|
||||
AttachmentChunks[] attachments = mapiMessage.getAttachmentFiles();
|
||||
AttachmentChunks[] attachments = twoSimpleAttachments.getAttachmentFiles();
|
||||
|
||||
// Basic checks
|
||||
for (AttachmentChunks attachment : attachments) {
|
||||
@ -76,18 +80,52 @@ public class TestFileWithAttachmentsRead extends TestCase {
|
||||
AttachmentChunks attachment;
|
||||
|
||||
// Now check in detail
|
||||
attachment = mapiMessage.getAttachmentFiles()[0];
|
||||
attachment = twoSimpleAttachments.getAttachmentFiles()[0];
|
||||
assertEquals("TEST-U~1.DOC", attachment.attachFileName.toString());
|
||||
assertEquals("test-unicode.doc", attachment.attachLongFileName.toString());
|
||||
assertEquals(".doc", attachment.attachExtension.getValue());
|
||||
assertEquals(null, attachment.attachMimeTag);
|
||||
assertEquals(24064, attachment.attachData.getValue().length);
|
||||
|
||||
attachment = mapiMessage.getAttachmentFiles()[1];
|
||||
attachment = twoSimpleAttachments.getAttachmentFiles()[1];
|
||||
assertEquals("pj1.txt", attachment.attachFileName.toString());
|
||||
assertEquals("pj1.txt", attachment.attachLongFileName.toString());
|
||||
assertEquals(".txt", attachment.attachExtension.getValue());
|
||||
assertEquals(null, attachment.attachMimeTag);
|
||||
assertEquals(89, attachment.attachData.getValue().length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can handle both PDF and MSG attachments
|
||||
*/
|
||||
public void testReadMsgAttachments() throws Exception {
|
||||
AttachmentChunks[] attachments = pdfMsgAttachments.getAttachmentFiles();
|
||||
assertEquals(2, attachments.length);
|
||||
|
||||
AttachmentChunks attachment;
|
||||
|
||||
// Second is a PDF
|
||||
attachment = pdfMsgAttachments.getAttachmentFiles()[1];
|
||||
assertEquals("smbprn~1.pdf", attachment.attachFileName.toString());
|
||||
assertEquals("smbprn.00009008.KdcPjl.pdf", attachment.attachLongFileName.toString());
|
||||
assertEquals(".pdf", attachment.attachExtension.getValue());
|
||||
assertEquals(null, attachment.attachMimeTag);
|
||||
assertEquals(null, attachment.attachmentDirectory);
|
||||
assertEquals(13539, attachment.attachData.getValue().length);
|
||||
|
||||
// First in a nested message
|
||||
attachment = pdfMsgAttachments.getAttachmentFiles()[0];
|
||||
assertEquals("Test Attachment", attachment.attachFileName.toString());
|
||||
assertEquals(null, attachment.attachLongFileName);
|
||||
assertEquals(null, attachment.attachExtension);
|
||||
assertEquals(null, attachment.attachMimeTag);
|
||||
assertEquals(null, attachment.attachData);
|
||||
assertNotNull(attachment.attachmentDirectory);
|
||||
|
||||
// Check we can see some bits of it
|
||||
MAPIMessage nested = attachment.attachmentDirectory.getAsEmbededMessage();
|
||||
assertEquals(1, nested.getRecipientNamesList().length);
|
||||
assertEquals("Nick Booth", nested.getRecipientNames());
|
||||
assertEquals("Test Attachment", nested.getConversationTopic());
|
||||
}
|
||||
}
|
||||
|
BIN
test-data/hsmf/attachment_msg_pdf.msg
Normal file
BIN
test-data/hsmf/attachment_msg_pdf.msg
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user