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
020package org.apache.james.mime4j.field;
021
022import java.util.Collections;
023import java.util.HashMap;
024import java.util.Locale;
025import java.util.Map;
026
027import org.apache.james.mime4j.codec.DecodeMonitor;
028import org.apache.james.mime4j.dom.FieldParser;
029import org.apache.james.mime4j.dom.field.ContentTypeField;
030import org.apache.james.mime4j.stream.Field;
031import org.apache.james.mime4j.stream.NameValuePair;
032import org.apache.james.mime4j.stream.RawBody;
033import org.apache.james.mime4j.stream.RawField;
034import org.apache.james.mime4j.stream.RawFieldParser;
035
036/**
037 * Represents a <code>Content-Type</code> field.
038 */
039public 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}