KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > mail > MimePart


1 /*
2  * MimePart.java
3  *
4  * Copyright (C) 2000-2003 Peter Graves
5  * $Id: MimePart.java,v 1.2 2003/06/29 00:19:34 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j.mail;
23
24 import java.io.BufferedOutputStream JavaDoc;
25 import java.io.ByteArrayOutputStream JavaDoc;
26 import java.io.FileOutputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.UnsupportedEncodingException JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Vector JavaDoc;
32 import org.armedbear.j.Directories;
33 import org.armedbear.j.Editor;
34 import org.armedbear.j.File;
35 import org.armedbear.j.FastStringBuffer;
36 import org.armedbear.j.Headers;
37 import org.armedbear.j.Log;
38 import org.armedbear.j.StringPair;
39 import org.armedbear.j.Utilities;
40
41 public class MimePart
42 {
43     protected String JavaDoc raw;
44     protected Headers headers;
45
46     private Vector JavaDoc parts;
47
48     public MimePart(String JavaDoc raw)
49     {
50         this.raw = raw;
51     }
52
53     public MimePart(String JavaDoc raw, Headers headers)
54     {
55         this.raw = raw;
56         this.headers = headers;
57     }
58
59     public final String JavaDoc getRawText()
60     {
61         return raw;
62     }
63
64     public String JavaDoc getAllHeaders()
65     {
66         if (raw.startsWith("\r\n"))
67             return "\r\n";
68         if (raw.startsWith("\n"))
69             return "\n";
70         int index = raw.indexOf("\r\n\r\n");
71         if (index >= 0)
72             return RFC2047.decode(raw.substring(0, index + 2));
73         index = raw.indexOf("\n\n");
74         if (index >= 0)
75             return RFC2047.decode(raw.substring(0, index + 1));
76         return raw;
77     }
78
79     public String JavaDoc getRawHeaders()
80     {
81         if (raw.startsWith("\r\n"))
82             return "\r\n";
83         if (raw.startsWith("\n"))
84             return "\n";
85         int index = raw.indexOf("\r\n\r\n");
86         if (index >= 0)
87             return raw.substring(0, index + 2);
88         index = raw.indexOf("\n\n");
89         if (index >= 0)
90             return raw.substring(0, index + 1);
91         return raw;
92     }
93
94     public String JavaDoc getRawBody()
95     {
96         if (raw.startsWith("\r\n"))
97             return raw.substring(2);
98         else if (raw.startsWith("\n"))
99             return raw.substring(1);
100         else {
101             int index = raw.indexOf("\r\n\r\n");
102             if (index >= 0)
103                 return raw.substring(index + 4);
104             else {
105                 index = raw.indexOf("\n\n");
106                 if (index >= 0)
107                     return raw.substring(index + 2);
108                 else
109                     return raw;
110             }
111         }
112     }
113
114     public String JavaDoc getDecodedBody()
115     {
116         final String JavaDoc rawBody = getRawBody();
117         final String JavaDoc contentType = getContentType();
118         final String JavaDoc transferEncoding = getTransferEncoding();
119         final String JavaDoc charset =
120             Utilities.getCharsetFromContentType(getHeaderValue(Headers.CONTENT_TYPE));
121         final String JavaDoc characterEncoding = Utilities.getEncodingFromCharset(charset);
122         if (contentType == null || contentType.toLowerCase().startsWith("text/")) {
123             if (transferEncoding == null ||
124                 transferEncoding.equals("7bit") ||
125                 transferEncoding.equals("8bit") ||
126                 transferEncoding.equals("binary"))
127                 return rawBody;
128             else if (transferEncoding.equals("quoted-printable")) {
129                 byte[] bytes = QuotedPrintableDecoder.decode(rawBody);
130                 try {
131                     return new String JavaDoc(bytes, characterEncoding);
132                 }
133                 catch (UnsupportedEncodingException JavaDoc e) {
134                     Log.error(e);
135                     return new String JavaDoc(bytes);
136                 }
137             } else if (transferEncoding.equals("base64")) {
138                 try {
139                     ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc();
140                     Base64Decoder.decode(rawBody, out); // Ignore errors.
141
byte[] bytes = out.toByteArray();
142                     if (bytes != null) {
143                         try {
144                             return new String JavaDoc(bytes, 0, bytes.length,
145                                 characterEncoding);
146                         }
147                         catch (UnsupportedEncodingException JavaDoc e) {
148                             Log.error(e);
149                             return new String JavaDoc(bytes, 0, bytes.length);
150                         }
151                     }
152                 }
153                 catch (IOException JavaDoc e) {
154                     Log.error(e);
155                 }
156                 return null;
157             } else
158                 return null;
159         } else if (contentType.startsWith("multipart/"))
160             return rawBody;
161         else if (transferEncoding == null)
162             return rawBody;
163         else
164             return null;
165     }
166
167     private byte[] getDecodedBodyAsByteArray()
168     {
169         final String JavaDoc rawBody = getRawBody();
170         final String JavaDoc encoding = getTransferEncoding();
171         if (encoding == null || encoding.equals("7bit") ||
172             encoding.equals("8bit") || encoding.equals("binary")) {
173             byte[] bytes = null;
174             try {
175                  bytes = rawBody.getBytes("ISO8859_1");
176             }
177             catch (UnsupportedEncodingException JavaDoc e) {
178                 Log.error(e);
179             }
180             return bytes;
181         }
182         if (encoding.equals("quoted-printable"))
183             return QuotedPrintableDecoder.decode(rawBody);
184         if (encoding.equals("base64")) {
185             try {
186                 ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc();
187                 if (Base64Decoder.decode(rawBody, out))
188                     return out.toByteArray();
189             }
190             catch (IOException JavaDoc e) {
191                 Log.error(e);
192             }
193             // Fall through, return null...
194
}
195         return null;
196     }
197
198     public Vector JavaDoc getParts()
199     {
200         return parts;
201     }
202
203     public MimePart getPart(int i)
204     {
205         if (parts == null)
206             return null;
207         if (i < 0)
208             return null;
209         if (i >= parts.size())
210             return null;
211         return (MimePart) parts.get(i);
212     }
213
214     protected void addParts(Vector JavaDoc v)
215     {
216         v.add(this);
217         // Recurse.
218
if (parts != null) {
219             for (int i = 0; i < parts.size(); i++) {
220                 MimePart part = (MimePart) parts.get(i);
221                 String JavaDoc contentType = part.getContentType();
222                 if (contentType != null && contentType.startsWith("multipart/"))
223                     part.addParts(v);
224                 else
225                     v.add(part);
226             }
227         }
228     }
229
230     public final Headers getHeaders()
231     {
232         if (headers == null)
233             headers = Headers.parse(raw);
234         return headers;
235     }
236
237     public final String JavaDoc getHeaderValue(int index)
238     {
239         if (headers == null)
240             headers = Headers.parse(raw);
241         return headers.getValue(index);
242     }
243
244     public final String JavaDoc getContentType()
245     {
246         String JavaDoc s = getHeaderValue(Headers.CONTENT_TYPE);
247         if (s == null )
248             return null;
249         s = s.trim();
250         if (s.length() == 0)
251             return null;
252         int index = s.indexOf(';');
253         if (index >= 0)
254             s = s.substring(0, index);
255         return s.toLowerCase();
256     }
257
258     public final String JavaDoc getTransferEncoding()
259     {
260         String JavaDoc s = getHeaderValue(Headers.CONTENT_TRANSFER_ENCODING);
261         if (s == null )
262             return null;
263         return s.toLowerCase();
264     }
265
266     public final String JavaDoc getDisposition()
267     {
268         String JavaDoc s = getHeaderValue(Headers.CONTENT_DISPOSITION);
269         if (s == null)
270             return null;
271         s = s.trim();
272         int index = s.indexOf(';');
273         if (index >= 0 )
274             s = s.substring(0, index);
275         return s;
276     }
277
278     public final int getSize()
279     {
280         String JavaDoc s = getRawBody();
281         return s == null ? 0 : s.length();
282     }
283
284     public final boolean isAttachment()
285     {
286         String JavaDoc s = getHeaderValue(Headers.CONTENT_DISPOSITION);
287         if (s != null && s.trim().startsWith("attachment"))
288             return true;
289         else
290             return false;
291     }
292
293     public final boolean isInline()
294     {
295         String JavaDoc s = getHeaderValue(Headers.CONTENT_DISPOSITION);
296         if (s != null && s.trim().startsWith("inline"))
297             return true;
298         return false;
299     }
300
301     public String JavaDoc getAttachmentFileName()
302     {
303         String JavaDoc filename =
304             getHeaderParameter(Headers.CONTENT_DISPOSITION, "filename");
305         if (filename == null)
306             filename = getHeaderParameter(Headers.CONTENT_TYPE, "name");
307         if (filename != null) {
308             filename = filename.trim();
309             int length = filename.length();
310             // Strip quotes.
311
if (length >= 2 && filename.charAt(0) == '"' &&
312                 filename.charAt(length-1) == '"')
313                 filename = filename.substring(1, length-1);
314             // Filename might be RFC2047-encoded.
315
filename = RFC2047.decode(filename);
316             // Remove path prefix, if any.
317
int index = filename.lastIndexOf('/');
318             if (index < 0)
319                 index = filename.lastIndexOf('\\');
320             if (index >= 0)
321                 filename = filename.substring(index+1);
322         }
323         return filename;
324     }
325
326     private String JavaDoc getHeaderParameter(int header, String JavaDoc parameterName)
327     {
328         String JavaDoc s = getHeaderValue(header);
329         if (s != null) {
330             s = s.trim();
331             String JavaDoc lower = s.toLowerCase();
332             int index = lower.indexOf(parameterName.concat("="));
333             if (index >= 0) {
334                 int begin = index + parameterName.length() + 1;
335                 int end = s.indexOf(';', begin);
336                 if (end >= 0)
337                     return s.substring(begin, end);
338                 else
339                     return s.substring(begin);
340             }
341         }
342         return null;
343     }
344
345     public File cacheDecoded()
346     {
347         String JavaDoc filename = getAttachmentFileName();
348         String JavaDoc extension = null;
349         if (filename != null && filename.length() > 0) {
350             extension = Utilities.getExtension(filename);
351         } else {
352             // No filename specified.
353
String JavaDoc contentType = getContentType();
354             if (contentType != null) {
355                 if (contentType.equals("image/jpeg"))
356                     extension = ".jpg";
357                 else if (contentType.equals("image/gif"))
358                     extension = ".gif";
359                 else if (contentType.equals("text/html"))
360                     extension = ".html";
361             }
362         }
363         File cache =
364             Utilities.getTempFile(Directories.getTempDirectory(), extension);
365         if (cache != null && saveDecoded(cache))
366             return cache;
367         else
368             return null;
369     }
370
371     public boolean saveDecoded(File file)
372     {
373         String JavaDoc encoding = getTransferEncoding();
374         if (encoding == null || encoding.equals("7bit") ||
375             encoding.equals("8bit") || encoding.equals("binary") ||
376             encoding.equals("quoted-printable")) {
377             try {
378                 byte[] bytes = getDecodedBodyAsByteArray();
379                 if (bytes == null)
380                     return false;
381                 FileOutputStream JavaDoc out = file.getOutputStream();
382                 out.write(bytes);
383                 out.flush();
384                 out.close();
385                 return true;
386             }
387             catch (IOException JavaDoc e) {
388                 Log.error(e);
389                 return false;
390             }
391         } else if (encoding.equals("base64")) {
392             return saveDecodedBase64(file);
393         } else if (encoding.equals("x-uuencode")) {
394             Log.error("saveDecoded x-uuencode not supported");
395             return false;
396         } else {
397             Log.error("saveDecoded unrecognized encoding " + encoding);
398             return false;
399         }
400     }
401
402     private boolean saveDecodedBase64(File file)
403     {
404         boolean success = false;
405         try {
406             BufferedOutputStream JavaDoc out =
407                 new BufferedOutputStream JavaDoc(file.getOutputStream());
408             String JavaDoc rawBody = getRawBody();
409             success = Base64Decoder.decode(rawBody, out);
410             out.flush();
411             out.close();
412         }
413         catch (IOException JavaDoc e) {
414             Log.error(e);
415             success = false;
416         }
417         if (!success)
418             file.delete();
419         return success;
420     }
421
422     private static final String JavaDoc BOUNDARY_START = "boundary=";
423
424     public void parse()
425     {
426         final String JavaDoc contentType = getHeaderValue(Headers.CONTENT_TYPE);
427         if (contentType == null)
428             return;
429         if (contentType.toLowerCase().startsWith("multipart/")) {
430             int index = contentType.toLowerCase().indexOf(BOUNDARY_START);
431             if (index < 0) {
432                 Log.error("can't find boundary parameter");
433                 return;
434             }
435             String JavaDoc boundary =
436                 contentType.substring(index + BOUNDARY_START.length()).trim();
437             if (boundary.length() >= 2 && boundary.charAt(0) == '"') {
438                 int end = boundary.indexOf('"', 1);
439                 if (end >= 0)
440                     boundary = boundary.substring(1, end);
441             }
442             parts = parseParts(boundary);
443             if (parts != null) {
444                 for (int i = 0; i < parts.size(); i++) {
445                     MimePart part = (MimePart) parts.get(i);
446                     part.parse();
447                 }
448             }
449             return;
450         }
451         final String JavaDoc disposition = getDisposition();
452         if (disposition != null && disposition.equalsIgnoreCase("attachment")) {
453             parts = new Vector JavaDoc();
454             MimePart part = new MimePart(raw);
455             parts.add(part);
456         }
457     }
458
459     private Vector JavaDoc parseParts(String JavaDoc boundary)
460     {
461         final String JavaDoc marker = "--" + boundary;
462         final String JavaDoc endMarker = marker + "--";
463         final int veryEnd = raw.indexOf(endMarker);
464         int start = raw.indexOf(marker);
465         if (start < 0)
466             return null;
467         Vector JavaDoc v = new Vector JavaDoc();
468         while (true) {
469             start += marker.length();
470             if (raw.charAt(start) == '\r')
471                 ++start;
472             if (raw.charAt(start) == '\n')
473                 ++start;
474             int end = raw.indexOf(marker, start);
475             if (end < 0)
476                 end = raw.length();
477             MimePart part = new MimePart(raw.substring(start, end));
478             v.add(part);
479             if (end == veryEnd || end == raw.length())
480                 break;
481             start = end;
482         }
483         return v;
484     }
485 }
486
Popular Tags