View Javadoc

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.descriptor;
21  
22  import java.util.HashMap;
23  import java.util.Map;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.james.mime4j.parser.Field;
28  import org.apache.james.mime4j.util.MimeUtil;
29  
30  /**
31   * Encapsulates the values of the MIME-specific header fields 
32   * (which starts with <code>Content-</code>). 
33   */
34  public class DefaultBodyDescriptor implements MutableBodyDescriptor {
35      private static final String US_ASCII = "us-ascii";
36  
37      private static final String SUB_TYPE_EMAIL = "rfc822";
38  
39      private static final String MEDIA_TYPE_TEXT = "text";
40  
41      private static final String MEDIA_TYPE_MESSAGE = "message";
42  
43      private static final String EMAIL_MESSAGE_MIME_TYPE = MEDIA_TYPE_MESSAGE + "/" + SUB_TYPE_EMAIL;
44  
45      private static final String DEFAULT_SUB_TYPE = "plain";
46  
47      private static final String DEFAULT_MEDIA_TYPE = MEDIA_TYPE_TEXT;
48  
49      private static final String DEFAULT_MIME_TYPE = DEFAULT_MEDIA_TYPE + "/" + DEFAULT_SUB_TYPE;
50  
51      private static Log log = LogFactory.getLog(DefaultBodyDescriptor.class);
52      
53      private String mediaType = DEFAULT_MEDIA_TYPE;
54      private String subType = DEFAULT_SUB_TYPE;
55      private String mimeType = DEFAULT_MIME_TYPE;
56      private String boundary = null;
57      private String charset = US_ASCII;
58      private String transferEncoding = "7bit";
59      private Map<String, String> parameters = new HashMap<String, String>();
60      private boolean contentTypeSet;
61      private boolean contentTransferEncSet;
62      private long contentLength = -1;
63      
64      /**
65       * Creates a new root <code>BodyDescriptor</code> instance.
66       */
67      public DefaultBodyDescriptor() {
68          this(null);
69      }
70  
71      /**
72       * Creates a new <code>BodyDescriptor</code> instance.
73       * 
74       * @param parent the descriptor of the parent or <code>null</code> if this
75       *        is the root descriptor.
76       */
77      public DefaultBodyDescriptor(BodyDescriptor parent) {
78          if (parent != null && MimeUtil.isSameMimeType("multipart/digest", parent.getMimeType())) {
79              mimeType = EMAIL_MESSAGE_MIME_TYPE;
80              subType = SUB_TYPE_EMAIL;
81              mediaType = MEDIA_TYPE_MESSAGE;
82          } else {
83              mimeType = DEFAULT_MIME_TYPE;
84              subType = DEFAULT_SUB_TYPE;
85              mediaType = DEFAULT_MEDIA_TYPE;
86          }
87      }
88      
89      /**
90       * Should be called for each <code>Content-</code> header field of 
91       * a MIME message or part.
92       * 
93       * @param field the MIME field.
94       */
95      public void addField(Field field) {
96          String name = field.getName();
97          String value = field.getBody();
98  
99          name = name.trim().toLowerCase();
100         
101         if (name.equals("content-transfer-encoding") && !contentTransferEncSet) {
102             contentTransferEncSet = true;
103             
104             value = value.trim().toLowerCase();
105             if (value.length() > 0) {
106                 transferEncoding = value;
107             }
108             
109         } else if (name.equals("content-length") && contentLength == -1) {
110             try {
111                 contentLength = Long.parseLong(value.trim());
112             } catch (NumberFormatException e) {
113                 log.error("Invalid content-length: " + value);
114             }
115         } else if (name.equals("content-type") && !contentTypeSet) {
116             parseContentType(value);
117         }
118     }
119 
120     private void parseContentType(String value) {
121         contentTypeSet = true;
122         
123         Map<String, String> params = MimeUtil.getHeaderParams(value);
124         
125         String main = params.get("");
126         String type = null;
127         String subtype = null;
128         if (main != null) {
129             main = main.toLowerCase().trim();
130             int index = main.indexOf('/');
131             boolean valid = false;
132             if (index != -1) {
133                 type = main.substring(0, index).trim();
134                 subtype = main.substring(index + 1).trim();
135                 if (type.length() > 0 && subtype.length() > 0) {
136                     main = type + "/" + subtype;
137                     valid = true;
138                 }
139             }
140             
141             if (!valid) {
142                 main = null;
143                 type = null;
144                 subtype = null;
145             }
146         }
147         String b = params.get("boundary");
148         
149         if (main != null 
150                 && ((main.startsWith("multipart/") && b != null) 
151                         || !main.startsWith("multipart/"))) {
152             
153             mimeType = main;
154             this.subType = subtype;
155             this.mediaType = type;
156         }
157         
158         if (MimeUtil.isMultipart(mimeType)) {
159             boundary = b;
160         }
161         
162         String c = params.get("charset");
163         charset = null;
164         if (c != null) {
165             c = c.trim();
166             if (c.length() > 0) {
167                 charset = c.toLowerCase();
168             }
169         }
170         if (charset == null && MEDIA_TYPE_TEXT.equals(mediaType)) {
171             charset = US_ASCII;
172         }
173         
174         /*
175          * Add all other parameters to parameters.
176          */
177         parameters.putAll(params);
178         parameters.remove("");
179         parameters.remove("boundary");
180         parameters.remove("charset");
181     }
182 
183     /**
184      * Return the MimeType 
185      * 
186      * @return mimeType
187      */
188     public String getMimeType() {
189         return mimeType;
190     }
191     
192     /**
193      * Return the boundary
194      * 
195      * @return boundary
196      */
197     public String getBoundary() {
198         return boundary;
199     }
200     
201     /**
202      * Return the charset
203      * 
204      * @return charset
205      */
206     public String getCharset() {
207         return charset;
208     }
209     
210     /**
211      * Return all parameters for the BodyDescriptor
212      * 
213      * @return parameters
214      */
215     public Map<String, String> getContentTypeParameters() {
216         return parameters;
217     }
218     
219     /**
220      * Return the TransferEncoding
221      * 
222      * @return transferEncoding
223      */
224     public String getTransferEncoding() {
225         return transferEncoding;
226     }
227     
228     @Override
229     public String toString() {
230         return mimeType;
231     }
232 
233     public long getContentLength() {
234         return contentLength;
235     }
236 
237     public String getMediaType() {
238         return mediaType;
239     }
240 
241     public String getSubType() {
242         return subType;
243     }
244 }