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.message;
021
022 import java.util.HashMap;
023 import java.util.Locale;
024 import java.util.Map;
025
026 import org.apache.james.mime4j.MimeException;
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.dom.field.FieldName;
031 import org.apache.james.mime4j.dom.field.ParsedField;
032 import org.apache.james.mime4j.field.DefaultFieldParser;
033 import org.apache.james.mime4j.stream.BodyDescriptor;
034 import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
035 import org.apache.james.mime4j.stream.Field;
036 import org.apache.james.mime4j.stream.RawField;
037 import org.apache.james.mime4j.util.MimeUtil;
038
039 /**
040 * Default {@link BodyDescriptorBuilder} implementation.
041 */
042 public class DefaultBodyDescriptorBuilder implements BodyDescriptorBuilder {
043
044 private static final String CONTENT_TYPE = FieldName.CONTENT_TYPE.toLowerCase(Locale.US);
045
046 private static final String US_ASCII = "us-ascii";
047 private static final String SUB_TYPE_EMAIL = "rfc822";
048 private static final String MEDIA_TYPE_TEXT = "text";
049 private static final String MEDIA_TYPE_MESSAGE = "message";
050 private static final String EMAIL_MESSAGE_MIME_TYPE = MEDIA_TYPE_MESSAGE + "/" + SUB_TYPE_EMAIL;
051 private static final String DEFAULT_SUB_TYPE = "plain";
052 private static final String DEFAULT_MEDIA_TYPE = MEDIA_TYPE_TEXT;
053 private static final String DEFAULT_MIME_TYPE = DEFAULT_MEDIA_TYPE + "/" + DEFAULT_SUB_TYPE;
054
055 private final String parentMimeType;
056 private final DecodeMonitor monitor;
057 private final FieldParser<? extends ParsedField> fieldParser;
058 private final Map<String, ParsedField> fields;
059
060 /**
061 * Creates a new root <code>BodyDescriptor</code> instance.
062 */
063 public DefaultBodyDescriptorBuilder() {
064 this(null);
065 }
066
067 public DefaultBodyDescriptorBuilder(final String parentMimeType) {
068 this(parentMimeType, null, null);
069 }
070
071 /**
072 * Creates a new <code>BodyDescriptor</code> instance.
073 */
074 public DefaultBodyDescriptorBuilder(
075 final String parentMimeType,
076 final FieldParser<? extends ParsedField> fieldParser,
077 final DecodeMonitor monitor) {
078 super();
079 this.parentMimeType = parentMimeType;
080 this.fieldParser = fieldParser != null ? fieldParser : DefaultFieldParser.getParser();
081 this.monitor = monitor != null ? monitor : DecodeMonitor.SILENT;
082 this.fields = new HashMap<String, ParsedField>();
083 }
084
085 public void reset() {
086 fields.clear();
087 }
088
089 public Field addField(final RawField rawfield) throws MimeException {
090 ParsedField field = fieldParser.parse(rawfield, monitor);
091 String name = field.getName().toLowerCase(Locale.US);
092 if (!fields.containsKey(name)) {
093 fields.put(name, field);
094 }
095 return field;
096 }
097
098 public BodyDescriptor build() {
099 String actualMimeType = null;
100 String actualMediaType = null;
101 String actualSubType = null;
102 String actualCharset = null;
103 String actualBoundary = null;
104 ContentTypeField contentTypeField = (ContentTypeField) fields.get(CONTENT_TYPE);
105 if (contentTypeField != null) {
106 actualMimeType = contentTypeField.getMimeType();
107 actualMediaType = contentTypeField.getMediaType();
108 actualSubType = contentTypeField.getSubType();
109 actualCharset = contentTypeField.getCharset();
110 actualBoundary = contentTypeField.getBoundary();
111 }
112 if (actualMimeType == null) {
113 if (MimeUtil.isSameMimeType("multipart/digest", parentMimeType)) {
114 actualMimeType = EMAIL_MESSAGE_MIME_TYPE;
115 actualMediaType = MEDIA_TYPE_MESSAGE;
116 actualSubType = SUB_TYPE_EMAIL;
117 } else {
118 actualMimeType = DEFAULT_MIME_TYPE;
119 actualMediaType = DEFAULT_MEDIA_TYPE;
120 actualSubType = DEFAULT_SUB_TYPE;
121 }
122 }
123 if (actualCharset == null && MEDIA_TYPE_TEXT.equals(actualMediaType)) {
124 actualCharset = US_ASCII;
125 }
126 if (!MimeUtil.isMultipart(actualMimeType)) {
127 actualBoundary = null;
128 }
129 return new MaximalBodyDescriptor(
130 actualMimeType, actualMediaType, actualSubType, actualBoundary, actualCharset,
131 fields);
132 }
133
134 public BodyDescriptorBuilder newChild() {
135 String actualMimeType;
136 ContentTypeField contentTypeField = (ContentTypeField) fields.get(CONTENT_TYPE);
137 if (contentTypeField != null) {
138 actualMimeType = contentTypeField.getMimeType();
139 } else {
140 if (MimeUtil.isSameMimeType("multipart/digest", parentMimeType)) {
141 actualMimeType = EMAIL_MESSAGE_MIME_TYPE;
142 } else {
143 actualMimeType = DEFAULT_MIME_TYPE;
144 }
145 }
146 return new DefaultBodyDescriptorBuilder(actualMimeType, fieldParser, monitor);
147 }
148
149 }