Home | History | Annotate | Download | only in field
      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 
     20 package org.apache.james.mime4j.field;
     21 
     22 import java.io.StringReader;
     23 import java.util.ArrayList;
     24 import java.util.Collections;
     25 import java.util.HashMap;
     26 import java.util.Map;
     27 
     28 //BEGIN android-changed: Stubbing out logging
     29 import org.apache.james.mime4j.Log;
     30 import org.apache.james.mime4j.LogFactory;
     31 //END android-changed
     32 import org.apache.james.mime4j.field.contenttype.parser.ContentTypeParser;
     33 import org.apache.james.mime4j.field.contenttype.parser.ParseException;
     34 import org.apache.james.mime4j.field.contenttype.parser.TokenMgrError;
     35 
     36 /**
     37  * Represents a <code>Content-Type</code> field.
     38  *
     39  * <p>TODO: Remove dependency on Java 1.4 regexps</p>
     40  *
     41  *
     42  * @version $Id: ContentTypeField.java,v 1.6 2005/01/27 14:16:31 ntherning Exp $
     43  */
     44 public class ContentTypeField extends Field {
     45 
     46     /**
     47      * The prefix of all <code>multipart</code> MIME types.
     48      */
     49     public static final String TYPE_MULTIPART_PREFIX = "multipart/";
     50     /**
     51      * The <code>multipart/digest</code> MIME type.
     52      */
     53     public static final String TYPE_MULTIPART_DIGEST = "multipart/digest";
     54     /**
     55      * The <code>text/plain</code> MIME type.
     56      */
     57     public static final String TYPE_TEXT_PLAIN = "text/plain";
     58     /**
     59      * The <code>message/rfc822</code> MIME type.
     60      */
     61     public static final String TYPE_MESSAGE_RFC822 = "message/rfc822";
     62     /**
     63      * The name of the <code>boundary</code> parameter.
     64      */
     65     public static final String PARAM_BOUNDARY = "boundary";
     66     /**
     67      * The name of the <code>charset</code> parameter.
     68      */
     69     public static final String PARAM_CHARSET = "charset";
     70 
     71     private String mimeType = "";
     72     private Map<String, String> parameters = null;
     73     private ParseException parseException;
     74 
     75     protected ContentTypeField(String name, String body, String raw, String mimeType, Map<String, String> parameters, ParseException parseException) {
     76         super(name, body, raw);
     77         this.mimeType = mimeType;
     78         this.parameters = parameters;
     79         this.parseException = parseException;
     80     }
     81 
     82     /**
     83      * Gets the exception that was raised during parsing of
     84      * the field value, if any; otherwise, null.
     85      */
     86     public ParseException getParseException() {
     87         return parseException;
     88     }
     89 
     90     /**
     91      * Gets the MIME type defined in this Content-Type field.
     92      *
     93      * @return the MIME type or an empty string if not set.
     94      */
     95     public String getMimeType() {
     96         return mimeType;
     97     }
     98 
     99     /**
    100      * Gets the MIME type defined in the child's
    101      * Content-Type field or derives a MIME type from the parent
    102      * if child is <code>null</code> or hasn't got a MIME type value set.
    103      * If child's MIME type is multipart but no boundary
    104      * has been set the MIME type of child will be derived from
    105      * the parent.
    106      *
    107      * @param child the child.
    108      * @param parent the parent.
    109      * @return the MIME type.
    110      */
    111     public static String getMimeType(ContentTypeField child,
    112                                      ContentTypeField parent) {
    113 
    114         if (child == null || child.getMimeType().length() == 0
    115                 || child.isMultipart() && child.getBoundary() == null) {
    116 
    117             if (parent != null && parent.isMimeType(TYPE_MULTIPART_DIGEST)) {
    118                 return TYPE_MESSAGE_RFC822;
    119             } else {
    120                 return TYPE_TEXT_PLAIN;
    121             }
    122         }
    123 
    124         return child.getMimeType();
    125     }
    126 
    127     /**
    128      * Gets the value of a parameter. Parameter names are case-insensitive.
    129      *
    130      * @param name the name of the parameter to get.
    131      * @return the parameter value or <code>null</code> if not set.
    132      */
    133     public String getParameter(String name) {
    134         return parameters != null
    135                     ? parameters.get(name.toLowerCase())
    136                     : null;
    137     }
    138 
    139     /**
    140      * Gets all parameters.
    141      *
    142      * @return the parameters.
    143      */
    144     public Map<String, String> getParameters() {
    145         if (parameters != null) {
    146             return Collections.unmodifiableMap(parameters);
    147         }
    148         return Collections.emptyMap();
    149     }
    150 
    151     /**
    152      * Gets the value of the <code>boundary</code> parameter if set.
    153      *
    154      * @return the <code>boundary</code> parameter value or <code>null</code>
    155      *             if not set.
    156      */
    157     public String getBoundary() {
    158         return getParameter(PARAM_BOUNDARY);
    159     }
    160 
    161     /**
    162      * Gets the value of the <code>charset</code> parameter if set.
    163      *
    164      * @return the <code>charset</code> parameter value or <code>null</code>
    165      *         if not set.
    166      */
    167     public String getCharset() {
    168         return getParameter(PARAM_CHARSET);
    169     }
    170 
    171     /**
    172      * Gets the value of the <code>charset</code> parameter if set for the
    173      * given field. Returns the default <code>us-ascii</code> if not set or if
    174      * <code>f</code> is <code>null</code>.
    175      *
    176      * @return the <code>charset</code> parameter value.
    177      */
    178     public static String getCharset(ContentTypeField f) {
    179         if (f != null) {
    180             if (f.getCharset() != null && f.getCharset().length() > 0) {
    181                 return f.getCharset();
    182             }
    183         }
    184         return "us-ascii";
    185     }
    186 
    187     /**
    188      * Determines if the MIME type of this field matches the given one.
    189      *
    190      * @param mimeType the MIME type to match against.
    191      * @return <code>true</code> if the MIME type of this field matches,
    192      *         <code>false</code> otherwise.
    193      */
    194     public boolean isMimeType(String mimeType) {
    195         return this.mimeType.equalsIgnoreCase(mimeType);
    196     }
    197 
    198     /**
    199      * Determines if the MIME type of this field is <code>multipart/*</code>.
    200      *
    201      * @return <code>true</code> if this field is has a <code>multipart/*</code>
    202      *         MIME type, <code>false</code> otherwise.
    203      */
    204     public boolean isMultipart() {
    205         return mimeType.startsWith(TYPE_MULTIPART_PREFIX);
    206     }
    207 
    208     public static class Parser implements FieldParser {
    209         private static Log log = LogFactory.getLog(Parser.class);
    210 
    211         public Field parse(final String name, final String body, final String raw) {
    212             ParseException parseException = null;
    213             String mimeType = "";
    214             Map<String, String> parameters = null;
    215 
    216             ContentTypeParser parser = new ContentTypeParser(new StringReader(body));
    217             try {
    218                 parser.parseAll();
    219             }
    220             catch (ParseException e) {
    221                 if (log.isDebugEnabled()) {
    222                     log.debug("Parsing value '" + body + "': "+ e.getMessage());
    223                 }
    224                 parseException = e;
    225             }
    226             catch (TokenMgrError e) {
    227                 if (log.isDebugEnabled()) {
    228                     log.debug("Parsing value '" + body + "': "+ e.getMessage());
    229                 }
    230                 parseException = new ParseException(e.getMessage());
    231             }
    232 
    233             try {
    234                 final String type = parser.getType();
    235                 final String subType = parser.getSubType();
    236 
    237                 if (type != null && subType != null) {
    238                     mimeType = (type + "/" + parser.getSubType()).toLowerCase();
    239 
    240                     ArrayList<String> paramNames = parser.getParamNames();
    241                     ArrayList<String> paramValues = parser.getParamValues();
    242 
    243                     if (paramNames != null && paramValues != null) {
    244                         for (int i = 0; i < paramNames.size() && i < paramValues.size(); i++) {
    245                             if (parameters == null)
    246                                 parameters = new HashMap<String, String>((int)(paramNames.size() * 1.3 + 1));
    247                             String paramName = paramNames.get(i).toLowerCase();
    248                             String paramValue = paramValues.get(i);
    249                             parameters.put(paramName, paramValue);
    250                         }
    251                     }
    252                 }
    253             }
    254             catch (NullPointerException npe) {
    255             }
    256             return new ContentTypeField(name, body, raw, mimeType, parameters, parseException);
    257         }
    258     }
    259 }
    260