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.field;
021
022 import java.io.StringReader;
023 import java.util.Collections;
024 import java.util.Date;
025 import java.util.HashMap;
026 import java.util.List;
027 import java.util.Locale;
028 import java.util.Map;
029
030 import org.apache.james.mime4j.codec.DecodeMonitor;
031 import org.apache.james.mime4j.dom.FieldParser;
032 import org.apache.james.mime4j.dom.field.ContentDispositionField;
033 import org.apache.james.mime4j.field.contentdisposition.parser.ContentDispositionParser;
034 import org.apache.james.mime4j.field.contentdisposition.parser.ParseException;
035 import org.apache.james.mime4j.field.contentdisposition.parser.TokenMgrError;
036 import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;
037 import org.apache.james.mime4j.stream.Field;
038
039 /**
040 * Represents a <code>Content-Disposition</code> field.
041 */
042 public class ContentDispositionFieldImpl extends AbstractField implements ContentDispositionField {
043
044 private boolean parsed = false;
045
046 private String dispositionType = "";
047 private Map<String, String> parameters = new HashMap<String, String>();
048 private ParseException parseException;
049
050 private boolean creationDateParsed;
051 private Date creationDate;
052
053 private boolean modificationDateParsed;
054 private Date modificationDate;
055
056 private boolean readDateParsed;
057 private Date readDate;
058
059 ContentDispositionFieldImpl(Field rawField, DecodeMonitor monitor) {
060 super(rawField, monitor);
061 }
062
063 /**
064 * Gets the exception that was raised during parsing of the field value, if
065 * any; otherwise, null.
066 */
067 @Override
068 public ParseException getParseException() {
069 if (!parsed)
070 parse();
071
072 return parseException;
073 }
074
075 /**
076 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getDispositionType()
077 */
078 public String getDispositionType() {
079 if (!parsed)
080 parse();
081
082 return dispositionType;
083 }
084
085 /**
086 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getParameter(java.lang.String)
087 */
088 public String getParameter(String name) {
089 if (!parsed)
090 parse();
091
092 return parameters.get(name.toLowerCase());
093 }
094
095 /**
096 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getParameters()
097 */
098 public Map<String, String> getParameters() {
099 if (!parsed)
100 parse();
101
102 return Collections.unmodifiableMap(parameters);
103 }
104
105 /**
106 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#isDispositionType(java.lang.String)
107 */
108 public boolean isDispositionType(String dispositionType) {
109 if (!parsed)
110 parse();
111
112 return this.dispositionType.equalsIgnoreCase(dispositionType);
113 }
114
115 /**
116 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#isInline()
117 */
118 public boolean isInline() {
119 if (!parsed)
120 parse();
121
122 return dispositionType.equals(DISPOSITION_TYPE_INLINE);
123 }
124
125 /**
126 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#isAttachment()
127 */
128 public boolean isAttachment() {
129 if (!parsed)
130 parse();
131
132 return dispositionType.equals(DISPOSITION_TYPE_ATTACHMENT);
133 }
134
135 /**
136 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getFilename()
137 */
138 public String getFilename() {
139 return getParameter(PARAM_FILENAME);
140 }
141
142 /**
143 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getCreationDate()
144 */
145 public Date getCreationDate() {
146 if (!creationDateParsed) {
147 creationDate = parseDate(PARAM_CREATION_DATE);
148 creationDateParsed = true;
149 }
150
151 return creationDate;
152 }
153
154 /**
155 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getModificationDate()
156 */
157 public Date getModificationDate() {
158 if (!modificationDateParsed) {
159 modificationDate = parseDate(PARAM_MODIFICATION_DATE);
160 modificationDateParsed = true;
161 }
162
163 return modificationDate;
164 }
165
166 /**
167 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getReadDate()
168 */
169 public Date getReadDate() {
170 if (!readDateParsed) {
171 readDate = parseDate(PARAM_READ_DATE);
172 readDateParsed = true;
173 }
174
175 return readDate;
176 }
177
178 /**
179 * @see org.apache.james.mime4j.dom.field.ContentDispositionField#getSize()
180 */
181 public long getSize() {
182 String value = getParameter(PARAM_SIZE);
183 if (value == null)
184 return -1;
185
186 try {
187 long size = Long.parseLong(value);
188 return size < 0 ? -1 : size;
189 } catch (NumberFormatException e) {
190 return -1;
191 }
192 }
193
194 private Date parseDate(String paramName) {
195 String value = getParameter(paramName);
196 if (value == null) {
197 monitor.warn("Parsing " + paramName + " null", "returning null");
198 return null;
199 }
200
201 try {
202 return new DateTimeParser(new StringReader(value)).parseAll()
203 .getDate();
204 } catch (org.apache.james.mime4j.field.datetime.parser.ParseException e) {
205 if (monitor.isListening()) {
206 monitor.warn(paramName + " parameter is invalid: " + value,
207 paramName + " parameter is ignored");
208 }
209 return null;
210 } catch (TokenMgrError e) {
211 monitor.warn(paramName + " parameter is invalid: " + value,
212 paramName + "parameter is ignored");
213 return null;
214 }
215 }
216
217 private void parse() {
218 String body = getBody();
219
220 ContentDispositionParser parser = new ContentDispositionParser(
221 new StringReader(body));
222 try {
223 parser.parseAll();
224 } catch (ParseException e) {
225 parseException = e;
226 } catch (TokenMgrError e) {
227 parseException = new ParseException(e.getMessage());
228 }
229
230 final String dispositionType = parser.getDispositionType();
231
232 if (dispositionType != null) {
233 this.dispositionType = dispositionType.toLowerCase(Locale.US);
234
235 List<String> paramNames = parser.getParamNames();
236 List<String> paramValues = parser.getParamValues();
237
238 if (paramNames != null && paramValues != null) {
239 final int len = Math.min(paramNames.size(), paramValues.size());
240 for (int i = 0; i < len; i++) {
241 String paramName = paramNames.get(i).toLowerCase(Locale.US);
242 String paramValue = paramValues.get(i);
243 parameters.put(paramName, paramValue);
244 }
245 }
246 }
247
248 parsed = true;
249 }
250
251 public static final FieldParser<ContentDispositionField> PARSER = new FieldParser<ContentDispositionField>() {
252
253 public ContentDispositionField parse(final Field rawField, final DecodeMonitor monitor) {
254 return new ContentDispositionFieldImpl(rawField, monitor);
255 }
256
257 };
258 }