| /* ==================================================================== |
| 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.Collections; |
| import java.util.List; |
| |
| import org.apache.poi.hmef.attribute.MAPIAttribute; |
| import org.apache.poi.hmef.attribute.MAPIStringAttribute; |
| import org.apache.poi.hmef.attribute.TNEFAttribute; |
| import org.apache.poi.hmef.attribute.TNEFMAPIAttribute; |
| import org.apache.poi.hmef.attribute.TNEFProperty; |
| import org.apache.poi.hsmf.datatypes.MAPIProperty; |
| import org.apache.poi.util.LittleEndian; |
| |
| /** |
| * HMEF - Implementation of the Microsoft TNEF message |
| * encoding format (aka winmail.dat) |
| * See: |
| * http://support.microsoft.com/kb/241538 |
| * http://en.wikipedia.org/wiki/Transport_Neutral_Encapsulation_Format |
| * http://search.cpan.org/dist/Convert-TNEF/ |
| */ |
| public final class HMEFMessage { |
| public static final int HEADER_SIGNATURE = 0x223e9f78; |
| |
| @SuppressWarnings("unused") |
| private int fileId; |
| private final List<TNEFAttribute> messageAttributes = new ArrayList<TNEFAttribute>(); |
| private final List<MAPIAttribute> mapiAttributes = new ArrayList<MAPIAttribute>(); |
| private final List<Attachment> attachments = new ArrayList<Attachment>(); |
| |
| public HMEFMessage(InputStream inp) throws IOException { |
| try { |
| // Check the signature matches |
| int sig = LittleEndian.readInt(inp); |
| if (sig != HEADER_SIGNATURE) { |
| throw new IllegalArgumentException( |
| "TNEF signature not detected in file, " + |
| "expected " + HEADER_SIGNATURE + " but got " + sig |
| ); |
| } |
| |
| // Read the File ID |
| fileId = LittleEndian.readUShort(inp); |
| |
| // Now begin processing the contents |
| process(inp); |
| } finally { |
| inp.close(); |
| } |
| } |
| |
| private void process(InputStream inp) throws IOException { |
| int level; |
| do { |
| // Fetch the level |
| level = inp.read(); |
| |
| // Decide what to attach it to, based on the levels and IDs |
| switch (level) { |
| case TNEFProperty.LEVEL_MESSAGE: |
| processMessage(inp); |
| break; |
| case TNEFProperty.LEVEL_ATTACHMENT: |
| processAttachment(inp); |
| break; |
| // ignore trailing newline |
| case '\r': |
| case '\n': |
| case TNEFProperty.LEVEL_END_OF_FILE: |
| break; |
| default: |
| throw new IllegalStateException("Unhandled level " + level); |
| } |
| } while (level != TNEFProperty.LEVEL_END_OF_FILE); |
| } |
| |
| void processMessage(InputStream inp) throws IOException { |
| // Build the attribute |
| TNEFAttribute attr = TNEFAttribute.create(inp); |
| |
| messageAttributes.add(attr); |
| |
| if (attr instanceof TNEFMAPIAttribute) { |
| TNEFMAPIAttribute tnefMAPI = (TNEFMAPIAttribute) attr; |
| mapiAttributes.addAll(tnefMAPI.getMAPIAttributes()); |
| } |
| } |
| |
| void processAttachment(InputStream inp) throws IOException { |
| // Build the attribute |
| TNEFAttribute attr = TNEFAttribute.create(inp); |
| |
| // Previous attachment or a new one? |
| if (attachments.isEmpty() |
| || attr.getProperty() == TNEFProperty.ID_ATTACHRENDERDATA) { |
| attachments.add(new Attachment()); |
| } |
| |
| // Save the attribute for it |
| Attachment attach = attachments.get(attachments.size() - 1); |
| attach.addAttribute(attr); |
| } |
| |
| /** |
| * Returns all HMEF/TNEF attributes of the message. |
| * Note - In a typical message, most of the interesting properties |
| * are stored as {@link MAPIAttribute}s - see {@link #getMessageMAPIAttributes()} |
| */ |
| public List<TNEFAttribute> getMessageAttributes() { |
| return Collections.unmodifiableList(messageAttributes); |
| } |
| |
| /** |
| * Returns all MAPI attributes of the message. |
| * Note - A small number of HMEF/TNEF specific attributes normally |
| * apply to most messages, see {@link #getMessageAttributes()} |
| */ |
| public List<MAPIAttribute> getMessageMAPIAttributes() { |
| return Collections.unmodifiableList(mapiAttributes); |
| } |
| |
| /** |
| * Returns all the Attachments of the message. |
| */ |
| public List<Attachment> getAttachments() { |
| return Collections.unmodifiableList(attachments); |
| } |
| |
| /** |
| * Return the message attribute with the given ID, |
| * or null if there isn't one. |
| */ |
| public TNEFAttribute getMessageAttribute(TNEFProperty id) { |
| for (TNEFAttribute attr : messageAttributes) { |
| if (attr.getProperty() == id) { |
| return attr; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Return the message MAPI Attribute with the given ID, |
| * or null if there isn't one. |
| */ |
| public MAPIAttribute getMessageMAPIAttribute(MAPIProperty id) { |
| for (MAPIAttribute attr : mapiAttributes) { |
| // Because of custom properties, match on ID not literal property object |
| if (attr.getProperty().id == id.id) { |
| return attr; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Return the string value of the mapi property, or null |
| * if it isn't set |
| */ |
| private String getString(MAPIProperty id) { |
| return MAPIStringAttribute.getAsString( getMessageMAPIAttribute(id) ); |
| } |
| |
| /** |
| * Returns the Message Subject, or null if the mapi property |
| * for this isn't set |
| */ |
| public String getSubject() { |
| return getString(MAPIProperty.CONVERSATION_TOPIC); |
| } |
| |
| /** |
| * Returns the Message Body, as RTF, or null if the mapi property |
| * for this isn't set |
| */ |
| public String getBody() { |
| return getString(MAPIProperty.RTF_COMPRESSED); |
| } |
| } |