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 | |
---|
20 | package org.apache.james.mime4j.message; |
---|
21 | |
---|
22 | import java.io.IOException; |
---|
23 | import java.io.InputStream; |
---|
24 | import java.util.Stack; |
---|
25 | |
---|
26 | import org.apache.james.mime4j.MimeException; |
---|
27 | import org.apache.james.mime4j.codec.DecodeMonitor; |
---|
28 | import org.apache.james.mime4j.dom.Body; |
---|
29 | import org.apache.james.mime4j.dom.Entity; |
---|
30 | import org.apache.james.mime4j.dom.Header; |
---|
31 | import org.apache.james.mime4j.dom.Message; |
---|
32 | import org.apache.james.mime4j.dom.Multipart; |
---|
33 | import org.apache.james.mime4j.dom.field.Field; |
---|
34 | import org.apache.james.mime4j.field.DefaultFieldParser; |
---|
35 | import org.apache.james.mime4j.parser.ContentHandler; |
---|
36 | import org.apache.james.mime4j.stream.BodyDescriptor; |
---|
37 | import org.apache.james.mime4j.stream.RawField; |
---|
38 | import org.apache.james.mime4j.util.ByteArrayBuffer; |
---|
39 | import org.apache.james.mime4j.util.ByteSequence; |
---|
40 | |
---|
41 | /** |
---|
42 | * A <code>ContentHandler</code> for building an <code>Entity</code> to be |
---|
43 | * used in conjunction with a {@link org.apache.james.mime4j.parser.MimeStreamParser}. |
---|
44 | */ |
---|
45 | class EntityBuilder implements ContentHandler { |
---|
46 | |
---|
47 | private final Entity entity; |
---|
48 | private final BodyFactory bodyFactory; |
---|
49 | private final Stack<Object> stack; |
---|
50 | private final DecodeMonitor monitor; |
---|
51 | |
---|
52 | public EntityBuilder(Entity entity) { |
---|
53 | this(entity, null, null); |
---|
54 | } |
---|
55 | |
---|
56 | public EntityBuilder( |
---|
57 | final Entity entity, |
---|
58 | final BodyFactory bodyFactory, |
---|
59 | final DecodeMonitor monitor) { |
---|
60 | this.entity = entity; |
---|
61 | this.stack = new Stack<Object>(); |
---|
62 | this.monitor = monitor != null ? monitor : DecodeMonitor.SILENT; |
---|
63 | this.bodyFactory = bodyFactory != null ? bodyFactory : new BasicBodyFactory(); |
---|
64 | } |
---|
65 | |
---|
66 | private void expect(Class<?> c) { |
---|
67 | if (!c.isInstance(stack.peek())) { |
---|
68 | throw new IllegalStateException("Internal stack error: " |
---|
69 | + "Expected '" + c.getName() + "' found '" |
---|
70 | + stack.peek().getClass().getName() + "'"); |
---|
71 | } |
---|
72 | } |
---|
73 | |
---|
74 | /** |
---|
75 | * @see org.apache.james.mime4j.parser.ContentHandler#startMessage() |
---|
76 | */ |
---|
77 | public void startMessage() throws MimeException { |
---|
78 | if (stack.isEmpty()) { |
---|
79 | stack.push(this.entity); |
---|
80 | } else { |
---|
81 | expect(Entity.class); |
---|
82 | Message m = new MessageImpl(); |
---|
83 | ((Entity) stack.peek()).setBody(m); |
---|
84 | stack.push(m); |
---|
85 | } |
---|
86 | } |
---|
87 | |
---|
88 | /** |
---|
89 | * @see org.apache.james.mime4j.parser.ContentHandler#endMessage() |
---|
90 | */ |
---|
91 | public void endMessage() throws MimeException { |
---|
92 | expect(Message.class); |
---|
93 | stack.pop(); |
---|
94 | } |
---|
95 | |
---|
96 | /** |
---|
97 | * @see org.apache.james.mime4j.parser.ContentHandler#startHeader() |
---|
98 | */ |
---|
99 | public void startHeader() throws MimeException { |
---|
100 | stack.push(new HeaderImpl()); |
---|
101 | } |
---|
102 | |
---|
103 | /** |
---|
104 | * @see org.apache.james.mime4j.parser.ContentHandler#field(RawField) |
---|
105 | */ |
---|
106 | public void field(RawField field) throws MimeException { |
---|
107 | expect(Header.class); |
---|
108 | Field parsedField = DefaultFieldParser.parse(field.getRaw(), monitor); |
---|
109 | ((Header) stack.peek()).addField(parsedField); |
---|
110 | } |
---|
111 | |
---|
112 | /** |
---|
113 | * @see org.apache.james.mime4j.parser.ContentHandler#endHeader() |
---|
114 | */ |
---|
115 | public void endHeader() throws MimeException { |
---|
116 | expect(Header.class); |
---|
117 | Header h = (Header) stack.pop(); |
---|
118 | expect(Entity.class); |
---|
119 | ((Entity) stack.peek()).setHeader(h); |
---|
120 | } |
---|
121 | |
---|
122 | /** |
---|
123 | * @see org.apache.james.mime4j.parser.ContentHandler#startMultipart(org.apache.james.mime4j.stream.BodyDescriptor) |
---|
124 | */ |
---|
125 | public void startMultipart(final BodyDescriptor bd) throws MimeException { |
---|
126 | expect(Entity.class); |
---|
127 | |
---|
128 | final Entity e = (Entity) stack.peek(); |
---|
129 | final String subType = bd.getSubType(); |
---|
130 | final Multipart multiPart = new MultipartImpl(subType); |
---|
131 | e.setBody(multiPart); |
---|
132 | stack.push(multiPart); |
---|
133 | } |
---|
134 | |
---|
135 | /** |
---|
136 | * @see org.apache.james.mime4j.parser.ContentHandler#body(org.apache.james.mime4j.stream.BodyDescriptor, java.io.InputStream) |
---|
137 | */ |
---|
138 | public void body(BodyDescriptor bd, final InputStream is) throws MimeException, IOException { |
---|
139 | expect(Entity.class); |
---|
140 | |
---|
141 | // NO NEED TO MANUALLY RUN DECODING. |
---|
142 | // The parser has a "setContentDecoding" method. We should |
---|
143 | // simply instantiate the MimeStreamParser with that method. |
---|
144 | |
---|
145 | // final String enc = bd.getTransferEncoding(); |
---|
146 | |
---|
147 | final Body body; |
---|
148 | |
---|
149 | /* |
---|
150 | final InputStream decodedStream; |
---|
151 | if (MimeUtil.ENC_BASE64.equals(enc)) { |
---|
152 | decodedStream = new Base64InputStream(is); |
---|
153 | } else if (MimeUtil.ENC_QUOTED_PRINTABLE.equals(enc)) { |
---|
154 | decodedStream = new QuotedPrintableInputStream(is); |
---|
155 | } else { |
---|
156 | decodedStream = is; |
---|
157 | } |
---|
158 | */ |
---|
159 | |
---|
160 | if (bd.getMimeType().startsWith("text/")) { |
---|
161 | body = bodyFactory.textBody(is, bd.getCharset()); |
---|
162 | } else { |
---|
163 | body = bodyFactory.binaryBody(is); |
---|
164 | } |
---|
165 | |
---|
166 | Entity entity = ((Entity) stack.peek()); |
---|
167 | entity.setBody(body); |
---|
168 | } |
---|
169 | |
---|
170 | /** |
---|
171 | * @see org.apache.james.mime4j.parser.ContentHandler#endMultipart() |
---|
172 | */ |
---|
173 | public void endMultipart() throws MimeException { |
---|
174 | stack.pop(); |
---|
175 | } |
---|
176 | |
---|
177 | /** |
---|
178 | * @see org.apache.james.mime4j.parser.ContentHandler#startBodyPart() |
---|
179 | */ |
---|
180 | public void startBodyPart() throws MimeException { |
---|
181 | expect(Multipart.class); |
---|
182 | |
---|
183 | BodyPart bodyPart = new BodyPart(); |
---|
184 | ((Multipart) stack.peek()).addBodyPart(bodyPart); |
---|
185 | stack.push(bodyPart); |
---|
186 | } |
---|
187 | |
---|
188 | /** |
---|
189 | * @see org.apache.james.mime4j.parser.ContentHandler#endBodyPart() |
---|
190 | */ |
---|
191 | public void endBodyPart() throws MimeException { |
---|
192 | expect(BodyPart.class); |
---|
193 | stack.pop(); |
---|
194 | } |
---|
195 | |
---|
196 | /** |
---|
197 | * @see org.apache.james.mime4j.parser.ContentHandler#epilogue(java.io.InputStream) |
---|
198 | */ |
---|
199 | public void epilogue(InputStream is) throws MimeException, IOException { |
---|
200 | expect(MultipartImpl.class); |
---|
201 | ByteSequence bytes = loadStream(is); |
---|
202 | ((MultipartImpl) stack.peek()).setEpilogueRaw(bytes); |
---|
203 | } |
---|
204 | |
---|
205 | /** |
---|
206 | * @see org.apache.james.mime4j.parser.ContentHandler#preamble(java.io.InputStream) |
---|
207 | */ |
---|
208 | public void preamble(InputStream is) throws MimeException, IOException { |
---|
209 | expect(MultipartImpl.class); |
---|
210 | ByteSequence bytes = loadStream(is); |
---|
211 | ((MultipartImpl) stack.peek()).setPreambleRaw(bytes); |
---|
212 | } |
---|
213 | |
---|
214 | /** |
---|
215 | * Unsupported. |
---|
216 | * @see org.apache.james.mime4j.parser.ContentHandler#raw(java.io.InputStream) |
---|
217 | */ |
---|
218 | public void raw(InputStream is) throws MimeException, IOException { |
---|
219 | throw new UnsupportedOperationException("Not supported"); |
---|
220 | } |
---|
221 | |
---|
222 | private static ByteSequence loadStream(InputStream in) throws IOException { |
---|
223 | ByteArrayBuffer bab = new ByteArrayBuffer(64); |
---|
224 | |
---|
225 | int b; |
---|
226 | while ((b = in.read()) != -1) { |
---|
227 | bab.append(b); |
---|
228 | } |
---|
229 | |
---|
230 | return bab; |
---|
231 | } |
---|
232 | |
---|
233 | } |
---|