KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > mail > pop3 > POP3Message


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21
22 /*
23  * @(#)POP3Message.java 1.16 05/08/29
24  *
25  * Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package com.sun.mail.pop3;
29
30 import java.io.*;
31 import java.util.Enumeration JavaDoc;
32 import javax.mail.*;
33 import javax.mail.internet.*;
34 import javax.mail.event.*;
35
36 /**
37  * A POP3 Message. Just like a MimeMessage except that
38  * some things are not supported.
39  *
40  * @author Bill Shannon
41  */

42 public class POP3Message extends MimeMessage {
43
44     /*
45      * Our locking strategy is to always lock the POP3Folder before the
46      * POP3Message so we have to be careful to drop our lock before calling
47      * back to the folder to close it and notify of connection lost events.
48      */

49
50     // flag to indicate we haven't tried to fetch the UID yet
51
static final String JavaDoc UNKNOWN = "UNKNOWN";
52
53     private POP3Folder folder; // overrides folder in MimeMessage
54
private int hdrSize = -1;
55     private int msgSize = -1;
56     String JavaDoc uid = UNKNOWN; // controlled by folder lock
57

58     public POP3Message(Folder folder, int msgno)
59             throws MessagingException {
60     super(folder, msgno);
61     this.folder = (POP3Folder)folder;
62     }
63
64     /**
65      * Set the specified flags on this message to the specified value.
66      *
67      * @param newFlags the flags to be set
68      * @param set the value to be set
69      */

70     public void setFlags(Flags newFlags, boolean set)
71                 throws MessagingException {
72     Flags oldFlags = (Flags)flags.clone();
73     super.setFlags(newFlags, set);
74     if (!flags.equals(oldFlags))
75         folder.notifyMessageChangedListeners(
76                 MessageChangedEvent.FLAGS_CHANGED, this);
77     }
78
79     /**
80      * Return the size of the content of this message in bytes.
81      * Returns -1 if the size cannot be determined. <p>
82      *
83      * Note that this number may not be an exact measure of the
84      * content size and may or may not account for any transfer
85      * encoding of the content. <p>
86      *
87      * @return size of content in bytes
88      * @exception MessagingException
89      */

90     public int getSize() throws MessagingException {
91     // avoid synchronization once size has been cached
92
if (msgSize >= 0)
93         return msgSize;
94     try {
95         synchronized (this) {
96         if (msgSize < 0) {
97             /*
98              * Use LIST to determine the entire message
99              * size and subtract out the header size
100              * (which may involve loading the headers,
101              * which may load the content as a side effect).
102              * If the content is loaded as a side effect of
103              * loading the headers, get the size directly.
104              */

105             if (headers == null)
106             loadHeaders();
107             if (contentStream != null)
108             msgSize = contentStream.available();
109             else
110             msgSize = folder.getProtocol().list(msgnum) - hdrSize;
111         }
112         return msgSize;
113         }
114     } catch (EOFException eex) {
115         folder.close(false);
116         throw new FolderClosedException(folder, eex.toString());
117     } catch (IOException ex) {
118         throw new MessagingException("error getting size", ex);
119     }
120     }
121
122     /**
123      * Produce the raw bytes of the content. The data is fetched using
124      * the POP3 RETR command.
125      *
126      * @see #contentStream
127      */

128     protected InputStream getContentStream()
129                     throws MessagingException {
130     try {
131     synchronized(this) {
132         if (contentStream == null) {
133         InputStream rawcontent = folder.getProtocol().retr(msgnum,
134                     msgSize > 0 ? msgSize + hdrSize : 0);
135         if (rawcontent == null) {
136             expunged = true;
137             throw new MessageRemovedException(); // XXX - what else?
138
}
139         if (headers == null ||
140             ((POP3Store)(folder.getStore())).forgetTopHeaders) {
141             headers = new InternetHeaders(rawcontent);
142             hdrSize =
143             (int)((SharedInputStream)rawcontent).getPosition();
144         } else {
145             /*
146              * Already have the headers, have to skip the headers
147              * in the content array and return the body.
148              *
149              * XXX - It seems that some mail servers return slightly
150              * different headers in the RETR results than were returned
151              * in the TOP results, so we can't depend on remembering
152              * the size of the headers from the TOP command and just
153              * skipping that many bytes. Instead, we have to process
154              * the content, skipping over the header until we come to
155              * the empty line that separates the header from the body.
156              */

157             int offset = 0;
158             for (;;) {
159             int len = 0; // number of bytes in this line
160
int c1;
161             while ((c1 = rawcontent.read()) >= 0) {
162                 if (c1 == '\n') // end of line
163
break;
164                 else if (c1 == '\r') {
165                 // got CR, is the next char LF?
166
if (rawcontent.available() > 0) {
167                     rawcontent.mark(1);
168                     if (rawcontent.read() != '\n')
169                     rawcontent.reset();
170                 }
171                 break; // in any case, end of line
172
}
173
174                 // not CR, NL, or CRLF, count the byte
175
len++;
176             }
177             // here when end of line or out of data
178

179             // if out of data, we're done
180
if (rawcontent.available() == 0)
181                 break;
182             
183             // if it was an empty line, we're done
184
if (len == 0)
185                 break;
186             }
187             hdrSize =
188             (int)((SharedInputStream)rawcontent).getPosition();
189         }
190         contentStream =
191             ((SharedInputStream)rawcontent).newStream(hdrSize, -1);
192         rawcontent = null; // help GC
193
}
194     }
195     } catch (EOFException eex) {
196         folder.close(false);
197         throw new FolderClosedException(folder, eex.toString());
198     } catch (IOException ex) {
199         throw new MessagingException("error fetching POP3 content", ex);
200     }
201     return super.getContentStream();
202     }
203
204     /**
205      * Invalidate the cache of content for this message object, causing
206      * it to be fetched again from the server the next time it is needed.
207      * If <code>invalidateHeaders</code> is true, invalidate the headers
208      * as well.
209      *
210      * @param invalidateHeaders invalidate the headers as well?
211      */

212     public void invalidate(boolean invalidateHeaders) {
213     content = null;
214     contentStream = null;
215     msgSize = -1;
216     if (invalidateHeaders) {
217         headers = null;
218         hdrSize = -1;
219     }
220     }
221
222     /**
223      * Fetch the header of the message and the first <code>n</code> lines
224      * of the raw content of the message. The headers and data are
225      * available in the returned InputStream.
226      *
227      * @param n number of lines of content to fetch
228      * @return InputStream containing the message headers and n content lines
229      */

230     public InputStream top(int n) throws MessagingException {
231     try {
232         synchronized (this) {
233         return folder.getProtocol().top(msgnum, n);
234         }
235     } catch (EOFException eex) {
236         folder.close(false);
237         throw new FolderClosedException(folder, eex.toString());
238     } catch (IOException ex) {
239         throw new MessagingException("error getting size", ex);
240     }
241     }
242
243     /**
244      * Get all the headers for this header_name. Note that certain
245      * headers may be encoded as per RFC 2047 if they contain
246      * non US-ASCII characters and these should be decoded. <p>
247      *
248      * @param name name of header
249      * @return array of headers
250      * @exception MessagingException
251      * @see javax.mail.internet.MimeUtility
252      */

253     public String JavaDoc[] getHeader(String JavaDoc name)
254             throws MessagingException {
255     if (headers == null)
256         loadHeaders();
257     return headers.getHeader(name);
258     }
259
260     /**
261      * Get all the headers for this header name, returned as a single
262      * String, with headers separated by the delimiter. If the
263      * delimiter is <code>null</code>, only the first header is
264      * returned.
265      *
266      * @param name the name of this header
267      * @param delimiter delimiter between returned headers
268      * @return the value fields for all headers with
269      * this name
270      * @exception MessagingException
271      */

272     public String JavaDoc getHeader(String JavaDoc name, String JavaDoc delimiter)
273                 throws MessagingException {
274     if (headers == null)
275         loadHeaders();
276     return headers.getHeader(name, delimiter);
277     }
278
279     /**
280      * Set the value for this header_name. Throws IllegalWriteException
281      * because POP3 messages are read-only.
282      *
283      * @param name header name
284      * @param value header value
285      * @see javax.mail.internet.MimeUtility
286      * @exception IllegalWriteException because the underlying
287      * implementation does not support modification
288      * @exception IllegalStateException if this message is
289      * obtained from a READ_ONLY folder.
290      */

291     public void setHeader(String JavaDoc name, String JavaDoc value)
292                                 throws MessagingException {
293     // XXX - should check for read-only folder?
294
throw new IllegalWriteException("POP3 messages are read-only");
295     }
296
297     /**
298      * Add this value to the existing values for this header_name.
299      * Throws IllegalWriteException because POP3 messages are read-only.
300      *
301      * @param name header name
302      * @param value header value
303      * @see javax.mail.internet.MimeUtility
304      * @exception IllegalWriteException because the underlying
305      * implementation does not support modification
306      * @exception IllegalStateException if this message is
307      * obtained from a READ_ONLY folder.
308      */

309     public void addHeader(String JavaDoc name, String JavaDoc value)
310                                 throws MessagingException {
311     // XXX - should check for read-only folder?
312
throw new IllegalWriteException("POP3 messages are read-only");
313     }
314
315     /**
316      * Remove all headers with this name.
317      * Throws IllegalWriteException because POP3 messages are read-only.
318      *
319      * @exception IllegalWriteException because the underlying
320      * implementation does not support modification
321      * @exception IllegalStateException if this message is
322      * obtained from a READ_ONLY folder.
323      */

324     public void removeHeader(String JavaDoc name)
325                                 throws MessagingException {
326     // XXX - should check for read-only folder?
327
throw new IllegalWriteException("POP3 messages are read-only");
328     }
329
330     /**
331      * Return all the headers from this Message as an enumeration
332      * of Header objects. <p>
333      *
334      * Note that certain headers may be encoded as per RFC 2047
335      * if they contain non US-ASCII characters and these should
336      * be decoded. <p>
337      *
338      * @return array of header objects
339      * @exception MessagingException
340      * @see javax.mail.internet.MimeUtility
341      */

342     public Enumeration JavaDoc getAllHeaders() throws MessagingException {
343     if (headers == null)
344         loadHeaders();
345     return headers.getAllHeaders();
346     }
347
348     /**
349      * Return matching headers from this Message as an Enumeration of
350      * Header objects.
351      *
352      * @exception MessagingException
353      */

354     public Enumeration JavaDoc getMatchingHeaders(String JavaDoc[] names)
355             throws MessagingException {
356     if (headers == null)
357         loadHeaders();
358     return headers.getMatchingHeaders(names);
359     }
360
361     /**
362      * Return non-matching headers from this Message as an
363      * Enumeration of Header objects.
364      *
365      * @exception MessagingException
366      */

367     public Enumeration JavaDoc getNonMatchingHeaders(String JavaDoc[] names)
368             throws MessagingException {
369     if (headers == null)
370         loadHeaders();
371     return headers.getNonMatchingHeaders(names);
372     }
373
374     /**
375      * Add a raw RFC822 header-line.
376      * Throws IllegalWriteException because POP3 messages are read-only.
377      *
378      * @exception IllegalWriteException because the underlying
379      * implementation does not support modification
380      * @exception IllegalStateException if this message is
381      * obtained from a READ_ONLY folder.
382      */

383     public void addHeaderLine(String JavaDoc line) throws MessagingException {
384     // XXX - should check for read-only folder?
385
throw new IllegalWriteException("POP3 messages are read-only");
386     }
387
388     /**
389      * Get all header lines as an Enumeration of Strings. A Header
390      * line is a raw RFC822 header-line, containing both the "name"
391      * and "value" field.
392      *
393      * @exception MessagingException
394      */

395     public Enumeration JavaDoc getAllHeaderLines() throws MessagingException {
396     if (headers == null)
397         loadHeaders();
398     return headers.getAllHeaderLines();
399     }
400
401     /**
402      * Get matching header lines as an Enumeration of Strings.
403      * A Header line is a raw RFC822 header-line, containing both
404      * the "name" and "value" field.
405      *
406      * @exception MessagingException
407      */

408     public Enumeration JavaDoc getMatchingHeaderLines(String JavaDoc[] names)
409                                         throws MessagingException {
410     if (headers == null)
411         loadHeaders();
412     return headers.getMatchingHeaderLines(names);
413     }
414
415     /**
416      * Get non-matching header lines as an Enumeration of Strings.
417      * A Header line is a raw RFC822 header-line, containing both
418      * the "name" and "value" field.
419      *
420      * @exception MessagingException
421      */

422     public Enumeration JavaDoc getNonMatchingHeaderLines(String JavaDoc[] names)
423                                         throws MessagingException {
424     if (headers == null)
425         loadHeaders();
426     return headers.getNonMatchingHeaderLines(names);
427     }
428
429     /**
430      * POP3 message can't be changed. This method throws
431      * IllegalWriteException.
432      *
433      * @exception IllegalWriteException because the underlying
434      * implementation does not support modification
435      */

436     public void saveChanges() throws MessagingException {
437     // POP3 Messages are read-only
438
throw new IllegalWriteException("POP3 messages are read-only");
439     }
440
441     /**
442      * Load the headers for this message into the InternetHeaders object.
443      * The headers are fetched using the POP3 TOP command.
444      */

445     private void loadHeaders() throws MessagingException {
446     try {
447         synchronized (this) {
448         if (headers != null) // check again under lock
449
return;
450         InputStream hdrs = null;
451         if (((POP3Store)(folder.getStore())).disableTop ||
452             (hdrs = folder.getProtocol().top(msgnum, 0)) == null) {
453             // possibly because the TOP command isn't supported,
454
// load headers as a side effect of loading the entire
455
// content.
456
InputStream cs = getContentStream();
457             cs.close();
458         } else {
459             hdrSize = hdrs.available();
460             headers = new InternetHeaders(hdrs);
461         }
462         }
463     } catch (EOFException eex) {
464         folder.close(false);
465         throw new FolderClosedException(folder, eex.toString());
466     } catch (IOException ex) {
467         throw new MessagingException("error loading POP3 headers", ex);
468     }
469     }
470 }
471
Popular Tags