source: contrib/MailArchiver/sources/vendor/mime4j/custom/dom/src/main/java/org/apache/james/mime4j/message/MaximalBodyDescriptor.java @ 6785

Revision 6785, 19.0 KB checked in by rafaelraymundo, 12 years ago (diff)

Ticket #2946 - Liberado codigo do MailArchiver?. Documentação na subpasta DOCS.

Line 
1/****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one   *
3 * or more contributor license agreements.  See the NOTICE file *
4 * distributed with this work for additional information        *
5 * regarding copyright ownership.  The ASF licenses this file   *
6 * to you under the Apache License, Version 2.0 (the            *
7 * "License"); you may not use this file except in compliance   *
8 * with the License.  You may obtain a copy of the License at   *
9 *                                                              *
10 *   http://www.apache.org/licenses/LICENSE-2.0                 *
11 *                                                              *
12 * Unless required by applicable law or agreed to in writing,   *
13 * software distributed under the License is distributed on an  *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15 * KIND, either express or implied.  See the License for the    *
16 * specific language governing permissions and limitations      *
17 * under the License.                                           *
18 ****************************************************************/
19
20package org.apache.james.mime4j.message;
21
22import java.io.StringReader;
23import java.util.Collections;
24import java.util.HashMap;
25import java.util.List;
26import java.util.Locale;
27import java.util.Map;
28
29import org.apache.james.mime4j.MimeException;
30import org.apache.james.mime4j.codec.DecodeMonitor;
31import org.apache.james.mime4j.dom.datetime.DateTime;
32import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;
33import org.apache.james.mime4j.field.datetime.parser.ParseException;
34import org.apache.james.mime4j.field.language.parser.ContentLanguageParser;
35import org.apache.james.mime4j.field.mimeversion.parser.MimeVersionParser;
36import org.apache.james.mime4j.field.structured.parser.StructuredFieldParser;
37import org.apache.james.mime4j.stream.BodyDescriptor;
38import org.apache.james.mime4j.stream.DefaultBodyDescriptor;
39import org.apache.james.mime4j.stream.RawBody;
40import org.apache.james.mime4j.stream.MutableBodyDescriptor;
41import org.apache.james.mime4j.stream.NameValuePair;
42import org.apache.james.mime4j.stream.RawField;
43import org.apache.james.mime4j.stream.RawFieldParser;
44import org.apache.james.mime4j.util.MimeUtil;
45
46/**
47 * Parses and stores values for standard MIME header values.
48 *
49 */
50public class MaximalBodyDescriptor extends DefaultBodyDescriptor {
51
52    private static final int DEFAULT_MINOR_VERSION = 0;
53    private static final int DEFAULT_MAJOR_VERSION = 1;
54    private boolean isMimeVersionSet;
55    private int mimeMinorVersion;
56    private int mimeMajorVersion;
57    private MimeException mimeVersionException;
58    private String contentId;
59    private boolean isContentIdSet;
60    private String contentDescription;
61    private boolean isContentDescriptionSet;
62    private String contentDispositionType;
63    private Map<String, String> contentDispositionParameters;
64    private DateTime contentDispositionModificationDate;
65    private MimeException contentDispositionModificationDateParseException;
66    private DateTime contentDispositionCreationDate;
67    private MimeException contentDispositionCreationDateParseException;
68    private DateTime contentDispositionReadDate;
69    private MimeException contentDispositionReadDateParseException;
70    private long contentDispositionSize;
71    private MimeException contentDispositionSizeParseException;
72    private boolean isContentDispositionSet;
73    private List<String> contentLanguage;
74    private MimeException contentLanguageParseException;
75    private boolean isContentLanguageSet;
76    private MimeException contentLocationParseException;
77    private String contentLocation;
78    private boolean isContentLocationSet;
79    private String contentMD5Raw;
80    private boolean isContentMD5Set;
81   
82    protected MaximalBodyDescriptor() {
83        this(null, null);
84    }
85
86    public MaximalBodyDescriptor(final BodyDescriptor parent, final DecodeMonitor monitor) {
87        super(parent, monitor);
88        isMimeVersionSet = false;
89        mimeMajorVersion = DEFAULT_MAJOR_VERSION;
90        mimeMinorVersion = DEFAULT_MINOR_VERSION;
91        this.contentId = null;
92        this.isContentIdSet = false;
93        this.contentDescription = null;
94        this.isContentDescriptionSet = false;
95        this.contentDispositionType = null;
96        this.contentDispositionParameters = Collections.emptyMap();
97        this.contentDispositionModificationDate = null;
98        this.contentDispositionModificationDateParseException = null;
99        this.contentDispositionCreationDate = null;
100        this.contentDispositionCreationDateParseException = null;
101        this.contentDispositionReadDate = null;
102        this.contentDispositionReadDateParseException = null;
103        this.contentDispositionSize = -1;
104        this.contentDispositionSizeParseException = null;
105        this.isContentDispositionSet = false;
106        this.contentLanguage = null;
107        this.contentLanguageParseException = null;
108        this.isContentIdSet = false;
109        this.contentLocation = null;
110        this.contentLocationParseException = null;
111        this.isContentLocationSet = false;
112        this.contentMD5Raw = null;
113        this.isContentMD5Set = false;
114    }
115
116    @Override
117    public MutableBodyDescriptor newChild() {
118        return new MaximalBodyDescriptor(this, getDecodeMonitor());
119    }
120
121    @Override
122    public void addField(RawField field) throws MimeException {
123        String name = field.getName().toLowerCase(Locale.US);;
124        if (MimeUtil.MIME_HEADER_MIME_VERSION.equals(name) && !isMimeVersionSet) {
125            parseMimeVersion(field);
126        } else if (MimeUtil.MIME_HEADER_CONTENT_ID.equals(name) && !isContentIdSet) {
127            parseContentId(field);
128        } else if (MimeUtil.MIME_HEADER_CONTENT_DESCRIPTION.equals(name) && !isContentDescriptionSet) {
129            parseContentDescription(field);
130        } else if (MimeUtil.MIME_HEADER_CONTENT_DISPOSITION.equals(name) && !isContentDispositionSet) {
131            parseContentDisposition(field);
132        } else if (MimeUtil.MIME_HEADER_LANGAUGE.equals(name) && !isContentLanguageSet) {
133            parseLanguage(field);
134        } else if (MimeUtil.MIME_HEADER_LOCATION.equals(name) && !isContentLocationSet) {
135            parseLocation(field);
136        } else if (MimeUtil.MIME_HEADER_MD5.equals(name) && !isContentMD5Set) {
137            parseMD5(field);
138        } else {
139            super.addField(field);
140        }
141    }
142   
143    private void parseMD5(final RawField field) {
144        String value = field.getBody();
145        isContentMD5Set = true;
146        if (value != null) {
147            contentMD5Raw = value.trim();
148        }
149    }
150
151    private void parseLocation(final RawField field) {
152        isContentLocationSet = true;
153        String value = field.getBody();
154        if (value != null) {
155            final StringReader stringReader = new StringReader(value);
156            final StructuredFieldParser parser = new StructuredFieldParser(stringReader);
157            try {
158                // From RFC2017 3.1
159                /*
160                 * Extraction of the URL string from the URL-parameter is even simpler:
161                 * The enclosing quotes and any linear whitespace are removed and the
162                 * remaining material is the URL string.
163                 * Read more: http://www.faqs.org/rfcs/rfc2017.html#ixzz0aufO9nRL
164                 */
165                contentLocation = parser.parse().replaceAll("\\s", "");
166            } catch (MimeException e) {
167                contentLocationParseException = e;
168            }
169        }
170    }
171   
172    private void parseLanguage(final RawField field) {
173        isContentLanguageSet = true;
174        String value = field.getBody();
175        if (value != null) {
176            try {
177                final ContentLanguageParser parser = new ContentLanguageParser(new StringReader(value));
178                contentLanguage = parser.parse();
179            } catch (MimeException e) {
180                contentLanguageParseException = e;
181            }
182        }
183    }
184
185    private void parseContentDisposition(final RawField field) throws MimeException {
186        isContentDispositionSet = true;
187        RawBody body = RawFieldParser.DEFAULT.parseRawBody(field);
188        Map<String, String> params = new HashMap<String, String>();
189        for (NameValuePair nmp: body.getParams()) {
190            String name = nmp.getName().toLowerCase(Locale.US);
191            params.put(name, nmp.getValue());
192        }
193       
194        contentDispositionType = body.getValue();
195        contentDispositionParameters = params;
196       
197        final String contentDispositionModificationDate
198            = contentDispositionParameters.get(MimeUtil.PARAM_MODIFICATION_DATE);
199        if (contentDispositionModificationDate != null) {
200            try {
201                this.contentDispositionModificationDate = parseDate(contentDispositionModificationDate);
202            } catch (ParseException e) {
203                this.contentDispositionModificationDateParseException = e;
204            }
205        }
206       
207        final String contentDispositionCreationDate
208            = contentDispositionParameters.get(MimeUtil.PARAM_CREATION_DATE);
209        if (contentDispositionCreationDate != null) {
210            try {
211                this.contentDispositionCreationDate = parseDate(contentDispositionCreationDate);
212            } catch (ParseException e) {
213                this.contentDispositionCreationDateParseException = e;
214            }         
215        }
216       
217        final String contentDispositionReadDate
218            = contentDispositionParameters.get(MimeUtil.PARAM_READ_DATE);
219        if (contentDispositionReadDate != null) {
220            try {
221                this.contentDispositionReadDate = parseDate(contentDispositionReadDate);
222            } catch (ParseException e) {
223                this.contentDispositionReadDateParseException = e;
224            }         
225        }
226       
227        final String size = contentDispositionParameters.get(MimeUtil.PARAM_SIZE);
228        if (size != null) {
229            try {
230                contentDispositionSize = Long.parseLong(size);
231            } catch (NumberFormatException e) {
232                this.contentDispositionSizeParseException = (MimeException) new MimeException(e.getMessage(), e).fillInStackTrace();
233            }
234        }
235        contentDispositionParameters.remove("");
236    }
237
238    private DateTime parseDate(final String date) throws ParseException {
239        final StringReader stringReader = new StringReader(date);
240        final DateTimeParser parser = new DateTimeParser(stringReader);
241        DateTime result = parser.date_time();
242        return result;
243    }
244   
245    private void parseContentDescription(final RawField field) {
246        String value = field.getBody();
247        if (value == null) {
248            contentDescription = "";
249        } else {
250            contentDescription = value.trim();
251        }
252        isContentDescriptionSet = true;
253    }
254
255    private void parseContentId(final RawField field) {
256        String value = field.getBody();
257        if (value == null) {
258            contentId = "";
259        } else {
260            contentId = value.trim();
261        }
262        isContentIdSet = true;
263    }
264
265    private void parseMimeVersion(RawField field) {
266        final StringReader reader = new StringReader(field.getBody());
267        final MimeVersionParser parser = new MimeVersionParser(reader);
268        try {
269            parser.parse();
270            final int major = parser.getMajorVersion();
271            if (major != MimeVersionParser.INITIAL_VERSION_VALUE) {
272                mimeMajorVersion = major;
273            }
274            final int minor = parser.getMinorVersion();
275            if (minor != MimeVersionParser.INITIAL_VERSION_VALUE) {
276                mimeMinorVersion = minor;
277            }
278        } catch (MimeException e) {
279            this.mimeVersionException = e;
280        }
281        isMimeVersionSet = true;
282    }
283   
284    /**
285     * Gets the MIME major version
286     * as specified by the <code>MIME-Version</code>
287     * header.
288     * Defaults to one.
289     * @return positive integer
290     */
291    public int getMimeMajorVersion() {
292        return mimeMajorVersion;
293    }
294   
295    /**
296     * Gets the MIME minor version
297     * as specified by the <code>MIME-Version</code>
298     * header.
299     * Defaults to zero.
300     * @return positive integer
301     */
302    public int getMimeMinorVersion() {
303        return mimeMinorVersion;
304    }
305   
306
307    /**
308     * When the MIME version header exists but cannot be parsed
309     * this field will be contain the exception.
310     * @return <code>MimeException</code> if the mime header cannot
311     * be parsed, null otherwise
312     */
313    public MimeException getMimeVersionParseException() {
314        return mimeVersionException;
315    }
316   
317    /**
318     * Gets the value of the <a href='http://www.faqs.org/rfcs/rfc2045'>RFC</a>
319     * <code>Content-Description</code> header.
320     * @return value of the <code>Content-Description</code> when present,
321     * null otherwise
322     */
323    public String getContentDescription() {
324        return contentDescription;
325    }
326   
327    /**
328     * Gets the value of the <a href='http://www.faqs.org/rfcs/rfc2045'>RFC</a>
329     * <code>Content-ID</code> header.
330     * @return value of the <code>Content-ID</code> when present,
331     * null otherwise
332     */
333    public String getContentId() {
334        return contentId;
335    }
336   
337    /**
338     * Gets the disposition type of the <code>content-disposition</code> field.
339     * The value is case insensitive and will be converted to lower case.
340     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
341     * @return content disposition type,
342     * or null when this has not been set
343     */
344    public String getContentDispositionType() {
345        return contentDispositionType;
346    }
347   
348    /**
349     * Gets the parameters of the <code>content-disposition</code> field.
350     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
351     * @return parameter value strings indexed by parameter name strings,
352     * not null
353     */
354    public Map<String, String> getContentDispositionParameters() {
355        return contentDispositionParameters;
356    }
357   
358    /**
359     * Gets the <code>filename</code> parameter value of the <code>content-disposition</code> field.
360     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
361     * @return filename parameter value,
362     * or null when it is not present
363     */
364    public String getContentDispositionFilename() {
365        return contentDispositionParameters.get(MimeUtil.PARAM_FILENAME);
366    }
367   
368    /**
369     * Gets the <code>modification-date</code> parameter value of the <code>content-disposition</code> field.
370     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
371     * @return modification-date parameter value,
372     * or null when this is not present
373     */
374    public DateTime getContentDispositionModificationDate() {
375        return contentDispositionModificationDate;
376    }
377   
378    /**
379     * Gets any exception thrown during the parsing of {@link #getContentDispositionModificationDate()}
380     * @return <code>ParseException</code> when the modification-date parse fails,
381     * null otherwise
382     */
383    public MimeException getContentDispositionModificationDateParseException() {
384        return contentDispositionModificationDateParseException;
385    }
386   
387    /**
388     * Gets the <code>creation-date</code> parameter value of the <code>content-disposition</code> field.
389     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
390     * @return creation-date parameter value,
391     * or null when this is not present
392     */
393    public DateTime getContentDispositionCreationDate() {
394        return contentDispositionCreationDate;
395    }
396   
397    /**
398     * Gets any exception thrown during the parsing of {@link #getContentDispositionCreationDate()}
399     * @return <code>ParseException</code> when the creation-date parse fails,
400     * null otherwise
401     */
402    public MimeException getContentDispositionCreationDateParseException() {
403        return contentDispositionCreationDateParseException;
404    }
405   
406    /**
407     * Gets the <code>read-date</code> parameter value of the <code>content-disposition</code> field.
408     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
409     * @return read-date parameter value,
410     * or null when this is not present
411     */
412    public DateTime getContentDispositionReadDate() {
413        return contentDispositionReadDate;
414    }
415   
416    /**
417     * Gets any exception thrown during the parsing of {@link #getContentDispositionReadDate()}
418     * @return <code>ParseException</code> when the read-date parse fails,
419     * null otherwise
420     */
421    public MimeException getContentDispositionReadDateParseException() {
422        return contentDispositionReadDateParseException;
423    }
424   
425    /**
426     * Gets the <code>size</code> parameter value of the <code>content-disposition</code> field.
427     * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>.
428     * @return size parameter value,
429     * or -1 if this size has not been set
430     */
431    public long getContentDispositionSize() {
432        return contentDispositionSize;
433    }
434   
435    /**
436     * Gets any exception thrown during the parsing of {@link #getContentDispositionSize()}
437     * @return <code>ParseException</code> when the read-date parse fails,
438     * null otherwise
439     */
440    public MimeException getContentDispositionSizeParseException() {
441        return contentDispositionSizeParseException;
442    }
443   
444    /**
445     * Get the <code>content-language</code> header values.
446     * Each applicable language tag will be returned in order.
447     * See <a href='http://tools.ietf.org/html/rfc4646'>RFC4646</a>
448     * <cite>http://tools.ietf.org/html/rfc4646</cite>.
449     * @return list of language tag Strings,
450     * or null if no header exists
451     */
452    public List<String> getContentLanguage() {
453        return contentLanguage;
454    }
455
456    /**
457     * Gets any exception thrown during the parsing of {@link #getContentLanguage()}
458     * @return <code>ParseException</code> when the content-language parse fails,
459     * null otherwise
460     */
461    public MimeException getContentLanguageParseException() {
462        return contentLanguageParseException;
463    }
464   
465
466    /**
467     * Get the <code>content-location</code> header value.
468     * See <a href='http://tools.ietf.org/html/rfc2557'>RFC2557</a>
469     * @return the URL content-location
470     * or null if no header exists
471     */
472    public String getContentLocation() {
473        return contentLocation;
474    }
475   
476    /**
477     * Gets any exception thrown during the parsing of {@link #getContentLocation()}
478     * @return <code>ParseException</code> when the content-language parse fails,
479     * null otherwise
480     */
481    public MimeException getContentLocationParseException() {
482        return contentLocationParseException;
483    }
484   
485    /**
486     * Gets the raw, Base64 encoded value of the
487     * <code>Content-MD5</code> field.
488     * See <a href='http://tools.ietf.org/html/rfc1864'>RFC1864</a>.
489     * @return raw encoded content-md5
490     * or null if no header exists
491     */
492    public String getContentMD5Raw() {
493        return contentMD5Raw;
494    }
495   
496   
497}
Note: See TracBrowser for help on using the repository browser.