source: contrib/MailArchiver/sources/vendor/mime4j/custom/core/src/main/java/org/apache/james/mime4j/parser/MimeStreamParser.java @ 6785

Revision 6785, 10.5 KB checked in by rafaelraymundo, 12 years ago (diff)

Ticket #2946 - Liberado codigo do MailArchiver?. Documentação na subpasta DOCS.

Line 
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
20package org.apache.james.mime4j.parser;
21
22import java.io.IOException;
23import java.io.InputStream;
24
25import org.apache.james.mime4j.MimeException;
26import org.apache.james.mime4j.codec.DecodeMonitor;
27import org.apache.james.mime4j.stream.BodyDescriptor;
28import org.apache.james.mime4j.stream.EntityState;
29import org.apache.james.mime4j.stream.MimeEntityConfig;
30import org.apache.james.mime4j.stream.MimeTokenStream;
31import org.apache.james.mime4j.stream.MutableBodyDescriptorFactory;
32import org.apache.james.mime4j.stream.RawField;
33import org.apache.james.mime4j.stream.RecursionMode;
34import org.apache.james.mime4j.io.LineNumberInputStream;
35
36/**
37 * <p>
38 * Parses MIME (or RFC822) message streams of bytes or characters and reports
39 * parsing events to a <code>ContentHandler</code> instance.
40 * </p>
41 * <p>
42 * Typical usage:<br/>
43 * <pre>
44 *      ContentHandler handler = new MyHandler();
45 *      MimeStreamParser parser = new MimeStreamParser();
46 *      parser.setContentHandler(handler);
47 *      parser.parse(new FileInputStream("mime.msg"));
48 * </pre>
49 */
50public class MimeStreamParser {
51
52    private ContentHandler handler = null;
53    private boolean contentDecoding;
54    private final MimeEntityConfig mimeEntityConfig;
55   
56    private final MimeTokenStream mimeTokenStream;
57
58    private LineNumberInputStream.Entity currentEntity;
59
60    public MimeStreamParser(MimeTokenStream tokenStream) {
61        super();
62        this.mimeTokenStream = tokenStream;
63        this.mimeEntityConfig = tokenStream.getConfig();
64        this.contentDecoding = false;
65    }
66
67    public MimeStreamParser(
68            final MimeEntityConfig config,
69            boolean clone,
70            final DecodeMonitor monitor,
71            final MutableBodyDescriptorFactory bodyDescFactory) {
72        this(new MimeTokenStream(clone ? config.clone() : config, monitor, bodyDescFactory));
73    }
74
75    public MimeStreamParser(final MimeEntityConfig config, boolean clone) {
76        this(new MimeTokenStream(clone ? config.clone() : config, null, null));
77    }
78
79    public MimeStreamParser(
80            final MimeEntityConfig config,
81            final DecodeMonitor monitor,
82            final MutableBodyDescriptorFactory bodyDescFactory) {
83        this(config != null ? config : new MimeEntityConfig(), config != null,
84                monitor, bodyDescFactory);
85    }
86
87    public MimeStreamParser(final MimeEntityConfig config) {
88        this(config, null, null);
89    }
90
91    public MimeStreamParser() {
92        this(new MimeEntityConfig(), false, null, null);
93    }
94
95    public MimeTokenStream getMimeTokenStream() {
96        return mimeTokenStream;
97    }
98
99    /**
100     * Determines whether this parser automatically decodes body content
101     * based on the on the MIME fields with the standard defaults.
102     */
103    public boolean isContentDecoding() {
104        return contentDecoding;
105    }
106
107    /**
108     * Defines whether parser should automatically decode body content
109     * based on the on the MIME fields with the standard defaults.
110     */
111    public void setContentDecoding(boolean b) {
112        this.contentDecoding = b;
113    }
114
115    /**
116     * Parses a stream of bytes containing a MIME message. If the mime config of this
117     * object contains a not null defaultContentType
118     * ({@link MimeEntityConfig#getDefaultContentType()}) a headless parsing is performed.
119     *
120     * @param is the stream to parse.
121     * @throws MimeException if the message can not be processed
122     * @throws IOException on I/O errors.
123     */
124    public void parse(InputStream inputStream) throws MimeException, IOException {
125        if (mimeEntityConfig.getHeadlessParsing() != null) {
126            mimeTokenStream.parseHeadless(inputStream, mimeEntityConfig.getHeadlessParsing());
127            if(currentEntity == null) {
128                currentEntity = getMimeTokenStream().getLineNumberRootEntity();
129            }
130            else {
131                currentEntity = currentEntity.getEmbeddedMessage();
132            }
133            if(handler instanceof ContentHandlerEx) {
134                ((ContentHandlerEx)handler).startMessage(currentEntity);
135            }
136            else {
137                handler.startMessage();
138            }
139            handler.startHeader();
140            handler.field(new RawField("Content-Type", mimeEntityConfig.getHeadlessParsing()));
141            handler.endHeader();
142        } else {
143            mimeTokenStream.parse(inputStream);
144        }
145        OUTER: for (;;) {
146            EntityState state = mimeTokenStream.getState();
147            switch (state) {
148                case T_BODY:
149                    BodyDescriptor desc = mimeTokenStream.getBodyDescriptor();
150                    InputStream bodyContent;
151                    if (contentDecoding) {
152                        bodyContent = mimeTokenStream.getDecodedInputStream();
153                    } else {
154                        bodyContent = mimeTokenStream.getInputStream();
155                    }
156                    handler.body(desc, bodyContent);
157                    break;
158                case T_END_BODYPART:
159                    handler.endBodyPart();
160                    currentEntity = currentEntity.getParent();
161                    break;
162                case T_END_HEADER:
163                    handler.endHeader();
164                    break;
165                case T_END_MESSAGE:
166                    handler.endMessage();
167                    currentEntity = currentEntity.getParent();
168                    break;
169                case T_END_MULTIPART:
170                    handler.endMultipart();
171                    break;
172                case T_END_OF_STREAM:
173                    break OUTER;
174                case T_EPILOGUE:
175                    handler.epilogue(mimeTokenStream.getInputStream());
176                    break;
177                case T_FIELD:
178                    handler.field(mimeTokenStream.getField());
179                    break;
180                case T_PREAMBLE:
181                    handler.preamble(mimeTokenStream.getInputStream());
182                    break;
183                case T_RAW_ENTITY:
184                    handler.raw(mimeTokenStream.getInputStream());
185                    break;
186                case T_START_BODYPART:
187                    currentEntity = currentEntity.getNextPart();
188                    if(handler instanceof ContentHandlerEx) {
189                        ((ContentHandlerEx)handler).startBodyPart(currentEntity);
190                    }
191                    else {
192                            handler.startBodyPart();
193                    }
194                    break;
195                case T_START_HEADER:
196                    handler.startHeader();
197                    break;
198                case T_START_MESSAGE:
199                    if(currentEntity == null) {
200                        currentEntity = getMimeTokenStream().getLineNumberRootEntity();
201                    }
202                    else {
203                        currentEntity = currentEntity.getEmbeddedMessage();
204                    }
205                    if(handler instanceof ContentHandlerEx) {
206                        ((ContentHandlerEx)handler).startMessage(currentEntity);
207                    }
208                    else {
209                        handler.startMessage();
210                    }
211                    break;
212                case T_START_MULTIPART:
213                    handler.startMultipart(mimeTokenStream.getBodyDescriptor());
214                    break;
215                default:
216                    throw new IllegalStateException("Invalid state: " + state);
217            }
218            state = mimeTokenStream.next();
219        }
220    }
221   
222    /**
223     * Determines if this parser is currently in raw mode.
224     *
225     * @return <code>true</code> if in raw mode, <code>false</code>
226     *         otherwise.
227     * @see #setRaw(boolean)
228     */
229    public boolean isRaw() {
230        return mimeTokenStream.isRaw();
231    }
232   
233    /**
234     * Enables raw mode. In raw mode all future entities (messages
235     * or body parts) in the stream will be reported to the
236     * {@link ContentHandler#raw(InputStream)} handler method only.
237     * The stream will contain the entire unparsed entity contents
238     * including header fields and whatever is in the body.
239     */
240    public void setRaw() {
241        mimeTokenStream.setRecursionMode(RecursionMode.M_RAW);
242    }
243   
244    /**
245     * Enables flat mode. In flat mode rfc822 parts are not recursively
246     * parsed and multipart content is handled as a single "simple" stream.
247     */
248    public void setFlat() {
249        mimeTokenStream.setRecursionMode(RecursionMode.M_FLAT);
250    }
251   
252    /**
253     * Enables recursive mode. In tihs mode rfc822 parts are recursively
254     * parsed.
255     */
256    public void setRecurse() {
257        mimeTokenStream.setRecursionMode(RecursionMode.M_RECURSE);
258    }
259
260    /**
261     * Finishes the parsing and stops reading lines.
262     * NOTE: No more lines will be parsed but the parser
263     * will still call
264     * {@link ContentHandler#endMultipart()},
265     * {@link ContentHandler#endBodyPart()},
266     * {@link ContentHandler#endMessage()}, etc to match previous calls
267     * to
268     * {@link ContentHandler#startMultipart(BodyDescriptor)},
269     * {@link ContentHandler#startBodyPart()},
270     * {@link ContentHandler#startMessage()}, etc.
271     */
272    public void stop() {
273        mimeTokenStream.stop();
274    }
275   
276    /**
277     * Sets the <code>ContentHandler</code> to use when reporting
278     * parsing events.
279     *
280     * @param h the <code>ContentHandler</code>.
281     */
282    public void setContentHandler(ContentHandler h) {
283        this.handler = h;
284    }
285}
Note: See TracBrowser for help on using the repository browser.