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.message; 021 022import java.util.Collections; 023import java.util.Date; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Locale; 027import java.util.Map; 028 029import org.apache.james.mime4j.dom.field.ContentDescriptionField; 030import org.apache.james.mime4j.dom.field.ContentDispositionField; 031import org.apache.james.mime4j.dom.field.ContentIdField; 032import org.apache.james.mime4j.dom.field.ContentLanguageField; 033import org.apache.james.mime4j.dom.field.ContentLengthField; 034import org.apache.james.mime4j.dom.field.ContentLocationField; 035import org.apache.james.mime4j.dom.field.ContentMD5Field; 036import org.apache.james.mime4j.dom.field.ContentTransferEncodingField; 037import org.apache.james.mime4j.dom.field.ContentTypeField; 038import org.apache.james.mime4j.dom.field.FieldName; 039import org.apache.james.mime4j.dom.field.MimeVersionField; 040import org.apache.james.mime4j.dom.field.ParsedField; 041import org.apache.james.mime4j.field.MimeVersionFieldImpl; 042import org.apache.james.mime4j.stream.BodyDescriptor; 043import org.apache.james.mime4j.util.MimeUtil; 044 045/** 046 * Extended {@link BodyDescriptor} implementation with complete content details. 047 */ 048public class MaximalBodyDescriptor implements BodyDescriptor { 049 050 private static final String CONTENT_TYPE = FieldName.CONTENT_TYPE.toLowerCase(Locale.US); 051 private static final String CONTENT_LENGTH = FieldName.CONTENT_LENGTH.toLowerCase(Locale.US); 052 private static final String CONTENT_TRANSFER_ENCODING = FieldName.CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.US); 053 private static final String CONTENT_DISPOSITION = FieldName.CONTENT_DISPOSITION.toLowerCase(Locale.US); 054 private static final String CONTENT_ID = FieldName.CONTENT_ID.toLowerCase(Locale.US); 055 private static final String CONTENT_MD5 = FieldName.CONTENT_MD5.toLowerCase(Locale.US); 056 private static final String CONTENT_DESCRIPTION = FieldName.CONTENT_DESCRIPTION.toLowerCase(Locale.US); 057 private static final String CONTENT_LANGUAGE = FieldName.CONTENT_LANGUAGE.toLowerCase(Locale.US); 058 private static final String CONTENT_LOCATION = FieldName.CONTENT_LOCATION.toLowerCase(Locale.US); 059 private static final String MIME_VERSION = FieldName.MIME_VERSION.toLowerCase(Locale.US); 060 061 private final String mediaType; 062 private final String subType; 063 private final String mimeType; 064 private final String boundary; 065 private final String charset; 066 private final Map<String, ParsedField> fields; 067 068 MaximalBodyDescriptor( 069 final String mimeType, 070 final String mediaType, 071 final String subType, 072 final String boundary, 073 final String charset, 074 final Map<String, ParsedField> fields) { 075 super(); 076 this.mimeType = mimeType; 077 this.mediaType = mediaType; 078 this.subType = subType; 079 this.boundary = boundary; 080 this.charset = charset; 081 this.fields = fields != null ? new HashMap<String, ParsedField>(fields) : 082 Collections.<String, ParsedField>emptyMap(); 083 } 084 085 public String getMimeType() { 086 return mimeType; 087 } 088 089 public String getBoundary() { 090 return boundary; 091 } 092 093 public String getCharset() { 094 return charset; 095 } 096 097 public String getMediaType() { 098 return mediaType; 099 } 100 101 public String getSubType() { 102 return subType; 103 } 104 105 public Map<String, String> getContentTypeParameters() { 106 ContentTypeField contentTypeField = (ContentTypeField) fields.get(CONTENT_TYPE); 107 return contentTypeField != null ? contentTypeField.getParameters() : 108 Collections.<String, String>emptyMap(); 109 } 110 111 public String getTransferEncoding() { 112 ContentTransferEncodingField contentTransferEncodingField = 113 (ContentTransferEncodingField) fields.get(CONTENT_TRANSFER_ENCODING); 114 return contentTransferEncodingField != null ? contentTransferEncodingField.getEncoding() : 115 MimeUtil.ENC_7BIT; 116 } 117 118 public long getContentLength() { 119 ContentLengthField contentLengthField = (ContentLengthField) fields.get(CONTENT_LENGTH); 120 return contentLengthField != null ? contentLengthField.getContentLength() : -1; 121 } 122 123 /** 124 * Gets the MIME major version 125 * as specified by the <code>MIME-Version</code> 126 * header. 127 * Defaults to one. 128 * @return positive integer 129 */ 130 public int getMimeMajorVersion() { 131 MimeVersionField mimeVersionField = (MimeVersionField) fields.get(MIME_VERSION); 132 return mimeVersionField != null ? mimeVersionField.getMajorVersion() : 133 MimeVersionFieldImpl.DEFAULT_MAJOR_VERSION; 134 } 135 136 /** 137 * Gets the MIME minor version 138 * as specified by the <code>MIME-Version</code> 139 * header. 140 * Defaults to zero. 141 * @return positive integer 142 */ 143 public int getMimeMinorVersion() { 144 MimeVersionField mimeVersionField = (MimeVersionField) fields.get(MIME_VERSION); 145 return mimeVersionField != null ? mimeVersionField.getMinorVersion() : 146 MimeVersionFieldImpl.DEFAULT_MINOR_VERSION; 147 } 148 149 150 /** 151 * Gets the value of the <a href='http://www.faqs.org/rfcs/rfc2045'>RFC</a> 152 * <code>Content-Description</code> header. 153 * @return value of the <code>Content-Description</code> when present, 154 * null otherwise 155 */ 156 public String getContentDescription() { 157 ContentDescriptionField contentDescriptionField = 158 (ContentDescriptionField) fields.get(CONTENT_DESCRIPTION); 159 return contentDescriptionField != null ? contentDescriptionField.getDescription() : null; 160 } 161 162 /** 163 * Gets the value of the <a href='http://www.faqs.org/rfcs/rfc2045'>RFC</a> 164 * <code>Content-ID</code> header. 165 * @return value of the <code>Content-ID</code> when present, 166 * null otherwise 167 */ 168 public String getContentId() { 169 ContentIdField contentIdField = (ContentIdField) fields.get(CONTENT_ID); 170 return contentIdField != null ? contentIdField.getId() : null; 171 } 172 173 /** 174 * Gets the disposition type of the <code>content-disposition</code> field. 175 * The value is case insensitive and will be converted to lower case. 176 * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 177 * @return content disposition type, 178 * or null when this has not been set 179 */ 180 public String getContentDispositionType() { 181 ContentDispositionField contentDispositionField = 182 (ContentDispositionField) fields.get(CONTENT_DISPOSITION); 183 return contentDispositionField != null ? contentDispositionField.getDispositionType() : null; 184 } 185 186 /** 187 * Gets the parameters of the <code>content-disposition</code> field. 188 * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 189 * @return parameter value strings indexed by parameter name strings, 190 * not null 191 */ 192 public Map<String, String> getContentDispositionParameters() { 193 ContentDispositionField contentDispositionField = 194 (ContentDispositionField) fields.get(CONTENT_DISPOSITION); 195 return contentDispositionField != null ? contentDispositionField.getParameters() : 196 Collections.<String, String>emptyMap(); 197 } 198 199 /** 200 * Gets the <code>filename</code> parameter value of the <code>content-disposition</code> field. 201 * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 202 * @return filename parameter value, 203 * or null when it is not present 204 */ 205 public String getContentDispositionFilename() { 206 ContentDispositionField contentDispositionField = 207 (ContentDispositionField) fields.get(CONTENT_DISPOSITION); 208 return contentDispositionField != null ? contentDispositionField.getFilename() : null; 209 } 210 211 /** 212 * Gets the <code>modification-date</code> parameter value of the <code>content-disposition</code> field. 213 * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 214 * @return modification-date parameter value, 215 * or null when this is not present 216 */ 217 public Date getContentDispositionModificationDate() { 218 ContentDispositionField contentDispositionField = 219 (ContentDispositionField) fields.get(CONTENT_DISPOSITION); 220 return contentDispositionField != null ? contentDispositionField.getModificationDate() : null; 221 } 222 223 /** 224 * Gets the <code>creation-date</code> parameter value of the <code>content-disposition</code> field. 225 * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 226 * @return creation-date parameter value, 227 * or null when this is not present 228 */ 229 public Date getContentDispositionCreationDate() { 230 ContentDispositionField contentDispositionField = 231 (ContentDispositionField) fields.get(CONTENT_DISPOSITION); 232 return contentDispositionField != null ? contentDispositionField.getCreationDate() : null; 233 } 234 235 /** 236 * Gets the <code>read-date</code> parameter value of the <code>content-disposition</code> field. 237 * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 238 * @return read-date parameter value, 239 * or null when this is not present 240 */ 241 public Date getContentDispositionReadDate() { 242 ContentDispositionField contentDispositionField = 243 (ContentDispositionField) fields.get(CONTENT_DISPOSITION); 244 return contentDispositionField != null ? contentDispositionField.getReadDate() : null; 245 } 246 247 /** 248 * Gets the <code>size</code> parameter value of the <code>content-disposition</code> field. 249 * See <a href='http://www.faqs.org/rfcs/rfc2183.html'>RFC2183</a>. 250 * @return size parameter value, 251 * or -1 if this size has not been set 252 */ 253 public long getContentDispositionSize() { 254 ContentDispositionField contentDispositionField = 255 (ContentDispositionField) fields.get(CONTENT_DISPOSITION); 256 return contentDispositionField != null ? contentDispositionField.getSize() : -1; 257 } 258 259 /** 260 * Get the <code>content-language</code> header values. 261 * Each applicable language tag will be returned in order. 262 * See <a href='http://tools.ietf.org/html/rfc4646'>RFC4646</a> 263 * <cite>http://tools.ietf.org/html/rfc4646</cite>. 264 * @return list of language tag Strings, 265 * or null if no header exists 266 */ 267 public List<String> getContentLanguage() { 268 ContentLanguageField contentLanguageField = 269 (ContentLanguageField) fields.get(CONTENT_LANGUAGE); 270 return contentLanguageField != null ? contentLanguageField.getLanguages() : 271 Collections.<String>emptyList(); 272 } 273 274 /** 275 * Get the <code>content-location</code> header value. 276 * See <a href='http://tools.ietf.org/html/rfc2557'>RFC2557</a> 277 * @return the URL content-location 278 * or null if no header exists 279 */ 280 public String getContentLocation() { 281 ContentLocationField contentLocationField = 282 (ContentLocationField) fields.get(CONTENT_LOCATION); 283 return contentLocationField != null ? contentLocationField.getLocation() : null; 284 } 285 286 /** 287 * Gets the raw, Base64 encoded value of the 288 * <code>Content-MD5</code> field. 289 * See <a href='http://tools.ietf.org/html/rfc1864'>RFC1864</a>. 290 * @return raw encoded content-md5 291 * or null if no header exists 292 */ 293 public String getContentMD5Raw() { 294 ContentMD5Field contentMD5Field = (ContentMD5Field) fields.get(CONTENT_MD5); 295 return contentMD5Field != null ? contentMD5Field.getMD5Raw() : null; 296 } 297 298 @Override 299 public String toString() { 300 StringBuilder sb = new StringBuilder(); 301 sb.append("[mimeType="); 302 sb.append(mimeType); 303 sb.append(", mediaType="); 304 sb.append(mediaType); 305 sb.append(", subType="); 306 sb.append(subType); 307 sb.append(", boundary="); 308 sb.append(boundary); 309 sb.append(", charset="); 310 sb.append(charset); 311 sb.append("]"); 312 return sb.toString(); 313 } 314 315}