1d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen/****************************************************************
2d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * Licensed to the Apache Software Foundation (ASF) under one   *
3d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * or more contributor license agreements.  See the NOTICE file *
4d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * distributed with this work for additional information        *
5d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * regarding copyright ownership.  The ASF licenses this file   *
6d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * to you under the Apache License, Version 2.0 (the            *
7d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * "License"); you may not use this file except in compliance   *
8d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * with the License.  You may obtain a copy of the License at   *
9d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *                                                              *
10d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *   http://www.apache.org/licenses/LICENSE-2.0                 *
11d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *                                                              *
12d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * Unless required by applicable law or agreed to in writing,   *
13d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * software distributed under the License is distributed on an  *
14d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * KIND, either express or implied.  See the License for the    *
16d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * specific language governing permissions and limitations      *
17d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * under the License.                                           *
18d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen ****************************************************************/
19d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
20d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenpackage org.apache.james.mime4j;
21d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
22d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport java.util.HashMap;
23d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport java.util.Map;
24d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
25d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen/**
26d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * Encapsulates the values of the MIME-specific header fields
27d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * (which starts with <code>Content-</code>).
28d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *
29d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *
30d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * @version $Id: BodyDescriptor.java,v 1.4 2005/02/11 10:08:37 ntherning Exp $
31d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen */
32d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenpublic class BodyDescriptor {
33d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    private static Log log = LogFactory.getLog(BodyDescriptor.class);
34d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
35d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    private String mimeType = "text/plain";
36d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    private String boundary = null;
37d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    private String charset = "us-ascii";
38d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    private String transferEncoding = "7bit";
39d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    private Map<String, String> parameters = new HashMap<String, String>();
40d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    private boolean contentTypeSet = false;
41d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    private boolean contentTransferEncSet = false;
42d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
43d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
44d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Creates a new root <code>BodyDescriptor</code> instance.
45d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
46d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public BodyDescriptor() {
47d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        this(null);
48d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
49d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
50d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
51d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Creates a new <code>BodyDescriptor</code> instance.
52d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     *
53d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * @param parent the descriptor of the parent or <code>null</code> if this
54d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     *        is the root descriptor.
55d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
56d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public BodyDescriptor(BodyDescriptor parent) {
57d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        if (parent != null && parent.isMimeType("multipart/digest")) {
58d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            mimeType = "message/rfc822";
59d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        } else {
60d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            mimeType = "text/plain";
61d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        }
62d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
63d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
64d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
65d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Should be called for each <code>Content-</code> header field of
66d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * a MIME message or part.
67d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     *
68d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * @param name the field name.
69d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * @param value the field value.
70d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
71d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public void addField(String name, String value) {
72d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
73d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        name = name.trim().toLowerCase();
74d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
75d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        if (name.equals("content-transfer-encoding") && !contentTransferEncSet) {
76d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            contentTransferEncSet = true;
77d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
78d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            value = value.trim().toLowerCase();
79d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            if (value.length() > 0) {
80d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                transferEncoding = value;
81d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            }
82d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
83d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        } else if (name.equals("content-type") && !contentTypeSet) {
84d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            contentTypeSet = true;
85d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
86d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            value = value.trim();
87d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
88d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            /*
89d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen             * Unfold Content-Type value
90d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen             */
91d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            StringBuffer sb = new StringBuffer();
92d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            for (int i = 0; i < value.length(); i++) {
93d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                char c = value.charAt(i);
94d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                if (c == '\r' || c == '\n') {
95d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    continue;
96d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                }
97d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                sb.append(c);
98d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            }
99d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
100d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            Map<String, String> params = getHeaderParams(sb.toString());
101d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
102d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            String main = params.get("");
103d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            if (main != null) {
104d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                main = main.toLowerCase().trim();
105d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                int index = main.indexOf('/');
106d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                boolean valid = false;
107d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                if (index != -1) {
108d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    String type = main.substring(0, index).trim();
109d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    String subtype = main.substring(index + 1).trim();
110d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    if (type.length() > 0 && subtype.length() > 0) {
111d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        main = type + "/" + subtype;
112d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        valid = true;
113d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    }
114d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                }
115d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
116d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                if (!valid) {
117d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    main = null;
118d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                }
119d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            }
120d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            String b = params.get("boundary");
121d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
122d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            if (main != null
123d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    && ((main.startsWith("multipart/") && b != null)
124d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            || !main.startsWith("multipart/"))) {
125d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
126d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                mimeType = main;
127d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            }
128d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
129d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            if (isMultipart()) {
130d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                boundary = b;
131d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            }
132d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
133d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            String c = params.get("charset");
134d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            if (c != null) {
135d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                c = c.trim();
136d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                if (c.length() > 0) {
137d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    charset = c.toLowerCase();
138d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                }
139d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            }
140d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
141d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            /*
142d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen             * Add all other parameters to parameters.
143d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen             */
144d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            parameters.putAll(params);
145d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            parameters.remove("");
146d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            parameters.remove("boundary");
147d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            parameters.remove("charset");
148d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        }
149d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
150d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
151d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    private Map<String, String> getHeaderParams(String headerValue) {
152d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        Map<String, String> result = new HashMap<String, String>();
153d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
154d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        // split main value and parameters
155d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        String main;
156d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        String rest;
157d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        if (headerValue.indexOf(";") == -1) {
158d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            main = headerValue;
159d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            rest = null;
160d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        } else {
161d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            main = headerValue.substring(0, headerValue.indexOf(";"));
162d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            rest = headerValue.substring(main.length() + 1);
163d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        }
164d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
165d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        result.put("", main);
166d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        if (rest != null) {
167d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            char[] chars = rest.toCharArray();
168d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            StringBuffer paramName = new StringBuffer();
169d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            StringBuffer paramValue = new StringBuffer();
170d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
171d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            final byte READY_FOR_NAME = 0;
172d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            final byte IN_NAME = 1;
173d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            final byte READY_FOR_VALUE = 2;
174d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            final byte IN_VALUE = 3;
175d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            final byte IN_QUOTED_VALUE = 4;
176d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            final byte VALUE_DONE = 5;
177d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            final byte ERROR = 99;
178d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
179d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            byte state = READY_FOR_NAME;
180d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            boolean escaped = false;
181d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            for (int i = 0; i < chars.length; i++) {
182d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                char c = chars[i];
183d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
184d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                switch (state) {
185d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    case ERROR:
186d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        if (c == ';')
187d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            state = READY_FOR_NAME;
188d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        break;
189d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
190d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    case READY_FOR_NAME:
191d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        if (c == '=') {
192d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            log.error("Expected header param name, got '='");
193d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            state = ERROR;
194d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            break;
195d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        }
196d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
197d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        paramName = new StringBuffer();
198d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        paramValue = new StringBuffer();
199d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
200d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        state = IN_NAME;
201d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        // $FALL-THROUGH$
202d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
203d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    case IN_NAME:
204d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        if (c == '=') {
205d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            if (paramName.length() == 0)
206d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                state = ERROR;
207d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            else
208d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                state = READY_FOR_VALUE;
209d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            break;
210d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        }
211d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
212d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        // not '='... just add to name
213d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        paramName.append(c);
214d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        break;
215d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
216d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    case READY_FOR_VALUE:
217d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        boolean fallThrough = false;
218d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        switch (c) {
219d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case ' ':
220d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case '\t':
221d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;  // ignore spaces, especially before '"'
222d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
223d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case '"':
224d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                state = IN_QUOTED_VALUE;
225d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
226d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
227d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            default:
228d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                state = IN_VALUE;
229d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                fallThrough = true;
230d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
231d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        }
232d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        if (!fallThrough)
233d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            break;
234d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
235d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        // $FALL-THROUGH$
236d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
237d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    case IN_VALUE:
238d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        fallThrough = false;
239d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        switch (c) {
240d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case ';':
241d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case ' ':
242d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case '\t':
243d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                result.put(
244d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                   paramName.toString().trim().toLowerCase(),
245d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                   paramValue.toString().trim());
246d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                state = VALUE_DONE;
247d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                fallThrough = true;
248d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
249d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            default:
250d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                paramValue.append(c);
251d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
252d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        }
253d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        if (!fallThrough)
254d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            break;
255d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
256d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        // $FALL-THROUGH$
257d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
258d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    case VALUE_DONE:
259d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        switch (c) {
260d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case ';':
261d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                state = READY_FOR_NAME;
262d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
263d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
264d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case ' ':
265d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case '\t':
266d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
267d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
268d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            default:
269d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                state = ERROR;
270d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
271d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        }
272d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        break;
273d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
274d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                    case IN_QUOTED_VALUE:
275d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        switch (c) {
276d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case '"':
277d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                if (!escaped) {
278d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                    // don't trim quoted strings; the spaces could be intentional.
279d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                    result.put(
280d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                            paramName.toString().trim().toLowerCase(),
281d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                            paramValue.toString());
282d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                    state = VALUE_DONE;
283d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                } else {
284d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                    escaped = false;
285d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                    paramValue.append(c);
286d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                }
287d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
288d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
289d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            case '\\':
290d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                if (escaped) {
291d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                    paramValue.append('\\');
292d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                }
293d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                escaped = !escaped;
294d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
295d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
296d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                            default:
297d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                if (escaped) {
298d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                    paramValue.append('\\');
299d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                }
300d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                escaped = false;
301d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                paramValue.append(c);
302d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                                break;
303d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        }
304d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        break;
305d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
306d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                }
307d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            }
308d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
309d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            // done looping.  check if anything is left over.
310d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            if (state == IN_VALUE) {
311d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                result.put(
312d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        paramName.toString().trim().toLowerCase(),
313d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                        paramValue.toString().trim());
314d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            }
315d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        }
316d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
317d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return result;
318d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
319d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
320d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
321d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public boolean isMimeType(String mimeType) {
322d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return this.mimeType.equals(mimeType.toLowerCase());
323d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
324d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
325d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
326d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Return true if the BodyDescriptor belongs to a message
327d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
328d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public boolean isMessage() {
329d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return mimeType.equals("message/rfc822");
330d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
331d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
332d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
333d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Return true if the BodyDescripotro belongs to a multipart
334d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
335d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public boolean isMultipart() {
336d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return mimeType.startsWith("multipart/");
337d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
338d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
339d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
340d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Return the MimeType
341d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
342d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public String getMimeType() {
343d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return mimeType;
344d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
345d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
346d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
347d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Return the boundary
348d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
349d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public String getBoundary() {
350d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return boundary;
351d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
352d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
353d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
354d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Return the charset
355d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
356d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public String getCharset() {
357d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return charset;
358d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
359d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
360d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
361d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Return all parameters for the BodyDescriptor
362d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
363d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public Map<String, String> getParameters() {
364d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return parameters;
365d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
366d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
367d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
368d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Return the TransferEncoding
369d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
370d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public String getTransferEncoding() {
371d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return transferEncoding;
372d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
373d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
374d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
375d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Return true if it's base64 encoded
376d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
377d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public boolean isBase64Encoded() {
378d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return "base64".equals(transferEncoding);
379d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
380d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
381d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    /**
382d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     * Return true if it's quoted-printable
383d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen     */
384d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public boolean isQuotedPrintableEncoded() {
385d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return "quoted-printable".equals(transferEncoding);
386d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
387d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
388d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    @Override
389d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    public String toString() {
390d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen        return mimeType;
391d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen    }
392d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen}