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.field;
021    
022    import java.util.Collections;
023    import java.util.HashMap;
024    import java.util.Locale;
025    import java.util.Map;
026    
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.stream.Field;
031    import org.apache.james.mime4j.stream.NameValuePair;
032    import org.apache.james.mime4j.stream.RawBody;
033    import org.apache.james.mime4j.stream.RawField;
034    import org.apache.james.mime4j.stream.RawFieldParser;
035    
036    /**
037     * Represents a <code>Content-Type</code> field.
038     */
039    public class ContentTypeFieldLenientImpl extends AbstractField implements ContentTypeField {
040    
041        private boolean parsed = false;
042    
043        private String mimeType = null;
044        private String mediaType = null;
045        private String subType = null;
046        private Map<String, String> parameters = new HashMap<String, String>();
047    
048        ContentTypeFieldLenientImpl(final Field rawField, final DecodeMonitor monitor) {
049            super(rawField, monitor);
050        }
051    
052        public String getMimeType() {
053            if (!parsed) {
054                parse();
055            }
056            return mimeType;
057        }
058    
059        public String getMediaType() {
060            if (!parsed) {
061                parse();
062            }
063            return mediaType;
064        }
065    
066        public String getSubType() {
067            if (!parsed) {
068                parse();
069            }
070            return subType;
071        }
072    
073        public String getParameter(String name) {
074            if (!parsed) {
075                parse();
076            }
077            return parameters.get(name.toLowerCase());
078        }
079    
080        public Map<String, String> getParameters() {
081            if (!parsed) {
082                parse();
083            }
084            return Collections.unmodifiableMap(parameters);
085        }
086    
087        public boolean isMimeType(String mimeType) {
088            if (!parsed) {
089                parse();
090            }
091            return this.mimeType != null && this.mimeType.equalsIgnoreCase(mimeType);
092        }
093    
094        public boolean isMultipart() {
095            if (!parsed) {
096                parse();
097            }
098            return this.mimeType != null && mimeType.startsWith(TYPE_MULTIPART_PREFIX);
099        }
100    
101        public String getBoundary() {
102            return getParameter(PARAM_BOUNDARY);
103        }
104    
105        public String getCharset() {
106            return getParameter(PARAM_CHARSET);
107        }
108    
109        private void parse() {
110            parsed = true;
111            RawField f = getRawField();
112            RawBody body = RawFieldParser.DEFAULT.parseRawBody(f);
113            String main = body.getValue();
114            String type = null;
115            String subtype = null;
116            if (main != null) {
117                main = main.toLowerCase().trim();
118                int index = main.indexOf('/');
119                boolean valid = false;
120                if (index != -1) {
121                    type = main.substring(0, index).trim();
122                    subtype = main.substring(index + 1).trim();
123                    if (type.length() > 0 && subtype.length() > 0) {
124                        main = type + "/" + subtype;
125                        valid = true;
126                    }
127                }
128                if (!valid) {
129                    if (monitor.isListening()) {
130                        monitor.warn("Invalid Content-Type: " + body, "Content-Type value ignored");
131                    }
132                    main = null;
133                    type = null;
134                    subtype = null;
135                }
136            }
137            mimeType = main;
138            mediaType = type;
139            subType = subtype;
140            parameters.clear();
141            for (NameValuePair nmp: body.getParams()) {
142                String name = nmp.getName().toLowerCase(Locale.US);
143                parameters.put(name, nmp.getValue());
144            }
145        }
146    
147        public static final FieldParser<ContentTypeField> PARSER = new FieldParser<ContentTypeField>() {
148    
149            public ContentTypeField parse(final Field rawField, final DecodeMonitor monitor) {
150                return new ContentTypeFieldLenientImpl(rawField, monitor);
151            }
152    
153        };
154    
155    }