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