Skip to content

Package: POP3Folder

POP3Folder

nameinstructionbranchcomplexitylinemethod
POP3Folder(POP3Store, String)
M: 43 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 12 C: 0
0%
M: 1 C: 0
0%
appendMessages(Message[])
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%
checkClosed()
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%
checkOpen()
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%
checkReadable()
M: 17 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
close(boolean)
M: 114 C: 0
0%
M: 24 C: 0
0%
M: 13 C: 0
0%
M: 27 C: 0
0%
M: 1 C: 0
0%
create(int)
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
createMessage(Folder, int)
M: 37 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%
delete(boolean)
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%
exists()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
expunge()
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%
fetch(Message[], FetchProfile)
M: 98 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 26 C: 0
0%
M: 1 C: 0
0%
finalize()
M: 21 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
getFileCache()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getFolder(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%
getFullName()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getMessage(int)
M: 25 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
getMessageCount()
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getName()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getParent()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getPermanentFlags()
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%
getProtocol()
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getSeparator()
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getSize()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getSizes()
M: 67 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 24 C: 0
0%
M: 1 C: 0
0%
getType()
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getUID(Message)
M: 51 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
hasNewMessages()
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
isOpen()
M: 25 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
list(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%
listCommand()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
notifyMessageChangedListeners(int, Message)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
open(int)
M: 92 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 27 C: 0
0%
M: 1 C: 0
0%
renameTo(Folder)
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%

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.AuthenticationFailedException;
20: import jakarta.mail.FetchProfile;
21: import jakarta.mail.Flags;
22: import jakarta.mail.Folder;
23: import jakarta.mail.FolderClosedException;
24: import jakarta.mail.FolderNotFoundException;
25: import jakarta.mail.Message;
26: import jakarta.mail.MessageRemovedException;
27: import jakarta.mail.MessagingException;
28: import jakarta.mail.MethodNotSupportedException;
29: import jakarta.mail.UIDFolder;
30: import jakarta.mail.event.ConnectionEvent;
31: import org.eclipse.angus.mail.util.LineInputStream;
32: import org.eclipse.angus.mail.util.MailLogger;
33:
34: import java.io.EOFException;
35: import java.io.IOException;
36: import java.io.InputStream;
37: import java.lang.reflect.Constructor;
38: import java.util.StringTokenizer;
39: import java.util.logging.Level;
40:
41: /**
42: * A POP3 Folder (can only be "INBOX").
43: *
44: * See the <a href="package-summary.html">org.eclipse.angus.mail.pop3</a> package
45: * documentation for further information on the POP3 protocol provider. <p>
46: *
47: * @author Bill Shannon
48: * @author John Mani (ported to the jakarta.mail APIs)
49: */
50: public class POP3Folder extends Folder {
51:
52: private String name;
53: private POP3Store store;
54: private volatile Protocol port;
55: private int total;
56: private int size;
57: private boolean exists = false;
58: private volatile boolean opened = false;
59: private POP3Message[] message_cache;
60: private boolean doneUidl = false;
61: private volatile TempFile fileCache = null;
62: private boolean forceClose;
63:
64: MailLogger logger; // package private, for POP3Message
65:
66: protected POP3Folder(POP3Store store, String name) {
67: super(store);
68: this.name = name;
69: this.store = store;
70:• if (name.equalsIgnoreCase("INBOX"))
71: exists = true;
72: logger = new MailLogger(this.getClass(), "DEBUG POP3",
73: store.getSession().getDebug(), store.getSession().getDebugOut());
74: }
75:
76: @Override
77: public String getName() {
78: return name;
79: }
80:
81: @Override
82: public String getFullName() {
83: return name;
84: }
85:
86: @Override
87: public Folder getParent() {
88: return new DefaultFolder(store);
89: }
90:
91: /**
92: * Always true for the folder "INBOX", always false for
93: * any other name.
94: *
95: * @return true for INBOX, false otherwise
96: */
97: @Override
98: public boolean exists() {
99: return exists;
100: }
101:
102: /**
103: * Always throws <code>MessagingException</code> because no POP3 folders
104: * can contain subfolders.
105: *
106: * @exception MessagingException always
107: */
108: @Override
109: public Folder[] list(String pattern) throws MessagingException {
110: throw new MessagingException("not a directory");
111: }
112:
113: /**
114: * Always returns a NUL character because POP3 doesn't support a hierarchy.
115: *
116: * @return NUL
117: */
118: @Override
119: public char getSeparator() {
120: return '\0';
121: }
122:
123: /**
124: * Always returns Folder.HOLDS_MESSAGES.
125: *
126: * @return Folder.HOLDS_MESSAGES
127: */
128: @Override
129: public int getType() {
130: return HOLDS_MESSAGES;
131: }
132:
133: /**
134: * Always returns <code>false</code> the POP3 protocol doesn't
135: * support creating folders.
136: *
137: * @return false
138: */
139: @Override
140: public boolean create(int type) throws MessagingException {
141: return false;
142: }
143:
144: /**
145: * Always returns <code>false</code> the POP3 protocol provides
146: * no way to determine when a new message arrives.
147: *
148: * @return false
149: */
150: @Override
151: public boolean hasNewMessages() throws MessagingException {
152: return false; // no way to know
153: }
154:
155: /**
156: * Always throws <code>MessagingException</code> because no POP3 folders
157: * can contain subfolders.
158: *
159: * @exception MessagingException always
160: */
161: @Override
162: public Folder getFolder(String name) throws MessagingException {
163: throw new MessagingException("not a directory");
164: }
165:
166: /**
167: * Always throws <code>MethodNotSupportedException</code>
168: * because the POP3 protocol doesn't allow the INBOX to
169: * be deleted.
170: *
171: * @exception MethodNotSupportedException always
172: */
173: @Override
174: public boolean delete(boolean recurse) throws MessagingException {
175: throw new MethodNotSupportedException("delete");
176: }
177:
178: /**
179: * Always throws <code>MethodNotSupportedException</code>
180: * because the POP3 protocol doesn't support multiple folders.
181: *
182: * @exception MethodNotSupportedException always
183: */
184: @Override
185: public boolean renameTo(Folder f) throws MessagingException {
186: throw new MethodNotSupportedException("renameTo");
187: }
188:
189: /**
190: * Throws <code>FolderNotFoundException</code> unless this
191: * folder is named "INBOX".
192: *
193: * @exception FolderNotFoundException if not INBOX
194: * @exception AuthenticationFailedException authentication failures
195: * @exception MessagingException other open failures
196: */
197: @Override
198: public synchronized void open(int mode) throws MessagingException {
199: checkClosed();
200:• if (!exists)
201: throw new FolderNotFoundException(this, "folder is not INBOX");
202:
203: try {
204: port = store.getPort(this);
205: Status s = port.stat();
206: total = s.total;
207: size = s.size;
208: this.mode = mode;
209:• if (store.useFileCache) {
210: try {
211: fileCache = new TempFile(store.fileCacheDir);
212: } catch (IOException ex) {
213: logger.log(Level.FINE, "failed to create file cache", ex);
214: throw ex; // caught below
215: }
216: }
217: opened = true;
218: } catch (IOException ioex) {
219: try {
220:• if (port != null)
221: port.quit();
222: } catch (IOException ioex2) {
223: // ignore
224: } finally {
225: port = null;
226: store.closePort(this);
227: }
228: throw new MessagingException("Open failed", ioex);
229: }
230:
231: // Create the message cache array of appropriate size
232: message_cache = new POP3Message[total];
233: doneUidl = false;
234:
235: notifyConnectionListeners(ConnectionEvent.OPENED);
236: }
237:
238: @Override
239: public synchronized void close(boolean expunge) throws MessagingException {
240: checkOpen();
241:
242: try {
243: /*
244: * Some POP3 servers will mark messages for deletion when
245: * they're read. To prevent such messages from being
246: * deleted before the client deletes them, you can set
247: * the mail.pop3.rsetbeforequit property to true. This
248: * causes us to issue a POP3 RSET command to clear all
249: * the "marked for deletion" flags. We can then explicitly
250: * delete messages as desired.
251: */
252:• if (store.rsetBeforeQuit && !forceClose)
253: port.rset();
254: POP3Message m;
255:• if (expunge && mode == READ_WRITE && !forceClose) {
256: // find all messages marked deleted and issue DELE commands
257:• for (int i = 0; i < message_cache.length; i++) {
258:• if ((m = message_cache[i]) != null) {
259:• if (m.isSet(Flags.Flag.DELETED))
260: try {
261: port.dele(i + 1);
262: } catch (IOException ioex) {
263: throw new MessagingException(
264: "Exception deleting messages during close",
265: ioex);
266: }
267: }
268: }
269: }
270:
271: /*
272: * Flush and free all cached data for the messages.
273: */
274:• for (int i = 0; i < message_cache.length; i++) {
275:• if ((m = message_cache[i]) != null)
276: m.invalidate(true);
277: }
278:
279:• if (forceClose)
280: port.close();
281: else
282: port.quit();
283: } catch (IOException ex) {
284: // do nothing
285: } finally {
286: port = null;
287: store.closePort(this);
288: message_cache = null;
289: opened = false;
290: notifyConnectionListeners(ConnectionEvent.CLOSED);
291:• if (fileCache != null) {
292: fileCache.close();
293: fileCache = null;
294: }
295: }
296: }
297:
298: @Override
299: public synchronized boolean isOpen() {
300:• if (!opened)
301: return false;
302: try {
303:• if (!port.noop())
304: throw new IOException("NOOP failed");
305: } catch (IOException ioex) {
306: try {
307: close(false);
308: } catch (MessagingException mex) {
309: // ignore it
310: }
311: return false;
312: }
313: return true;
314: }
315:
316: /**
317: * Always returns an empty <code>Flags</code> object because
318: * the POP3 protocol doesn't support any permanent flags.
319: *
320: * @return empty Flags object
321: */
322: @Override
323: public Flags getPermanentFlags() {
324: return new Flags(); // empty flags object
325: }
326:
327: /**
328: * Will not change while the folder is open because the POP3
329: * protocol doesn't support notification of new messages
330: * arriving in open folders.
331: */
332: @Override
333: public synchronized int getMessageCount() throws MessagingException {
334:• if (!opened)
335: return -1;
336: checkReadable();
337: return total;
338: }
339:
340: @Override
341: public synchronized Message getMessage(int msgno)
342: throws MessagingException {
343: checkOpen();
344:
345: POP3Message m;
346:
347: // Assuming that msgno is <= total
348:• if ((m = message_cache[msgno - 1]) == null) {
349: m = createMessage(this, msgno);
350: message_cache[msgno - 1] = m;
351: }
352: return m;
353: }
354:
355: protected POP3Message createMessage(Folder f, int msgno)
356: throws MessagingException {
357: POP3Message m = null;
358: Constructor<?> cons = store.messageConstructor;
359:• if (cons != null) {
360: try {
361: Object[] o = {this, Integer.valueOf(msgno)};
362: m = (POP3Message) cons.newInstance(o);
363: } catch (Exception ex) {
364: // ignore
365: }
366: }
367:• if (m == null)
368: m = new POP3Message(this, msgno);
369: return m;
370: }
371:
372: /**
373: * Always throws <code>MethodNotSupportedException</code>
374: * because the POP3 protocol doesn't support appending messages.
375: *
376: * @exception MethodNotSupportedException always
377: */
378: @Override
379: public void appendMessages(Message[] msgs) throws MessagingException {
380: throw new MethodNotSupportedException("Append not supported");
381: }
382:
383: /**
384: * Always throws <code>MethodNotSupportedException</code>
385: * because the POP3 protocol doesn't support expunging messages
386: * without closing the folder; call the {@link #close close} method
387: * with the <code>expunge</code> argument set to <code>true</code>
388: * instead.
389: *
390: * @exception MethodNotSupportedException always
391: */
392: @Override
393: public Message[] expunge() throws MessagingException {
394: throw new MethodNotSupportedException("Expunge not supported");
395: }
396:
397: /**
398: * Prefetch information about POP3 messages.
399: * If the FetchProfile contains <code>UIDFolder.FetchProfileItem.UID</code>,
400: * POP3 UIDs for all messages in the folder are fetched using the POP3
401: * UIDL command.
402: * If the FetchProfile contains <code>FetchProfile.Item.ENVELOPE</code>,
403: * the headers and size of all messages are fetched using the POP3 TOP
404: * and LIST commands.
405: */
406: @Override
407: public synchronized void fetch(Message[] msgs, FetchProfile fp)
408: throws MessagingException {
409: checkReadable();
410:• if (!doneUidl && store.supportsUidl &&
411:• fp.contains(UIDFolder.FetchProfileItem.UID)) {
412: /*
413: * Since the POP3 protocol only lets us fetch the UID
414: * for a single message or for all messages, we go ahead
415: * and fetch UIDs for all messages here, ignoring the msgs
416: * parameter. We could be more intelligent and base this
417: * decision on the number of messages fetched, or the
418: * percentage of the total number of messages fetched.
419: */
420: String[] uids = new String[message_cache.length];
421: try {
422:• if (!port.uidl(uids))
423: return;
424: } catch (EOFException eex) {
425: close(false);
426: throw new FolderClosedException(this, eex.toString());
427: } catch (IOException ex) {
428: throw new MessagingException("error getting UIDL", ex);
429: }
430:• for (int i = 0; i < uids.length; i++) {
431:• if (uids[i] == null)
432: continue;
433: POP3Message m = (POP3Message) getMessage(i + 1);
434: m.uid = uids[i];
435: }
436: doneUidl = true; // only do this once
437: }
438:• if (fp.contains(FetchProfile.Item.ENVELOPE)) {
439:• for (int i = 0; i < msgs.length; i++) {
440: try {
441: POP3Message msg = (POP3Message) msgs[i];
442: // fetch headers
443: msg.getHeader("");
444: // fetch message size
445: msg.getSize();
446: } catch (MessageRemovedException mex) {
447: // should never happen, but ignore it if it does
448: }
449: }
450: }
451: }
452:
453: /**
454: * Return the unique ID string for this message, or null if
455: * not available. Uses the POP3 UIDL command.
456: *
457: * @return unique ID string
458: * @param msg the message
459: * @exception MessagingException for failures
460: */
461: public synchronized String getUID(Message msg) throws MessagingException {
462: checkOpen();
463:• if (!(msg instanceof POP3Message))
464: throw new MessagingException("message is not a POP3Message");
465: POP3Message m = (POP3Message) msg;
466: try {
467:• if (!store.supportsUidl)
468: return null;
469:• if (m.uid == POP3Message.UNKNOWN)
470: m.uid = port.uidl(m.getMessageNumber());
471: return m.uid;
472: } catch (EOFException eex) {
473: close(false);
474: throw new FolderClosedException(this, eex.toString());
475: } catch (IOException ex) {
476: throw new MessagingException("error getting UIDL", ex);
477: }
478: }
479:
480: /**
481: * Return the size of this folder, as was returned by the POP3 STAT
482: * command when this folder was opened.
483: *
484: * @return folder size
485: * @exception IllegalStateException if the folder isn't open
486: * @exception MessagingException for other failures
487: */
488: public synchronized int getSize() throws MessagingException {
489: checkOpen();
490: return size;
491: }
492:
493: /**
494: * Return the sizes of all messages in this folder, as returned
495: * by the POP3 LIST command. Each entry in the array corresponds
496: * to a message; entry <i>i</i> corresponds to message number <i>i+1</i>.
497: *
498: * @return array of message sizes
499: * @exception IllegalStateException if the folder isn't open
500: * @exception MessagingException for other failures
501: * @since JavaMail 1.3.3
502: */
503: public synchronized int[] getSizes() throws MessagingException {
504: checkOpen();
505: int[] sizes = new int[total];
506: InputStream is = null;
507: LineInputStream lis = null;
508: try {
509: is = port.list();
510: lis = new LineInputStream(is);
511: String line;
512:• while ((line = lis.readLine()) != null) {
513: try {
514: StringTokenizer st = new StringTokenizer(line);
515: int msgnum = Integer.parseInt(st.nextToken());
516: int size = Integer.parseInt(st.nextToken());
517:• if (msgnum > 0 && msgnum <= total)
518: sizes[msgnum - 1] = size;
519: } catch (RuntimeException e) {
520: }
521: }
522: } catch (IOException ex) {
523: // ignore it?
524: } finally {
525: try {
526:• if (lis != null)
527: lis.close();
528: } catch (IOException cex) {
529: }
530: try {
531:• if (is != null)
532: is.close();
533: } catch (IOException cex) {
534: }
535: }
536: return sizes;
537: }
538:
539: /**
540: * Return the raw results of the POP3 LIST command with no arguments.
541: *
542: * @return InputStream containing results
543: * @exception IllegalStateException if the folder isn't open
544: * @exception IOException for I/O errors talking to the server
545: * @exception MessagingException for other errors
546: * @since JavaMail 1.3.3
547: */
548: public synchronized InputStream listCommand()
549: throws MessagingException, IOException {
550: checkOpen();
551: return port.list();
552: }
553:
554: /**
555: * Close the folder when we're finalized.
556: */
557: @Override
558: protected void finalize() throws Throwable {
559:• forceClose = !store.finalizeCleanClose;
560: try {
561:• if (opened)
562: close(false);
563: } finally {
564: super.finalize();
565: forceClose = false;
566: }
567: }
568:
569: /* Ensure the folder is open */
570: private void checkOpen() throws IllegalStateException {
571:• if (!opened)
572: throw new IllegalStateException("Folder is not Open");
573: }
574:
575: /* Ensure the folder is not open */
576: private void checkClosed() throws IllegalStateException {
577:• if (opened)
578: throw new IllegalStateException("Folder is Open");
579: }
580:
581: /* Ensure the folder is open & readable */
582: private void checkReadable() throws IllegalStateException {
583:• if (!opened || (mode != READ_ONLY && mode != READ_WRITE))
584: throw new IllegalStateException("Folder is not Readable");
585: }
586:
587: /* Ensure the folder is open & writable */
588: /*
589: private void checkWritable() throws IllegalStateException {
590:         if (!opened || mode != READ_WRITE)
591:          throw new IllegalStateException("Folder is not Writable");
592: }
593: */
594:
595: /**
596: * Centralize access to the Protocol object by POP3Message
597: * objects so that they will fail appropriately when the folder
598: * is closed.
599: */
600: Protocol getProtocol() throws MessagingException {
601: Protocol p = port; // read it before close() can set it to null
602: checkOpen();
603: // close() might happen here
604: return p;
605: }
606:
607: /*
608: * Only here to make accessible to POP3Message.
609: */
610: @Override
611: protected void notifyMessageChangedListeners(int type, Message m) {
612: super.notifyMessageChangedListeners(type, m);
613: }
614:
615: /**
616: * Used by POP3Message.
617: */
618: TempFile getFileCache() {
619: return fileCache;
620: }
621: }