1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.mercury.imap.util.section;
14
15 import java.io.ByteArrayInputStream;
16 import java.io.ByteArrayOutputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.PrintStream;
20 import java.io.SequenceInputStream;
21 import javax.mail.BodyPart;
22 import javax.mail.Flags;
23 import javax.mail.Folder;
24 import javax.mail.Message;
25 import javax.mail.MessagingException;
26 import javax.mail.Multipart;
27 import javax.mail.Part;
28 import javax.mail.internet.MimeBodyPart;
29 import javax.mail.internet.MimeMessage;
30 import javax.mail.internet.MimePart;
31 import javax.mail.internet.SharedInputStream;
32
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import org.abstracthorizon.mercury.common.io.RangedInputStream;
37 import org.abstracthorizon.mercury.imap.util.MessageUtilities;
38
39
40
41
42
43
44 public class Body extends PointerSection {
45
46
47 protected static final Logger logger = LoggerFactory.getLogger(Body.class);
48
49
50 public boolean peek = false;
51
52
53 public int from = -1;
54
55
56 public int to = -1;
57
58
59 public boolean rfc822 = false;
60
61
62
63
64 public Body() {
65 }
66
67
68
69
70
71
72
73
74 public MeasuredInputStream getInputStream(MimeMessage msg) throws IOException, MessagingException {
75 long size = -1;
76 InputStream is = null;
77 String headers = null;
78
79
80 Part part = msg;
81 PointerSection section = this;
82
83 while ((section.child != null) && (section.child instanceof MultipartSection)) {
84 section = (MultipartSection)section.child;
85 Object o = part.getContent();
86 int partNo = ((MultipartSection)section).partNo-1;
87 if (o instanceof Multipart) {
88 part = ((Multipart)o).getBodyPart(partNo);
89 if (part.getContentType().toLowerCase().startsWith("message/rfc822")) {
90 part = (MimePart)part.getContent();
91 }
92 } else if (o instanceof MimeMessage) {
93 part = (MimeMessage)o;
94 } else if (partNo == 0) {
95
96 } else {
97 throw new MessagingException("Multipart part expected");
98 }
99
100 }
101 if ((section.child != null) && (section.child instanceof HeaderSection)) {
102
103 HeaderSection ss = (HeaderSection)section.child;
104 if (ss.all) {
105 headers = MessageUtilities.createHeaders((MimePart)part);
106 } else {
107 headers = MessageUtilities.createHeaders((MimePart)part, ss.fields, ss.not);
108 }
109 byte[] headerBytes = headers.getBytes();
110 is = new ByteArrayInputStream(headerBytes);
111 size = headerBytes.length;
112
113 } else if ((section.child != null) && (section.child instanceof TextSection)) {
114 is = getPartsInputStream(part);
115 size = calcSize(part);
116 } else if ((section.child != null) && (section.child instanceof MimeSection)) {
117 headers = MessageUtilities.createHeaders((MimePart)part);
118 byte[] headerBytes = headers.getBytes();
119 is = new ByteArrayInputStream(headerBytes);
120 size = headerBytes.length;
121 } else if (part instanceof MimeMessage) {
122 headers = MessageUtilities.createHeaders((MimePart)part);
123 byte[] headerBytes = headers.getBytes();
124 ByteArrayInputStream bais = new ByteArrayInputStream(headerBytes);
125 is = getPartsInputStream(part);
126 is = new SequenceInputStream(bais, is);
127 long partSize = calcSize(part);
128 long headersSize = headerBytes.length;
129 size = partSize+headersSize;
130 } else {
131 is = getPartsInputStream(part);
132 size = calcSize(part);
133 }
134
135 if ((from >= 0) && (to >= 0)) {
136 if (to > size) {
137 to = (int)size;
138 }
139 size = to-from;
140 if (is instanceof SharedInputStream) {
141 is = ((SharedInputStream)is).newStream(from, to);
142 } else {
143 is = new RangedInputStream(is, from, to);
144 }
145 }
146
147 return new MeasuredInputStream(is, size);
148 }
149
150
151
152
153
154
155
156
157 public InputStream getPartsInputStream(Part part) throws IOException, MessagingException {
158 try {
159 if (part instanceof MimeBodyPart) {
160 return ((MimeBodyPart)part).getRawInputStream();
161
162
163 } else if (part instanceof MimeMessage) {
164 return ((MimeMessage)part).getRawInputStream();
165 } else {
166
167
168 return part.getInputStream();
169 }
170 } catch (IOException e) {
171 try {
172
173 String oldEncoding = "";
174 String[] encodings = part.getHeader("Content-Transfer-Encoding");
175 if (encodings.length > 0) {
176 oldEncoding = encodings[0];
177 }
178 part.addHeader("X-Error", "Wrong: Content-Transfer-Encoding: "+oldEncoding);
179 part.setHeader("Content-Transfer-Encoding", "7bit");
180 saveChanges(part);
181 return part.getInputStream();
182 } catch (MessagingException me) {
183 ByteArrayOutputStream baos = new ByteArrayOutputStream();
184 PrintStream ps = new PrintStream(baos);
185 me.printStackTrace(ps);
186 return new ByteArrayInputStream(baos.toByteArray());
187 }
188 }
189 }
190
191
192
193
194
195
196 protected void saveChanges(Part part) throws MessagingException {
197 while ((part != null) && !(part instanceof MimeMessage)) {
198 if (part instanceof BodyPart) {
199 Multipart mp = ((BodyPart)part).getParent();
200 part = mp.getParent();
201 } else {
202
203
204
205
206
207
208
209 part = null;
210 }
211 }
212 if (part instanceof MimeMessage) {
213 MimeMessage mm = (MimeMessage)part;
214 Folder f = mm.getFolder();
215 f.appendMessages(new Message[]{mm});
216 mm.setFlag(Flags.Flag.DELETED, true);
217 }
218 }
219
220
221
222
223
224 public boolean hasStream() {
225 return !((child != null) && (child instanceof HeaderSection));
226 }
227
228
229
230
231
232 public String toString() {
233 StringBuffer b = new StringBuffer();
234 if (rfc822) {
235 if ((child != null) && (child instanceof HeaderSection)) {
236 b.append("RFC822.HEADER");
237 } else if ((child != null) && (child instanceof TextSection)) {
238 b.append("RFC822.TEXT");
239 } else {
240 b.append("RFC822");
241 }
242 } else {
243 b.append("BODY");
244 b.append("[");
245 if (child != null) {
246 b.append(child.toString());
247 }
248 b.append("]");
249 if ((from >= 0) && (to >= 0)) {
250 b.append("<").append(from).append('.').append(to).append(">");
251 }
252 }
253 return b.toString();
254 }
255
256
257
258
259
260
261
262 protected InputStream skipHeaders(InputStream is) throws IOException {
263 int state = 0;
264 while (true) {
265 int c = is.read();
266 if (c < 0) {
267 return is;
268 }
269 switch (state) {
270 case 0: {
271 if (c == 13) {
272 state = 1;
273 }
274 break;
275 }
276 case 1: {
277 if (c == 10) {
278 state = 2;
279 } else {
280 state = 0;
281 }
282 break;
283 }
284 case 2: {
285 if (c == 13) {
286 state = 3;
287 } else {
288 state = 0;
289 }
290 break;
291 }
292 case 3: {
293 if (c == 10) {
294 return is;
295 }
296 break;
297 }
298 }
299 }
300 }
301
302
303
304
305
306
307
308
309 protected long calcSize(Part part) throws IOException, MessagingException {
310 InputStream is = getPartsInputStream(part);
311 if (is instanceof ByteArrayInputStream) {
312 return is.available();
313 }
314 if (is instanceof SharedInputStream) {
315 return is.available();
316 }
317 try {
318 long size = 0;
319 byte[] buf = new byte[10240];
320 int r = is.read(buf);
321 while (r >= 0) {
322 size = size+r;
323 r = is.read(buf);
324 }
325 return size;
326 } catch (Exception e) {
327
328
329
330 return part.getSize();
331 }
332 }
333 }