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.HashMap;
023    import java.util.Locale;
024    import java.util.Map;
025    
026    import org.apache.james.mime4j.MimeException;
027    import org.apache.james.mime4j.codec.DecodeMonitor;
028    import org.apache.james.mime4j.dom.FieldParser;
029    import org.apache.james.mime4j.dom.field.ContentTypeField;
030    import org.apache.james.mime4j.dom.field.FieldName;
031    import org.apache.james.mime4j.dom.field.ParsedField;
032    import org.apache.james.mime4j.field.DefaultFieldParser;
033    import org.apache.james.mime4j.stream.BodyDescriptor;
034    import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
035    import org.apache.james.mime4j.stream.Field;
036    import org.apache.james.mime4j.stream.RawField;
037    import org.apache.james.mime4j.util.MimeUtil;
038    
039    /**
040     * Default {@link BodyDescriptorBuilder} implementation.
041     */
042    public class DefaultBodyDescriptorBuilder implements BodyDescriptorBuilder {
043    
044        private static final String CONTENT_TYPE = FieldName.CONTENT_TYPE.toLowerCase(Locale.US);
045    
046        private static final String US_ASCII = "us-ascii";
047        private static final String SUB_TYPE_EMAIL = "rfc822";
048        private static final String MEDIA_TYPE_TEXT = "text";
049        private static final String MEDIA_TYPE_MESSAGE = "message";
050        private static final String EMAIL_MESSAGE_MIME_TYPE = MEDIA_TYPE_MESSAGE + "/" + SUB_TYPE_EMAIL;
051        private static final String DEFAULT_SUB_TYPE = "plain";
052        private static final String DEFAULT_MEDIA_TYPE = MEDIA_TYPE_TEXT;
053        private static final String DEFAULT_MIME_TYPE = DEFAULT_MEDIA_TYPE + "/" + DEFAULT_SUB_TYPE;
054    
055        private final String parentMimeType;
056        private final DecodeMonitor monitor;
057        private final FieldParser<? extends ParsedField> fieldParser;
058        private final Map<String, ParsedField> fields;
059    
060        /**
061         * Creates a new root <code>BodyDescriptor</code> instance.
062         */
063        public DefaultBodyDescriptorBuilder() {
064            this(null);
065        }
066    
067        public DefaultBodyDescriptorBuilder(final String parentMimeType) {
068            this(parentMimeType, null, null);
069        }
070    
071        /**
072         * Creates a new <code>BodyDescriptor</code> instance.
073         */
074        public DefaultBodyDescriptorBuilder(
075                final String parentMimeType,
076                final FieldParser<? extends ParsedField> fieldParser,
077                final DecodeMonitor monitor) {
078            super();
079            this.parentMimeType = parentMimeType;
080            this.fieldParser = fieldParser != null ? fieldParser : DefaultFieldParser.getParser();
081            this.monitor = monitor != null ? monitor : DecodeMonitor.SILENT;
082            this.fields = new HashMap<String, ParsedField>();
083        }
084    
085        public void reset() {
086            fields.clear();
087        }
088    
089        public Field addField(final RawField rawfield) throws MimeException {
090            ParsedField field = fieldParser.parse(rawfield, monitor);
091            String name = field.getName().toLowerCase(Locale.US);
092            if (!fields.containsKey(name)) {
093                fields.put(name, field);
094            }
095            return field;
096        }
097    
098        public BodyDescriptor build() {
099            String actualMimeType = null;
100            String actualMediaType = null;
101            String actualSubType = null;
102            String actualCharset = null;
103            String actualBoundary = null;
104            ContentTypeField contentTypeField = (ContentTypeField) fields.get(CONTENT_TYPE);
105            if (contentTypeField != null) {
106                actualMimeType = contentTypeField.getMimeType();
107                actualMediaType = contentTypeField.getMediaType();
108                actualSubType = contentTypeField.getSubType();
109                actualCharset = contentTypeField.getCharset();
110                actualBoundary = contentTypeField.getBoundary();
111            }
112            if (actualMimeType == null) {
113                if (MimeUtil.isSameMimeType("multipart/digest", parentMimeType)) {
114                    actualMimeType = EMAIL_MESSAGE_MIME_TYPE;
115                    actualMediaType = MEDIA_TYPE_MESSAGE;
116                    actualSubType = SUB_TYPE_EMAIL;
117                } else {
118                    actualMimeType = DEFAULT_MIME_TYPE;
119                    actualMediaType = DEFAULT_MEDIA_TYPE;
120                    actualSubType = DEFAULT_SUB_TYPE;
121                }
122            }
123            if (actualCharset == null && MEDIA_TYPE_TEXT.equals(actualMediaType)) {
124                actualCharset = US_ASCII;
125            }
126            if (!MimeUtil.isMultipart(actualMimeType)) {
127                actualBoundary = null;
128            }
129            return new MaximalBodyDescriptor(
130                    actualMimeType, actualMediaType, actualSubType, actualBoundary, actualCharset,
131                    fields);
132        }
133    
134        public BodyDescriptorBuilder newChild() {
135            String actualMimeType;
136            ContentTypeField contentTypeField = (ContentTypeField) fields.get(CONTENT_TYPE);
137            if (contentTypeField != null) {
138                actualMimeType = contentTypeField.getMimeType();
139            } else {
140                if (MimeUtil.isSameMimeType("multipart/digest", parentMimeType)) {
141                    actualMimeType = EMAIL_MESSAGE_MIME_TYPE;
142                } else {
143                    actualMimeType = DEFAULT_MIME_TYPE;
144                }
145            }
146            return new DefaultBodyDescriptorBuilder(actualMimeType, fieldParser, monitor);
147        }
148    
149    }