001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    
020    package org.apache.james.mime4j.message;
021    
022    import java.util.Collections;
023    import java.util.Date;
024    import java.util.HashMap;
025    import java.util.List;
026    import java.util.Locale;
027    import java.util.Map;
028    
029    import org.apache.james.mime4j.dom.field.ContentDescriptionField;
030    import org.apache.james.mime4j.dom.field.ContentDispositionField;
031    import org.apache.james.mime4j.dom.field.ContentIdField;
032    import org.apache.james.mime4j.dom.field.ContentLanguageField;
033    import org.apache.james.mime4j.dom.field.ContentLengthField;
034    import org.apache.james.mime4j.dom.field.ContentLocationField;
035    import org.apache.james.mime4j.dom.field.ContentMD5Field;
036    import org.apache.james.mime4j.dom.field.ContentTransferEncodingField;
037    import org.apache.james.mime4j.dom.field.ContentTypeField;
038    import org.apache.james.mime4j.dom.field.FieldName;
039    import org.apache.james.mime4j.dom.field.MimeVersionField;
040    import org.apache.james.mime4j.dom.field.ParsedField;
041    import org.apache.james.mime4j.field.MimeVersionFieldImpl;
042    import org.apache.james.mime4j.stream.BodyDescriptor;
043    import org.apache.james.mime4j.util.MimeUtil;
044    
045    /**
046     * Extended {@link BodyDescriptor} implementation with complete content details.
047     */
048    public class MaximalBodyDescriptor implements BodyDescriptor {
049    
050        private static final String CONTENT_TYPE = FieldName.CONTENT_TYPE.toLowerCase(Locale.US);
051        private static final String CONTENT_LENGTH = FieldName.CONTENT_LENGTH.toLowerCase(Locale.US);
052        private static final String CONTENT_TRANSFER_ENCODING = FieldName.CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.US);
053        private static final String CONTENT_DISPOSITION = FieldName.CONTENT_DISPOSITION.toLowerCase(Locale.US);
054        private static final String CONTENT_ID = FieldName.CONTENT_ID.toLowerCase(Locale.US);
055        private static final String CONTENT_MD5 = FieldName.CONTENT_MD5.toLowerCase(Locale.US);
056        private static final String CONTENT_DESCRIPTION = FieldName.CONTENT_DESCRIPTION.toLowerCase(Locale.US);
057        private static final String CONTENT_LANGUAGE = FieldName.CONTENT_LANGUAGE.toLowerCase(Locale.US);
058        private static final String CONTENT_LOCATION = FieldName.CONTENT_LOCATION.toLowerCase(Locale.US);
059        private static final String MIME_VERSION = FieldName.MIME_VERSION.toLowerCase(Locale.US);
060    
061        private final String mediaType;
062        private final String subType;
063        private final String mimeType;
064        private final String boundary;
065        private final String charset;
066        private final Map<String, ParsedField> fields;
067    
068        MaximalBodyDescriptor(
069                final String mimeType,
070                final String mediaType,
071                final String subType,
072                final String boundary,
073                final String charset,
074                final Map<String, ParsedField> fields) {
075            super();
076            this.mimeType = mimeType;
077            this.mediaType = mediaType;
078            this.subType = subType;
079            this.boundary = boundary;
080            this.charset = charset;
081            this.fields = fields != null ? new HashMap<String, ParsedField>(fields) :
082                Collections.<String, ParsedField>emptyMap();
083        }
084    
085        public String getMimeType() {
086            return mimeType;
087        }
088    
089        public String getBoundary() {
090            return boundary;
091        }
092    
093        public String getCharset() {
094            return charset;
095        }
096    
097        public String getMediaType() {
098            return mediaType;
099        }
100    
101        public String getSubType() {
102            return subType;
103        }
104    
105        public Map<String, String> getContentTypeParameters() {
106            ContentTypeField contentTypeField = (ContentTypeField) fields.get(CONTENT_TYPE);
107            return contentTypeField != null ? contentTypeField.getParameters() :
108                Collections.<String, String>emptyMap();
109        }
110    
111        public String getTransferEncoding() {
112            ContentTransferEncodingField contentTransferEncodingField =
113                (ContentTransferEncodingField) fields.get(CONTENT_TRANSFER_ENCODING);
114            return contentTransferEncodingField != null ? contentTransferEncodingField.getEncoding() :
115                MimeUtil.ENC_7BIT;
116        }
117    
118        public long getContentLength() {
119            ContentLengthField contentLengthField = (ContentLengthField) fields.get(CONTENT_LENGTH);
120            return contentLengthField != null ? contentLengthField.getContentLength() : -1;
121        }
122    
123        /**
124         * Gets the MIME major version
125         * as specified by the <code>MIME-Version</code>
126         * header.
127         * Defaults to one.
128         * @return positive integer
129         */
130        public int getMimeMajorVersion() {
131            MimeVersionField mimeVersionField = (MimeVersionField) fields.get(MIME_VERSION);
132            return mimeVersionField != null ? mimeVersionField.getMajorVersion() :
133                MimeVersionFieldImpl.DEFAULT_MAJOR_VERSION;
134        }
135    
136        /**
137         * Gets the MIME minor version
138         * as specified by the <code>MIME-Version</code>
139         * header.
140         * Defaults to zero.
141         * @return positive integer
142         */
143        public int getMimeMinorVersion() {
144            MimeVersionField mimeVersionField = (MimeVersionField) fields.get(MIME_VERSION);
145            return mimeVersionField != null ? mimeVersionField.getMinorVersion() :
146                MimeVersionFieldImpl.DEFAULT_MINOR_VERSION;
147        }
148    
149    
150        /**
151         * Gets the value of the <a href='http://www.faqs.org/rfcs/rfc2045'>RFC</a>
152         * <code>Content-Description</code> header.
153         * @return value of the <code>Content-Description</code> when present,
154         * null otherwise
155         */
156        public String getContentDescription() {
157            ContentDescriptionField contentDescriptionField =
158                (ContentDescriptionField) fields.get(CONTENT_DESCRIPTION);
159            return contentDescriptionField != null ? contentDescriptionField.getDescription() : null;
160        }
161    
162        /**
163         * Gets the value of the <a href='http://www.faqs.org/rfcs/rfc2045'>RFC</a>
164         * <code>Content-ID</code> header.
165         * @return value of the <code>Content-ID</code> when present,
166         * null otherwise
167         */
168        public String getContentId() {
169            ContentIdField contentIdField = (ContentIdField) fields.get(CONTENT_ID);
170            return contentIdField != null ? contentIdField.getId() : null;
171        }
172    
173        /**
174         * Gets the disposition type of the <code>content-disposition</code> field.
175         * The value is case insensitive and will be converted to lower case.
176         * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
177         * @return content disposition type,
178         * or null when this has not been set
179         */
180        public String getContentDispositionType() {
181            ContentDispositionField contentDispositionField =
182                (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
183            return contentDispositionField != null ? contentDispositionField.getDispositionType() : null;
184        }
185    
186        /**
187         * Gets the parameters of the <code>content-disposition</code> field.
188         * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
189         * @return parameter value strings indexed by parameter name strings,
190         * not null
191         */
192        public Map<String, String> getContentDispositionParameters() {
193            ContentDispositionField contentDispositionField =
194                (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
195            return contentDispositionField != null ? contentDispositionField.getParameters() :
196                Collections.<String, String>emptyMap();
197        }
198    
199        /**
200         * Gets the <code>filename</code> parameter value of the <code>content-disposition</code> field.
201         * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
202         * @return filename parameter value,
203         * or null when it is not present
204         */
205        public String getContentDispositionFilename() {
206            ContentDispositionField contentDispositionField =
207                (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
208            return contentDispositionField != null ? contentDispositionField.getFilename() : null;
209        }
210    
211        /**
212         * Gets the <code>modification-date</code> parameter value of the <code>content-disposition</code> field.
213         * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
214         * @return modification-date parameter value,
215         * or null when this is not present
216         */
217        public Date getContentDispositionModificationDate() {
218            ContentDispositionField contentDispositionField =
219                (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
220            return contentDispositionField != null ? contentDispositionField.getModificationDate() : null;
221        }
222    
223        /**
224         * Gets the <code>creation-date</code> parameter value of the <code>content-disposition</code> field.
225         * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
226         * @return creation-date parameter value,
227         * or null when this is not present
228         */
229        public Date getContentDispositionCreationDate() {
230            ContentDispositionField contentDispositionField =
231                (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
232            return contentDispositionField != null ? contentDispositionField.getCreationDate() : null;
233        }
234    
235        /**
236         * Gets the <code>read-date</code> parameter value of the <code>content-disposition</code> field.
237         * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
238         * @return read-date parameter value,
239         * or null when this is not present
240         */
241        public Date getContentDispositionReadDate() {
242            ContentDispositionField contentDispositionField =
243                (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
244            return contentDispositionField != null ? contentDispositionField.getReadDate() : null;
245        }
246    
247        /**
248         * Gets the <code>size</code> parameter value of the <code>content-disposition</code> field.
249         * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
250         * @return size parameter value,
251         * or -1 if this size has not been set
252         */
253        public long getContentDispositionSize() {
254            ContentDispositionField contentDispositionField =
255                (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
256            return contentDispositionField != null ? contentDispositionField.getSize() : -1;
257        }
258    
259        /**
260         * Get the <code>content-language</code> header values.
261         * Each applicable language tag will be returned in order.
262         * See <a href='http://tools.ietf.org/html/rfc4646'>RFC4646</a>
263         * <cite>http://tools.ietf.org/html/rfc4646</cite>.
264         * @return list of language tag Strings,
265         * or null if no header exists
266         */
267        public List<String> getContentLanguage() {
268            ContentLanguageField contentLanguageField =
269                (ContentLanguageField) fields.get(CONTENT_LANGUAGE);
270            return contentLanguageField != null ? contentLanguageField.getLanguages() :
271                Collections.<String>emptyList();
272        }
273    
274        /**
275         * Get the <code>content-location</code> header value.
276         * See <a href='http://tools.ietf.org/html/rfc2557'>RFC2557</a>
277         * @return the URL content-location
278         * or null if no header exists
279         */
280        public String getContentLocation() {
281            ContentLocationField contentLocationField =
282                (ContentLocationField) fields.get(CONTENT_LOCATION);
283            return contentLocationField != null ? contentLocationField.getLocation() : null;
284        }
285    
286        /**
287         * Gets the raw, Base64 encoded value of the
288         * <code>Content-MD5</code> field.
289         * See <a href='http://tools.ietf.org/html/rfc1864'>RFC1864</a>.
290         * @return raw encoded content-md5
291         * or null if no header exists
292         */
293        public String getContentMD5Raw() {
294            ContentMD5Field contentMD5Field = (ContentMD5Field) fields.get(CONTENT_MD5);
295            return contentMD5Field != null ? contentMD5Field.getMD5Raw() : null;
296        }
297    
298        @Override
299        public String toString() {
300            StringBuilder sb = new StringBuilder();
301            sb.append("[mimeType=");
302            sb.append(mimeType);
303            sb.append(", mediaType=");
304            sb.append(mediaType);
305            sb.append(", subType=");
306            sb.append(subType);
307            sb.append(", boundary=");
308            sb.append(boundary);
309            sb.append(", charset=");
310            sb.append(charset);
311            sb.append("]");
312            return sb.toString();
313        }
314    
315    }