Skip to content

Package: POP3Message

POP3Message

nameinstructionbranchcomplexitylinemethod
POP3Message(Folder, int)
M: 32 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
addHeader(String, String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
addHeaderLine(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getAllHeaderLines()
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getAllHeaders()
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getContentStream()
M: 35 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
getHeader(String)
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getHeader(String, String)
M: 11 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getMatchingHeaderLines(String[])
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getMatchingHeaders(String[])
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getMimeStream()
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getNonMatchingHeaderLines(String[])
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getNonMatchingHeaders(String[])
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getRawStream(boolean)
M: 212 C: 0
0%
M: 30 C: 0
0%
M: 16 C: 0
0%
M: 53 C: 0
0%
M: 1 C: 0
0%
getSize()
M: 63 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 15 C: 0
0%
M: 1 C: 0
0%
invalidate(boolean)
M: 43 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 17 C: 0
0%
M: 1 C: 0
0%
loadHeaders()
M: 89 C: 0
0%
M: 12 C: 0
0%
M: 7 C: 0
0%
M: 25 C: 0
0%
M: 1 C: 0
0%
removeHeader(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
saveChanges()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
setFlags(Flags, boolean)
M: 20 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
setHeader(String, String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 1 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
top(int)
M: 34 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
writeTo(OutputStream, String[])
M: 97 C: 0
0%
M: 18 C: 0
0%
M: 10 C: 0
0%
M: 20 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package org.eclipse.angus.mail.pop3;
18:
19: import jakarta.mail.Flags;
20: import jakarta.mail.Folder;
21: import jakarta.mail.FolderClosedException;
22: import jakarta.mail.Header;
23: import jakarta.mail.IllegalWriteException;
24: import jakarta.mail.MessageRemovedException;
25: import jakarta.mail.MessagingException;
26: import jakarta.mail.event.MessageChangedEvent;
27: import jakarta.mail.internet.InternetHeaders;
28: import jakarta.mail.internet.MimeMessage;
29: import jakarta.mail.internet.SharedInputStream;
30: import org.eclipse.angus.mail.util.ReadableMime;
31:
32: import java.io.BufferedOutputStream;
33: import java.io.EOFException;
34: import java.io.IOException;
35: import java.io.InputStream;
36: import java.io.OutputStream;
37: import java.lang.ref.SoftReference;
38: import java.util.Enumeration;
39: import java.util.logging.Level;
40:
41: /**
42: * A POP3 Message. Just like a MimeMessage except that
43: * some things are not supported.
44: *
45: * @author Bill Shannon
46: */
47: public class POP3Message extends MimeMessage implements ReadableMime {
48:
49: /*
50: * Our locking strategy is to always lock the POP3Folder before the
51: * POP3Message so we have to be careful to drop our lock before calling
52: * back to the folder to close it and notify of connection lost events.
53: */
54:
55: // flag to indicate we haven't tried to fetch the UID yet
56: static final String UNKNOWN = "UNKNOWN";
57:
58: private POP3Folder folder; // overrides folder in MimeMessage
59: private int hdrSize = -1;
60: private int msgSize = -1;
61: String uid = UNKNOWN; // controlled by folder lock
62:
63: // rawData itself is never null
64: private SoftReference<InputStream> rawData
65: = new SoftReference<>(null);
66:
67: public POP3Message(Folder folder, int msgno)
68: throws MessagingException {
69: super(folder, msgno);
70:• assert folder instanceof POP3Folder;
71: this.folder = (POP3Folder) folder;
72: }
73:
74: /**
75: * Set the specified flags on this message to the specified value.
76: *
77: * @param newFlags the flags to be set
78: * @param set the value to be set
79: */
80: @Override
81: public synchronized void setFlags(Flags newFlags, boolean set)
82: throws MessagingException {
83: Flags oldFlags = (Flags) flags.clone();
84: super.setFlags(newFlags, set);
85:• if (!flags.equals(oldFlags))
86: folder.notifyMessageChangedListeners(
87: MessageChangedEvent.FLAGS_CHANGED, this);
88: }
89:
90: /**
91: * Return the size of the content of this message in bytes.
92: * Returns -1 if the size cannot be determined. <p>
93: *
94: * Note that this number may not be an exact measure of the
95: * content size and may or may not account for any transfer
96: * encoding of the content. <p>
97: *
98: * @return size of content in bytes
99: * @exception MessagingException for failures
100: */
101: @Override
102: public int getSize() throws MessagingException {
103: try {
104: synchronized (this) {
105: // if we already have the size, return it
106:• if (msgSize > 0)
107: return msgSize;
108: }
109:
110: /*
111: * Use LIST to determine the entire message
112: * size and subtract out the header size
113: * (which may involve loading the headers,
114: * which may load the content as a side effect).
115: * If the content is loaded as a side effect of
116: * loading the headers, it will set the size.
117: *
118: * Make sure to call loadHeaders() outside of the
119: * synchronization block. There's a potential race
120: * condition here but synchronization will occur in
121: * loadHeaders() to make sure the headers are only
122: * loaded once, and again in the following block to
123: * only compute msgSize once.
124: */
125:• if (headers == null)
126: loadHeaders();
127:
128: synchronized (this) {
129:• if (msgSize < 0)
130: msgSize = folder.getProtocol().list(msgnum) - hdrSize;
131: return msgSize;
132: }
133: } catch (EOFException eex) {
134: folder.close(false);
135: throw new FolderClosedException(folder, eex.toString());
136: } catch (IOException ex) {
137: throw new MessagingException("error getting size", ex);
138: }
139: }
140:
141: /**
142: * Produce the raw bytes of the message. The data is fetched using
143: * the POP3 RETR command. If skipHeader is true, just the content
144: * is returned.
145: */
146: private InputStream getRawStream(boolean skipHeader)
147: throws MessagingException {
148: InputStream rawcontent = null;
149: try {
150: synchronized (this) {
151: rawcontent = rawData.get();
152:• if (rawcontent == null) {
153: TempFile cache = folder.getFileCache();
154:• if (cache != null) {
155:• if (folder.logger.isLoggable(Level.FINE))
156: folder.logger.fine("caching message #" + msgnum +
157: " in temp file");
158: AppendStream os = cache.getAppendStream();
159: BufferedOutputStream bos = new BufferedOutputStream(os);
160: try {
161: folder.getProtocol().retr(msgnum, bos);
162: } finally {
163: bos.close();
164: }
165: rawcontent = os.getInputStream();
166: } else {
167: rawcontent = folder.getProtocol().retr(msgnum,
168:• msgSize > 0 ? msgSize + hdrSize : 0);
169: }
170:• if (rawcontent == null) {
171: expunged = true;
172: throw new MessageRemovedException(
173: "can't retrieve message #" + msgnum +
174: " in POP3Message.getContentStream"); // XXX - what else?
175: }
176:
177:• if (headers == null ||
178:• ((POP3Store) (folder.getStore())).forgetTopHeaders) {
179: headers = new InternetHeaders(rawcontent);
180: hdrSize =
181: (int) ((SharedInputStream) rawcontent).getPosition();
182: } else {
183: /*
184: * Already have the headers, have to skip the headers
185: * in the content array and return the body.
186: *
187: * XXX - It seems that some mail servers return slightly
188: * different headers in the RETR results than were returned
189: * in the TOP results, so we can't depend on remembering
190: * the size of the headers from the TOP command and just
191: * skipping that many bytes. Instead, we have to process
192: * the content, skipping over the header until we come to
193: * the empty line that separates the header from the body.
194: */
195: for (; ; ) {
196: int len = 0; // number of bytes in this line
197: int c1;
198:• while ((c1 = rawcontent.read()) >= 0) {
199:• if (c1 == '\n') // end of line
200: break;
201:• else if (c1 == '\r') {
202: // got CR, is the next char LF?
203:• if (rawcontent.available() > 0) {
204: rawcontent.mark(1);
205:• if (rawcontent.read() != '\n')
206: rawcontent.reset();
207: }
208: break; // in any case, end of line
209: }
210:
211: // not CR, NL, or CRLF, count the byte
212: len++;
213: }
214: // here when end of line or out of data
215:
216: // if out of data, we're done
217:• if (rawcontent.available() == 0)
218: break;
219:
220: // if it was an empty line, we're done
221:• if (len == 0)
222: break;
223: }
224: hdrSize =
225: (int) ((SharedInputStream) rawcontent).getPosition();
226: }
227:
228: // skipped the header, the message is what's left
229: msgSize = rawcontent.available();
230:
231: rawData = new SoftReference<>(rawcontent);
232: }
233: }
234: } catch (EOFException eex) {
235: folder.close(false);
236: throw new FolderClosedException(folder, eex.toString());
237: } catch (IOException ex) {
238: throw new MessagingException("error fetching POP3 content", ex);
239: }
240:
241: /*
242: * We have a cached stream, but we need to return
243: * a fresh stream to read from the beginning and
244: * that can be safely closed.
245: */
246: rawcontent = ((SharedInputStream) rawcontent).newStream(
247:• skipHeader ? hdrSize : 0, -1);
248: return rawcontent;
249: }
250:
251: /**
252: * Produce the raw bytes of the content. The data is fetched using
253: * the POP3 RETR command.
254: *
255: * @see #contentStream
256: */
257: @Override
258: protected synchronized InputStream getContentStream()
259: throws MessagingException {
260:• if (contentStream != null)
261: return ((SharedInputStream) contentStream).newStream(0, -1);
262:
263: InputStream cstream = getRawStream(true);
264:
265: /*
266: * Keep a hard reference to the data if we're using a file
267: * cache or if the "mail.pop3.keepmessagecontent" prop is set.
268: */
269: TempFile cache = folder.getFileCache();
270:• if (cache != null ||
271:• ((POP3Store) (folder.getStore())).keepMessageContent)
272: contentStream = ((SharedInputStream) cstream).newStream(0, -1);
273: return cstream;
274: }
275:
276: /**
277: * Return the MIME format stream corresponding to this message part.
278: *
279: * @return the MIME format stream
280: * @since JavaMail 1.4.5
281: */
282: @Override
283: public InputStream getMimeStream() throws MessagingException {
284: return getRawStream(false);
285: }
286:
287: /**
288: * Invalidate the cache of content for this message object, causing
289: * it to be fetched again from the server the next time it is needed.
290: * If <code>invalidateHeaders</code> is true, invalidate the headers
291: * as well.
292: *
293: * @param invalidateHeaders invalidate the headers as well?
294: */
295: public synchronized void invalidate(boolean invalidateHeaders) {
296: content = null;
297: InputStream rstream = rawData.get();
298:• if (rstream != null) {
299: // note that if the content is in the file cache, it will be lost
300: // and fetched from the server if it's needed again
301: try {
302: rstream.close();
303: } catch (IOException ex) {
304: // ignore it
305: }
306: rawData = new SoftReference<>(null);
307: }
308:• if (contentStream != null) {
309: try {
310: contentStream.close();
311: } catch (IOException ex) {
312: // ignore it
313: }
314: contentStream = null;
315: }
316: msgSize = -1;
317:• if (invalidateHeaders) {
318: headers = null;
319: hdrSize = -1;
320: }
321: }
322:
323: /**
324: * Fetch the header of the message and the first <code>n</code> lines
325: * of the raw content of the message. The headers and data are
326: * available in the returned InputStream.
327: *
328: * @param n number of lines of content to fetch
329: * @return InputStream containing the message headers and n content lines
330: * @exception MessagingException for failures
331: */
332: public InputStream top(int n) throws MessagingException {
333: try {
334: synchronized (this) {
335: return folder.getProtocol().top(msgnum, n);
336: }
337: } catch (EOFException eex) {
338: folder.close(false);
339: throw new FolderClosedException(folder, eex.toString());
340: } catch (IOException ex) {
341: throw new MessagingException("error getting size", ex);
342: }
343: }
344:
345: /**
346: * Get all the headers for this header_name. Note that certain
347: * headers may be encoded as per RFC 2047 if they contain
348: * non US-ASCII characters and these should be decoded. <p>
349: *
350: * @param name name of header
351: * @return array of headers
352: * @exception MessagingException for failures
353: * @see jakarta.mail.internet.MimeUtility
354: */
355: @Override
356: public String[] getHeader(String name)
357: throws MessagingException {
358:• if (headers == null)
359: loadHeaders();
360: return headers.getHeader(name);
361: }
362:
363: /**
364: * Get all the headers for this header name, returned as a single
365: * String, with headers separated by the delimiter. If the
366: * delimiter is <code>null</code>, only the first header is
367: * returned.
368: *
369: * @param name the name of this header
370: * @param delimiter delimiter between returned headers
371: * @return the value fields for all headers with
372: * this name
373: * @exception MessagingException for failures
374: */
375: @Override
376: public String getHeader(String name, String delimiter)
377: throws MessagingException {
378:• if (headers == null)
379: loadHeaders();
380: return headers.getHeader(name, delimiter);
381: }
382:
383: /**
384: * Set the value for this header_name. Throws IllegalWriteException
385: * because POP3 messages are read-only.
386: *
387: * @param name header name
388: * @param value header value
389: * @exception IllegalWriteException because the underlying
390: * implementation does not support modification
391: * @exception IllegalStateException if this message is
392: * obtained from a READ_ONLY folder.
393: * @exception MessagingException for other failures
394: * @see jakarta.mail.internet.MimeUtility
395: */
396: @Override
397: public void setHeader(String name, String value)
398: throws MessagingException {
399: // XXX - should check for read-only folder?
400: throw new IllegalWriteException("POP3 messages are read-only");
401: }
402:
403: /**
404: * Add this value to the existing values for this header_name.
405: * Throws IllegalWriteException because POP3 messages are read-only.
406: *
407: * @param name header name
408: * @param value header value
409: * @exception IllegalWriteException because the underlying
410: * implementation does not support modification
411: * @exception IllegalStateException if this message is
412: * obtained from a READ_ONLY folder.
413: * @see jakarta.mail.internet.MimeUtility
414: */
415: @Override
416: public void addHeader(String name, String value)
417: throws MessagingException {
418: // XXX - should check for read-only folder?
419: throw new IllegalWriteException("POP3 messages are read-only");
420: }
421:
422: /**
423: * Remove all headers with this name.
424: * Throws IllegalWriteException because POP3 messages are read-only.
425: *
426: * @exception IllegalWriteException because the underlying
427: * implementation does not support modification
428: * @exception IllegalStateException if this message is
429: * obtained from a READ_ONLY folder.
430: */
431: @Override
432: public void removeHeader(String name)
433: throws MessagingException {
434: // XXX - should check for read-only folder?
435: throw new IllegalWriteException("POP3 messages are read-only");
436: }
437:
438: /**
439: * Return all the headers from this Message as an enumeration
440: * of Header objects. <p>
441: *
442: * Note that certain headers may be encoded as per RFC 2047
443: * if they contain non US-ASCII characters and these should
444: * be decoded. <p>
445: *
446: * @return array of header objects
447: * @exception MessagingException for failures
448: * @see jakarta.mail.internet.MimeUtility
449: */
450: @Override
451: public Enumeration<Header> getAllHeaders() throws MessagingException {
452:• if (headers == null)
453: loadHeaders();
454: return headers.getAllHeaders();
455: }
456:
457: /**
458: * Return matching headers from this Message as an Enumeration of
459: * Header objects.
460: *
461: * @exception MessagingException for failures
462: */
463: @Override
464: public Enumeration<Header> getMatchingHeaders(String[] names)
465: throws MessagingException {
466:• if (headers == null)
467: loadHeaders();
468: return headers.getMatchingHeaders(names);
469: }
470:
471: /**
472: * Return non-matching headers from this Message as an
473: * Enumeration of Header objects.
474: *
475: * @exception MessagingException for failures
476: */
477: @Override
478: public Enumeration<Header> getNonMatchingHeaders(String[] names)
479: throws MessagingException {
480:• if (headers == null)
481: loadHeaders();
482: return headers.getNonMatchingHeaders(names);
483: }
484:
485: /**
486: * Add a raw RFC822 header-line.
487: * Throws IllegalWriteException because POP3 messages are read-only.
488: *
489: * @exception IllegalWriteException because the underlying
490: * implementation does not support modification
491: * @exception IllegalStateException if this message is
492: * obtained from a READ_ONLY folder.
493: */
494: @Override
495: public void addHeaderLine(String line) throws MessagingException {
496: // XXX - should check for read-only folder?
497: throw new IllegalWriteException("POP3 messages are read-only");
498: }
499:
500: /**
501: * Get all header lines as an Enumeration of Strings. A Header
502: * line is a raw RFC822 header-line, containing both the "name"
503: * and "value" field.
504: *
505: * @exception MessagingException for failures
506: */
507: @Override
508: public Enumeration<String> getAllHeaderLines() throws MessagingException {
509:• if (headers == null)
510: loadHeaders();
511: return headers.getAllHeaderLines();
512: }
513:
514: /**
515: * Get matching header lines as an Enumeration of Strings.
516: * A Header line is a raw RFC822 header-line, containing both
517: * the "name" and "value" field.
518: *
519: * @exception MessagingException for failures
520: */
521: @Override
522: public Enumeration<String> getMatchingHeaderLines(String[] names)
523: throws MessagingException {
524:• if (headers == null)
525: loadHeaders();
526: return headers.getMatchingHeaderLines(names);
527: }
528:
529: /**
530: * Get non-matching header lines as an Enumeration of Strings.
531: * A Header line is a raw RFC822 header-line, containing both
532: * the "name" and "value" field.
533: *
534: * @exception MessagingException for failures
535: */
536: @Override
537: public Enumeration<String> getNonMatchingHeaderLines(String[] names)
538: throws MessagingException {
539:• if (headers == null)
540: loadHeaders();
541: return headers.getNonMatchingHeaderLines(names);
542: }
543:
544: /**
545: * POP3 message can't be changed. This method throws
546: * IllegalWriteException.
547: *
548: * @exception IllegalWriteException because the underlying
549: * implementation does not support modification
550: */
551: @Override
552: public void saveChanges() throws MessagingException {
553: // POP3 Messages are read-only
554: throw new IllegalWriteException("POP3 messages are read-only");
555: }
556:
557: /**
558: * Output the message as an RFC 822 format stream, without
559: * specified headers. If the property "mail.pop3.cachewriteto"
560: * is set to "true", and ignoreList is null, and the message hasn't
561: * already been cached as a side effect of other operations, the message
562: * content is cached before being written. Otherwise, the message is
563: * streamed directly to the output stream without being cached.
564: *
565: * @throws IOException if an error occurs writing to the stream
566: * or if an error is generated by the
567: * jakarta.activation layer.
568: * @throws MessagingException for other failures
569: * @see jakarta.activation.DataHandler#writeTo
570: */
571: @Override
572: public synchronized void writeTo(OutputStream os, String[] ignoreList)
573: throws IOException, MessagingException {
574: InputStream rawcontent = rawData.get();
575:• if (rawcontent == null && ignoreList == null &&
576:• !((POP3Store) (folder.getStore())).cacheWriteTo) {
577:• if (folder.logger.isLoggable(Level.FINE))
578: folder.logger.fine("streaming msg " + msgnum);
579:• if (!folder.getProtocol().retr(msgnum, os)) {
580: expunged = true;
581: throw new MessageRemovedException("can't retrieve message #" +
582: msgnum + " in POP3Message.writeTo"); // XXX - what else?
583: }
584:• } else if (rawcontent != null && ignoreList == null) {
585: // can just copy the cached data
586: InputStream in = ((SharedInputStream) rawcontent).newStream(0, -1);
587: try {
588: byte[] buf = new byte[16 * 1024];
589: int len;
590:• while ((len = in.read(buf)) > 0)
591: os.write(buf, 0, len);
592: } finally {
593: try {
594:• if (in != null)
595: in.close();
596: } catch (IOException ex) {
597: }
598: }
599: } else
600: super.writeTo(os, ignoreList);
601: }
602:
603: /**
604: * Load the headers for this message into the InternetHeaders object.
605: * The headers are fetched using the POP3 TOP command.
606: */
607: private void loadHeaders() throws MessagingException {
608:• assert !Thread.holdsLock(this);
609: try {
610: boolean fetchContent = false;
611: synchronized (this) {
612:• if (headers != null) // check again under lock
613: return;
614: InputStream hdrs = null;
615:• if (((POP3Store) (folder.getStore())).disableTop ||
616:• (hdrs = folder.getProtocol().top(msgnum, 0)) == null) {
617: // possibly because the TOP command isn't supported,
618: // load headers as a side effect of loading the entire
619: // content.
620: fetchContent = true;
621: } else {
622: try {
623: hdrSize = hdrs.available();
624: headers = new InternetHeaders(hdrs);
625: } finally {
626: hdrs.close();
627: }
628: }
629: }
630:
631: /*
632: * Outside the synchronization block...
633: *
634: * Do we need to fetch the entire mesage content in order to
635: * load the headers as a side effect? Yes, there's a race
636: * condition here - multiple threads could decide that the
637: * content needs to be fetched. Fortunately, they'll all
638: * synchronize in the getContentStream method and the content
639: * will only be loaded once.
640: */
641:• if (fetchContent) {
642: InputStream cs = null;
643: try {
644: cs = getContentStream();
645: } finally {
646:• if (cs != null)
647: cs.close();
648: }
649: }
650: } catch (EOFException eex) {
651: folder.close(false);
652: throw new FolderClosedException(folder, eex.toString());
653: } catch (IOException ex) {
654: throw new MessagingException("error loading POP3 headers", ex);
655: }
656: }
657: }