1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3  *
4  * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
5  *
6  * The contents of this file are subject to the terms of either the GNU
7  * General Public License Version 2 only ("GPL") or the Common Development
8  * and Distribution License("CDDL") (collectively, the "License").  You
9  * may not use this file except in compliance with the License.  You can
10  * obtain a copy of the License at
11  * https://oss.oracle.com/licenses/CDDL+GPL-1.1
12  * or LICENSE.txt.  See the License for the specific
13  * language governing permissions and limitations under the License.
14  *
15  * When distributing the software, include this License Header Notice in each
16  * file and include the License file at LICENSE.txt.
17  *
18  * GPL Classpath Exception:
19  * Oracle designates this particular file as subject to the "Classpath"
20  * exception as provided by Oracle in the GPL Version 2 section of the License
21  * file that accompanied this code.
22  *
23  * Modifications:
24  * If applicable, add the following below the License Header, with the fields
25  * enclosed by brackets [] replaced by your own identifying information:
26  * "Portions Copyright [year] [name of copyright owner]"
27  *
28  * Contributor(s):
29  * If you wish your version of this file to be governed by only the CDDL or
30  * only the GPL Version 2, indicate your decision by adding "[Contributor]
31  * elects to include this software in this distribution under the [CDDL or GPL
32  * Version 2] license."  If you don't indicate a single choice of license, a
33  * recipient has the option to distribute your version of this file under
34  * either the CDDL, the GPL Version 2 or to extend the choice of license to
35  * its licensees as provided above.  However, if you add GPL Version 2 code
36  * and therefore, elected the GPL Version 2 license, then the option applies
37  * only if the new code is made subject to such option by the copyright
38  * holder.
39  */
40 
41 package javax.mail;
42 
43 import java.lang.*;
44 import java.util.ArrayList;
45 import java.util.EventListener;
46 import java.util.List;
47 import java.util.Vector;
48 import java.util.concurrent.Executor;
49 import javax.mail.search.SearchTerm;
50 import javax.mail.event.*;
51 
52 /**
53  * Folder is an abstract class that represents a folder for mail
54  * messages. Subclasses implement protocol specific Folders.<p>
55  *
56  * Folders can contain Messages, other Folders or both, thus providing
57  * a tree-like hierarchy rooted at the Store's default folder. (Note
58  * that some Folder implementations may not allow both Messages and
59  * other Folders in the same Folder).<p>
60  *
61  * The interpretation of folder names is implementation dependent.
62  * The different levels of hierarchy in a folder's full name
63  * are separated from each other by the hierarchy delimiter
64  * character.<p>
65  *
66  * The case-insensitive full folder name (that is, the full name
67  * relative to the default folder for a Store) <strong>INBOX</strong>
68  * is reserved to mean the "primary folder for this user on this
69  * server".  Not all Stores will provide an INBOX folder, and not
70  * all users will have an INBOX folder at all times.  The name
71  * <strong>INBOX</strong> is reserved to refer to this folder,
72  * when it exists, in Stores that provide it. <p>
73  *
74  * A Folder object obtained from a Store need not actually exist
75  * in the backend store. The <code>exists</code> method tests whether
76  * the folder exists or not. The <code>create</code> method
77  * creates a Folder. <p>
78  *
79  * A Folder is initially in the closed state. Certain methods are valid
80  * in this state; the documentation for those methods note this.  A
81  * Folder is opened by calling its 'open' method. All Folder methods,
82  * except <code>open</code>, <code>delete</code> and
83  * <code>renameTo</code>, are valid in this state. <p>
84  *
85  * The only way to get a Folder is by invoking the
86  * <code>getFolder</code> method on Store, Folder, or Session, or by invoking
87  * the <code>list</code> or <code>listSubscribed</code> methods
88  * on Folder. Folder objects returned by the above methods are not
89  * cached by the Store. Thus, invoking the <code>getFolder</code> method
90  * with the same folder name multiple times will return distinct Folder
91  * objects.  Likewise for the <code>list</code> and <code>listSubscribed</code>
92  * methods. <p>
93  *
94  * The Message objects within the Folder are cached by the Folder.
95  * Thus, invoking <code>getMessage(msgno)</code> on the same message number
96  * multiple times will return the same Message object, until an
97  * expunge is done on this Folder. <p>
98  *
99  * Message objects from a Folder are only valid while a Folder is open
100  * and should not be accessed after the Folder is closed, even if the
101  * Folder is subsequently reopened.  Instead, new Message objects must
102  * be fetched from the Folder after the Folder is reopened. <p>
103  *
104  * Note that a Message's message number can change within a
105  * session if the containing Folder is expunged using the expunge
106  * method.  Clients that use message numbers as references to messages
107  * should be aware of this and should be prepared to deal with this
108  * situation (probably by flushing out existing message number references
109  * and reloading them). Because of this complexity, it is better for
110  * clients to use Message objects as references to messages, rather than
111  * message numbers. Expunged Message objects still have to be
112  * pruned, but other Message objects in that folder are not affected by the
113  * expunge.
114  *
115  * @author John Mani
116  * @author Bill Shannon
117  */
118 
119 public abstract class Folder implements AutoCloseable {
120 
121     /**
122      * The parent store.
123      */
124     protected Store store;
125 
126     /**
127      * The open mode of this folder.  The open mode is
128      * <code>Folder.READ_ONLY</code>, <code>Folder.READ_WRITE</code>,
129      * or -1 if not known.
130      * @since	JavaMail 1.1
131      */
132     protected int mode = -1;
133 
134     /*
135      * The queue of events to be delivered.
136      */
137     private final EventQueue q;
138 
139     /**
140      * Constructor that takes a Store object.
141      *
142      * @param store the Store that holds this folder
143      */
Folder(Store store)144     protected Folder(Store store) {
145 	this.store = store;
146 
147 	// create or choose the appropriate event queue
148 	Session session = store.getSession();
149 	String scope =
150 	    session.getProperties().getProperty("mail.event.scope", "folder");
151 	Executor executor =
152 		(Executor)session.getProperties().get("mail.event.executor");
153 	if (scope.equalsIgnoreCase("application"))
154 	    q = EventQueue.getApplicationEventQueue(executor);
155 	else if (scope.equalsIgnoreCase("session"))
156 	    q = session.getEventQueue();
157 	else if (scope.equalsIgnoreCase("store"))
158 	    q = store.getEventQueue();
159 	else // if (scope.equalsIgnoreCase("folder"))
160 	    q = new EventQueue(executor);
161     }
162 
163     /**
164      * Returns the name of this Folder. <p>
165      *
166      * This method can be invoked on a closed Folder.
167      *
168      * @return		name of the Folder
169      */
getName()170     public abstract String getName();
171 
172     /**
173      * Returns the full name of this Folder. If the folder resides under
174      * the root hierarchy of this Store, the returned name is relative
175      * to the root. Otherwise an absolute name, starting with the
176      * hierarchy delimiter, is returned. <p>
177      *
178      * This method can be invoked on a closed Folder.
179      *
180      * @return		full name of the Folder
181      */
getFullName()182     public abstract String getFullName();
183 
184     /**
185      * Return a URLName representing this folder.  The returned URLName
186      * does <em>not</em> include the password used to access the store.
187      *
188      * @return	the URLName representing this folder
189      * @exception	MessagingException for failures
190      * @see	URLName
191      * @since	JavaMail 1.1
192      */
getURLName()193     public URLName getURLName() throws MessagingException {
194 	URLName storeURL = getStore().getURLName();
195 	String fullname = getFullName();
196 	StringBuilder encodedName = new StringBuilder();
197 
198 	if (fullname != null) {
199 	    /*
200 	    // We need to encode each of the folder's names.
201 	    char separator = getSeparator();
202 	    StringTokenizer tok = new StringTokenizer(
203 		fullname, new Character(separator).toString(), true);
204 
205 	    while (tok.hasMoreTokens()) {
206 		String s = tok.nextToken();
207 		if (s.charAt(0) == separator)
208 		    encodedName.append(separator);
209 		else
210 		    // XXX - should encode, but since there's no decoder...
211 		    //encodedName.append(java.net.URLEncoder.encode(s));
212 		    encodedName.append(s);
213 	    }
214 	    */
215 	    // append the whole thing, until we can encode
216 	    encodedName.append(fullname);
217 	}
218 
219 	/*
220 	 * Sure would be convenient if URLName had a
221 	 * constructor that took a base URLName.
222 	 */
223 	return new URLName(storeURL.getProtocol(), storeURL.getHost(),
224 			    storeURL.getPort(), encodedName.toString(),
225 			    storeURL.getUsername(),
226 			    null /* no password */);
227     }
228 
229     /**
230      * Returns the Store that owns this Folder object.
231      * This method can be invoked on a closed Folder.
232      *
233      * @return 		the Store
234      */
getStore()235     public Store getStore() {
236 	return store;
237     }
238 
239     /**
240      * Returns the parent folder of this folder.
241      * This method can be invoked on a closed Folder. If this folder
242      * is the top of a folder hierarchy, this method returns null. <p>
243      *
244      * Note that since Folder objects are not cached, invoking this method
245      * returns a new distinct Folder object.
246      *
247      * @return		Parent folder
248      * @exception	MessagingException for failures
249      */
getParent()250     public abstract Folder getParent() throws MessagingException;
251 
252     /**
253      * Tests if this folder physically exists on the Store.
254      * This method can be invoked on a closed Folder.
255      *
256      * @return true if the folder exists, otherwise false
257      * @see    #create
258      * @exception	MessagingException typically if the connection
259      *			to the server is lost.
260      */
exists()261     public abstract boolean exists() throws MessagingException;
262 
263     /**
264      * Returns a list of Folders belonging to this Folder's namespace
265      * that match the specified pattern. Patterns may contain the wildcard
266      * characters <code>"%"</code>, which matches any character except hierarchy
267      * delimiters, and <code>"*"</code>, which matches any character. <p>
268      *
269      * As an example, given the folder hierarchy: <pre>
270      *    Personal/
271      *       Finance/
272      *          Stocks
273      *          Bonus
274      *          StockOptions
275      *       Jokes
276      * </pre>
277      * <code>list("*")</code> on "Personal" will return the whole
278      * hierarchy. <br>
279      * <code>list("%")</code> on "Personal" will return "Finance" and
280      * "Jokes". <br>
281      * <code>list("Jokes")</code> on "Personal" will return "Jokes".<br>
282      * <code>list("Stock*")</code> on "Finance" will return "Stocks"
283      * and "StockOptions". <p>
284      *
285      * Folder objects are not cached by the Store, so invoking this
286      * method on the same pattern multiple times will return that many
287      * distinct Folder objects. <p>
288      *
289      * This method can be invoked on a closed Folder.
290      *
291      * @param pattern	the match pattern
292      * @return		array of matching Folder objects. An empty
293      *			array is returned if no matching Folders exist.
294      * @see 		#listSubscribed
295      * @exception 	FolderNotFoundException if this folder does
296      *			not exist.
297      * @exception 	MessagingException for other failures
298      */
list(String pattern)299     public abstract Folder[] list(String pattern) throws MessagingException;
300 
301     /**
302      * Returns a list of subscribed Folders belonging to this Folder's
303      * namespace that match the specified pattern. If the folder does
304      * not support subscription, this method should resolve to
305      * <code>list</code>.
306      * (The default implementation provided here, does just this).
307      * The pattern can contain wildcards as for <code>list</code>. <p>
308      *
309      * Note that, at a given level of the folder hierarchy, a particular
310      * folder may not be subscribed, but folders underneath that folder
311      * in the folder hierarchy may be subscribed.  In order to allow
312      * walking the folder hierarchy, such unsubscribed folders may be
313      * returned, indicating that a folder lower in the hierarchy is
314      * subscribed.  The <code>isSubscribed</code> method on a folder will
315      * tell whether any particular folder is actually subscribed. <p>
316      *
317      * Folder objects are not cached by the Store, so invoking this
318      * method on the same pattern multiple times will return that many
319      * distinct Folder objects. <p>
320      *
321      * This method can be invoked on a closed Folder.
322      *
323      * @param pattern	the match pattern
324      * @return		array of matching subscribed Folder objects. An
325      *			empty array is returned if no matching
326      *			subscribed folders exist.
327      * @see 		#list
328      * @exception 	FolderNotFoundException if this folder does
329      *			not exist.
330      * @exception 	MessagingException for other failures
331      */
listSubscribed(String pattern)332     public Folder[] listSubscribed(String pattern) throws MessagingException {
333 	return list(pattern);
334     }
335 
336     /**
337      * Convenience method that returns the list of folders under this
338      * Folder. This method just calls the <code>list(String pattern)</code>
339      * method with <code>"%"</code> as the match pattern. This method can
340      * be invoked on a closed Folder.
341      *
342      * @return		array of Folder objects under this Folder. An
343      *			empty array is returned if no subfolders exist.
344      * @see		#list
345      * @exception 	FolderNotFoundException if this folder does
346      *			not exist.
347      * @exception 	MessagingException for other failures
348      */
349 
list()350     public Folder[] list() throws MessagingException {
351 	return list("%");
352     }
353 
354     /**
355      * Convenience method that returns the list of subscribed folders
356      * under this Folder. This method just calls the
357      * <code>listSubscribed(String pattern)</code> method with <code>"%"</code>
358      * as the match pattern. This method can be invoked on a closed Folder.
359      *
360      * @return		array of subscribed Folder objects under this
361      *			Folder. An empty array is returned if no subscribed
362      *			subfolders exist.
363      * @see		#listSubscribed
364      * @exception 	FolderNotFoundException if this folder does
365      *			not exist.
366      * @exception 	MessagingException for other failures
367      */
listSubscribed()368     public Folder[] listSubscribed() throws MessagingException {
369 	return listSubscribed("%");
370     }
371 
372     /**
373      * Return the delimiter character that separates this Folder's pathname
374      * from the names of immediate subfolders. This method can be invoked
375      * on a closed Folder.
376      *
377      * @exception 	FolderNotFoundException if the implementation
378      *			requires the folder to exist, but it does not
379      * @return          Hierarchy separator character
380      */
getSeparator()381     public abstract char getSeparator() throws MessagingException;
382 
383     /**
384      * This folder can contain messages
385      */
386     public final static int HOLDS_MESSAGES = 0x01;
387 
388     /**
389      * This folder can contain other folders
390      */
391     public final static int HOLDS_FOLDERS  = 0x02;
392 
393     /**
394      * Returns the type of this Folder, that is, whether this folder can hold
395      * messages or subfolders or both. The returned value is an integer
396      * bitfield with the appropriate bits set. This method can be invoked
397      * on a closed folder.
398      *
399      * @return 		integer with appropriate bits set
400      * @exception 	FolderNotFoundException if this folder does
401      *			not exist.
402      * @see 		#HOLDS_FOLDERS
403      * @see		#HOLDS_MESSAGES
404      */
getType()405     public abstract int getType() throws MessagingException;
406 
407     /**
408      * Create this folder on the Store. When this folder is created, any
409      * folders in its path that do not exist are also created. <p>
410      *
411      * If the creation is successful, a CREATED FolderEvent is delivered
412      * to any FolderListeners registered on this Folder and this Store.
413      *
414      * @param  type	The type of this folder.
415      *
416      * @return		true if the creation succeeds, else false.
417      * @exception 	MessagingException for failures
418      * @see 		#HOLDS_FOLDERS
419      * @see		#HOLDS_MESSAGES
420      * @see		javax.mail.event.FolderEvent
421      */
create(int type)422     public abstract boolean create(int type) throws MessagingException;
423 
424     /**
425      * Returns true if this Folder is subscribed. <p>
426      *
427      * This method can be invoked on a closed Folder. <p>
428      *
429      * The default implementation provided here just returns true.
430      *
431      * @return		true if this Folder is subscribed
432      */
isSubscribed()433     public boolean isSubscribed() {
434 	return true;
435     }
436 
437     /**
438      * Subscribe or unsubscribe this Folder. Not all Stores support
439      * subscription. <p>
440      *
441      * This method can be invoked on a closed Folder. <p>
442      *
443      * The implementation provided here just throws the
444      * MethodNotSupportedException.
445      *
446      * @param subscribe	true to subscribe, false to unsubscribe
447      * @exception 	FolderNotFoundException if this folder does
448      *			not exist.
449      * @exception 	MethodNotSupportedException if this store
450      *			does not support subscription
451      * @exception 	MessagingException for other failures
452      */
setSubscribed(boolean subscribe)453     public void setSubscribed(boolean subscribe)
454 			throws MessagingException {
455 	throw new MethodNotSupportedException();
456     }
457 
458     /**
459      * Returns true if this Folder has new messages since the last time
460      * this indication was reset.  When this indication is set or reset
461      * depends on the Folder implementation (and in the case of IMAP,
462      * depends on the server).  This method can be used to implement
463      * a lightweight "check for new mail" operation on a Folder without
464      * opening it.  (For example, a thread that monitors a mailbox and
465      * flags when it has new mail.)  This method should indicate whether
466      * any messages in the Folder have the <code>RECENT</code> flag set. <p>
467      *
468      * Note that this is not an incremental check for new mail, i.e.,
469      * it cannot be used to determine whether any new messages have
470      * arrived since the last time this method was invoked. To
471      * implement incremental checks, the Folder needs to be opened. <p>
472      *
473      * This method can be invoked on a closed Folder that can contain
474      * Messages.
475      *
476      * @return		true if the Store has new Messages
477      * @exception	FolderNotFoundException if this folder does
478      *			not exist.
479      * @exception 	MessagingException for other failures
480      */
hasNewMessages()481     public abstract boolean hasNewMessages() throws MessagingException;
482 
483     /**
484      * Return the Folder object corresponding to the given name. Note that
485      * this folder does not physically have to exist in the Store. The
486      * <code>exists()</code> method on a Folder indicates whether it really
487      * exists on the Store. <p>
488      *
489      * In some Stores, name can be an absolute path if it starts with the
490      * hierarchy delimiter.  Otherwise, it is interpreted relative to
491      * this Folder. <p>
492      *
493      * Folder objects are not cached by the Store, so invoking this
494      * method on the same name multiple times will return that many
495      * distinct Folder objects. <p>
496      *
497      * This method can be invoked on a closed Folder.
498      *
499      * @param name 	name of the Folder
500      * @return		Folder object
501      * @exception 	MessagingException for failures
502      */
getFolder(String name)503     public abstract Folder getFolder(String name)
504 				throws MessagingException;
505 
506     /**
507      * Delete this Folder. This method will succeed only on a closed
508      * Folder. <p>
509      *
510      * The <code>recurse</code> flag controls whether the deletion affects
511      * subfolders or not. If true, all subfolders are deleted, then this
512      * folder itself is deleted. If false, the behaviour is dependent on
513      * the folder type and is elaborated below:
514      *
515      * <ul>
516      * <li>
517      * The folder can contain only messages: (type == HOLDS_MESSAGES).
518      * <br>
519      * All messages within the folder are removed. The folder
520      * itself is then removed. An appropriate FolderEvent is generated by
521      * the Store and this folder.
522      *
523      * <li>
524      * The folder can contain only subfolders: (type == HOLDS_FOLDERS).
525      * <br>
526      * If this folder is empty (does not contain any
527      * subfolders at all), it is removed. An appropriate FolderEvent is
528      * generated by the Store and this folder.<br>
529      * If this folder contains any subfolders, the delete fails
530      * and returns false.
531      *
532      * <li>
533      * The folder can contain subfolders as well as messages: <br>
534      * If the folder is empty (no messages or subfolders), it
535      * is removed. If the folder contains no subfolders, but only messages,
536      * then all messages are removed. The folder itself is then removed.
537      * In both the above cases, an appropriate FolderEvent is
538      * generated by the Store and this folder. <p>
539      *
540      * If the folder contains subfolders there are 3 possible
541      * choices an implementation is free to do:
542      *
543      *  <ol>
544      *   <li> The operation fails, irrespective of whether this folder
545      * contains messages or not. Some implementations might elect to go
546      * with this simple approach. The delete() method returns false.
547      *
548      *   <li> Any messages within the folder are removed. Subfolders
549      * are not removed. The folder itself is not removed or affected
550      * in any manner. The delete() method returns true. And the
551      * exists() method on this folder will return true indicating that
552      * this folder still exists. <br>
553      * An appropriate FolderEvent is generated by the Store and this folder.
554      *
555      *   <li> Any messages within the folder are removed. Subfolders are
556      * not removed. The folder itself changes its type from
557      * HOLDS_FOLDERS | HOLDS_MESSAGES to HOLDS_FOLDERS. Thus new
558      * messages cannot be added to this folder, but new subfolders can
559      * be created underneath. The delete() method returns true indicating
560      * success. The exists() method on this folder will return true
561      * indicating that this folder still exists. <br>
562      * An appropriate FolderEvent is generated by the Store and this folder.
563      * </ol>
564      * </ul>
565      *
566      * @param	recurse	also delete subfolders?
567      * @return		true if the Folder is deleted successfully
568      * @exception	FolderNotFoundException if this folder does
569      *			not exist
570      * @exception	IllegalStateException if this folder is not in
571      *			the closed state.
572      * @exception       MessagingException for other failures
573      * @see		javax.mail.event.FolderEvent
574      */
delete(boolean recurse)575     public abstract boolean delete(boolean recurse)
576 				throws MessagingException;
577 
578     /**
579      * Rename this Folder. This method will succeed only on a closed
580      * Folder. <p>
581      *
582      * If the rename is successful, a RENAMED FolderEvent is delivered
583      * to FolderListeners registered on this folder and its containing
584      * Store.
585      *
586      * @param f		a folder representing the new name for this Folder
587      * @return		true if the Folder is renamed successfully
588      * @exception	FolderNotFoundException if this folder does
589      *			not exist
590      * @exception	IllegalStateException if this folder is not in
591      *			the closed state.
592      * @exception       MessagingException for other failures
593      * @see		javax.mail.event.FolderEvent
594      */
renameTo(Folder f)595     public abstract boolean renameTo(Folder f) throws MessagingException;
596 
597     /**
598      * The Folder is read only.  The state and contents of this
599      * folder cannot be modified.
600      */
601     public static final int READ_ONLY 	= 1;
602 
603     /**
604      * The state and contents of this folder can be modified.
605      */
606     public static final int READ_WRITE 	= 2;
607 
608     /**
609      * Open this Folder. This method is valid only on Folders that
610      * can contain Messages and that are closed. <p>
611      *
612      * If this folder is opened successfully, an OPENED ConnectionEvent
613      * is delivered to any ConnectionListeners registered on this
614      * Folder. <p>
615      *
616      * The effect of opening multiple connections to the same folder
617      * on a specifc Store is implementation dependent. Some implementations
618      * allow multiple readers, but only one writer. Others allow
619      * multiple writers as well as readers.
620      *
621      * @param mode	open the Folder READ_ONLY or READ_WRITE
622      * @exception	FolderNotFoundException if this folder does
623      *			not exist.
624      * @exception	IllegalStateException if this folder is not in
625      *			the closed state.
626      * @exception       MessagingException for other failures
627      * @see 		#READ_ONLY
628      * @see 		#READ_WRITE
629      * @see 		#getType()
630      * @see 		javax.mail.event.ConnectionEvent
631      */
open(int mode)632     public abstract void open(int mode) throws MessagingException;
633 
634     /**
635      * Close this Folder. This method is valid only on open Folders. <p>
636      *
637      * A CLOSED ConnectionEvent is delivered to any ConnectionListeners
638      * registered on this Folder. Note that the folder is closed even
639      * if this method terminates abnormally by throwing a
640      * MessagingException.
641      *
642      * @param expunge	expunges all deleted messages if this flag is true
643      * @exception	IllegalStateException if this folder is not opened
644      * @exception       MessagingException for other failures
645      * @see 		javax.mail.event.ConnectionEvent
646      */
close(boolean expunge)647     public abstract void close(boolean expunge) throws MessagingException;
648 
649     /**
650      * Close this Folder and expunge deleted messages. <p>
651      *
652      * A CLOSED ConnectionEvent is delivered to any ConnectionListeners
653      * registered on this Folder. Note that the folder is closed even
654      * if this method terminates abnormally by throwing a
655      * MessagingException. <p>
656      *
657      * This method supports the {@link java.lang.AutoCloseable AutoCloseable}
658      * interface. <p>
659      *
660      * This implementation calls <code>close(true)</code>.
661      *
662      * @exception	IllegalStateException if this folder is not opened
663      * @exception       MessagingException for other failures
664      * @see 		javax.mail.event.ConnectionEvent
665      * @since		JavaMail 1.6
666      */
667     @Override
close()668     public void close() throws MessagingException {
669 	close(true);
670     }
671 
672     /**
673      * Indicates whether this Folder is in the 'open' state.
674      * @return  true if this Folder is in the 'open' state.
675      */
isOpen()676     public abstract boolean isOpen();
677 
678     /**
679      * Return the open mode of this folder.  Returns
680      * <code>Folder.READ_ONLY</code>, <code>Folder.READ_WRITE</code>,
681      * or -1 if the open mode is not known (usually only because an older
682      * <code>Folder</code> provider has not been updated to use this new
683      * method).
684      *
685      * @exception	IllegalStateException if this folder is not opened
686      * @return	        the open mode of this folder
687      * @since		JavaMail 1.1
688      */
getMode()689     public synchronized int getMode() {
690 	if (!isOpen())
691 	    throw new IllegalStateException("Folder not open");
692 	return mode;
693     }
694 
695     /**
696      * Get the permanent flags supported by this Folder. Returns a Flags
697      * object that contains all the flags supported. <p>
698      *
699      * The special flag <code>Flags.Flag.USER </code> indicates that this Folder
700      * supports arbitrary user-defined flags. <p>
701      *
702      * The supported permanent flags for a folder may not be available
703      * until the folder is opened.
704      *
705      * @return 		permanent flags, or null if not known
706      */
getPermanentFlags()707     public abstract Flags getPermanentFlags();
708 
709     /**
710      * Get total number of messages in this Folder. <p>
711      *
712      * This method can be invoked on a closed folder. However, note
713      * that for some folder implementations, getting the total message
714      * count can be an expensive operation involving actually opening
715      * the folder. In such cases, a provider can choose not to support
716      * this functionality in the closed state, in which case this method
717      * must return -1. <p>
718      *
719      * Clients invoking this method on a closed folder must be aware
720      * that this is a potentially expensive operation. Clients must
721      * also be prepared to handle a return value of -1 in this case.
722      *
723      * @return 		total number of messages. -1 may be returned
724      *			by certain implementations if this method is
725      *			invoked on a closed folder.
726      * @exception	FolderNotFoundException if this folder does
727      *			not exist.
728      * @exception       MessagingException for other failures
729      */
getMessageCount()730     public abstract int getMessageCount() throws MessagingException;
731 
732     /**
733      * Get the number of new messages in this Folder. <p>
734      *
735      * This method can be invoked on a closed folder. However, note
736      * that for some folder implementations, getting the new message
737      * count can be an expensive operation involving actually opening
738      * the folder. In such cases, a provider can choose not to support
739      * this functionality in the closed state, in which case this method
740      * must return -1. <p>
741      *
742      * Clients invoking this method on a closed folder must be aware
743      * that this is a potentially expensive operation. Clients must
744      * also be prepared to handle a return value of -1 in this case. <p>
745      *
746      * This implementation returns -1 if this folder is closed. Else
747      * this implementation gets each Message in the folder using
748      * <code>getMessage(int)</code> and checks whether its
749      * <code>RECENT</code> flag is set. The total number of messages
750      * that have this flag set is returned.
751      *
752      * @return 		number of new messages. -1 may be returned
753      *			by certain implementations if this method is
754      *			invoked on a closed folder.
755      * @exception	FolderNotFoundException if this folder does
756      *			not exist.
757      * @exception       MessagingException for other failures
758      */
getNewMessageCount()759     public synchronized int getNewMessageCount()
760 			throws MessagingException {
761 	if (!isOpen())
762 	    return -1;
763 
764 	int newmsgs = 0;
765 	int total = getMessageCount();
766 	for (int i = 1; i <= total; i++) {
767 	    try {
768 		if (getMessage(i).isSet(Flags.Flag.RECENT))
769 		    newmsgs++;
770 	    } catch (MessageRemovedException me) {
771 		// This is an expunged message, ignore it.
772 		continue;
773 	    }
774 	}
775 	return newmsgs;
776     }
777 
778     /**
779      * Get the total number of unread messages in this Folder. <p>
780      *
781      * This method can be invoked on a closed folder. However, note
782      * that for some folder implementations, getting the unread message
783      * count can be an expensive operation involving actually opening
784      * the folder. In such cases, a provider can choose not to support
785      * this functionality in the closed state, in which case this method
786      * must return -1. <p>
787      *
788      * Clients invoking this method on a closed folder must be aware
789      * that this is a potentially expensive operation. Clients must
790      * also be prepared to handle a return value of -1 in this case. <p>
791      *
792      * This implementation returns -1 if this folder is closed. Else
793      * this implementation gets each Message in the folder using
794      * <code>getMessage(int)</code> and checks whether its
795      * <code>SEEN</code> flag is set. The total number of messages
796      * that do not have this flag set is returned.
797      *
798      * @return 		total number of unread messages. -1 may be returned
799      *			by certain implementations if this method is
800      *			invoked on a closed folder.
801      * @exception	FolderNotFoundException if this folder does
802      *			not exist.
803      * @exception       MessagingException for other failures
804      */
getUnreadMessageCount()805     public synchronized int getUnreadMessageCount()
806 			throws MessagingException {
807 	if (!isOpen())
808 	    return -1;
809 
810 	int unread = 0;
811 	int total = getMessageCount();
812 	for (int i = 1; i <= total; i++) {
813 	    try {
814 		if (!getMessage(i).isSet(Flags.Flag.SEEN))
815 		    unread++;
816 	    } catch (MessageRemovedException me) {
817 		// This is an expunged message, ignore it.
818 		continue;
819 	    }
820 	}
821 	return unread;
822     }
823 
824     /**
825      * Get the number of deleted messages in this Folder. <p>
826      *
827      * This method can be invoked on a closed folder. However, note
828      * that for some folder implementations, getting the deleted message
829      * count can be an expensive operation involving actually opening
830      * the folder. In such cases, a provider can choose not to support
831      * this functionality in the closed state, in which case this method
832      * must return -1. <p>
833      *
834      * Clients invoking this method on a closed folder must be aware
835      * that this is a potentially expensive operation. Clients must
836      * also be prepared to handle a return value of -1 in this case. <p>
837      *
838      * This implementation returns -1 if this folder is closed. Else
839      * this implementation gets each Message in the folder using
840      * <code>getMessage(int)</code> and checks whether its
841      * <code>DELETED</code> flag is set. The total number of messages
842      * that have this flag set is returned.
843      *
844      * @return 		number of deleted messages. -1 may be returned
845      *			by certain implementations if this method is
846      *			invoked on a closed folder.
847      * @exception	FolderNotFoundException if this folder does
848      *			not exist.
849      * @exception       MessagingException for other failures
850      * @since		JavaMail 1.3
851      */
getDeletedMessageCount()852     public synchronized int getDeletedMessageCount() throws MessagingException {
853 	if (!isOpen())
854 	    return -1;
855 
856 	int deleted = 0;
857 	int total = getMessageCount();
858 	for (int i = 1; i <= total; i++) {
859 	    try {
860 		if (getMessage(i).isSet(Flags.Flag.DELETED))
861 		    deleted++;
862 	    } catch (MessageRemovedException me) {
863 		// This is an expunged message, ignore it.
864 		continue;
865 	    }
866 	}
867 	return deleted;
868     }
869 
870     /**
871      * Get the Message object corresponding to the given message
872      * number.  A Message object's message number is the relative
873      * position of this Message in its Folder. Messages are numbered
874      * starting at 1 through the total number of message in the folder.
875      * Note that the message number for a particular Message can change
876      * during a session if other messages in the Folder are deleted and
877      * the Folder is expunged. <p>
878      *
879      * Message objects are light-weight references to the actual message
880      * that get filled up on demand. Hence Folder implementations are
881      * expected to provide light-weight Message objects. <p>
882      *
883      * Unlike Folder objects, repeated calls to getMessage with the
884      * same message number will return the same Message object, as
885      * long as no messages in this folder have been expunged. <p>
886      *
887      * Since message numbers can change within a session if the folder
888      * is expunged , clients are advised not to use message numbers as
889      * references to messages. Use Message objects instead.
890      *
891      * @param msgnum	the message number
892      * @return 		the Message object
893      * @see		#getMessageCount
894      * @see		#fetch
895      * @exception	FolderNotFoundException if this folder does
896      *			not exist.
897      * @exception	IllegalStateException if this folder is not opened
898      * @exception	IndexOutOfBoundsException if the message number
899      *			is out of range.
900      * @exception 	MessagingException for other failures
901      */
getMessage(int msgnum)902     public abstract Message getMessage(int msgnum)
903 				throws MessagingException;
904 
905     /**
906      * Get the Message objects for message numbers ranging from start
907      * through end, both start and end inclusive. Note that message
908      * numbers start at 1, not 0. <p>
909      *
910      * Message objects are light-weight references to the actual message
911      * that get filled up on demand. Hence Folder implementations are
912      * expected to provide light-weight Message objects. <p>
913      *
914      * This implementation uses getMessage(index) to obtain the required
915      * Message objects. Note that the returned array must contain
916      * <code>(end-start+1)</code> Message objects.
917      *
918      * @param start	the number of the first message
919      * @param end	the number of the last message
920      * @return 		the Message objects
921      * @see		#fetch
922      * @exception	FolderNotFoundException if this folder does
923      *			not exist.
924      * @exception	IllegalStateException if this folder is not opened.
925      * @exception	IndexOutOfBoundsException if the start or end
926      *			message numbers are out of range.
927      * @exception 	MessagingException for other failures
928      */
getMessages(int start, int end)929     public synchronized Message[] getMessages(int start, int end)
930 			throws MessagingException {
931 	Message[] msgs = new Message[end - start +1];
932 	for (int i = start; i <= end; i++)
933 	    msgs[i - start] = getMessage(i);
934 	return msgs;
935     }
936 
937     /**
938      * Get the Message objects for message numbers specified in
939      * the array. <p>
940      *
941      * Message objects are light-weight references to the actual message
942      * that get filled up on demand. Hence Folder implementations are
943      * expected to provide light-weight Message objects. <p>
944      *
945      * This implementation uses getMessage(index) to obtain the required
946      * Message objects. Note that the returned array must contain
947      * <code>msgnums.length</code> Message objects
948      *
949      * @param msgnums	the array of message numbers
950      * @return 		the array of Message objects.
951      * @see		#fetch
952      * @exception	FolderNotFoundException if this folder does
953      *			not exist.
954      * @exception	IllegalStateException if this folder is not opened.
955      * @exception	IndexOutOfBoundsException if any message number
956      *			in the given array is out of range.
957      * @exception 	MessagingException for other failures
958      */
getMessages(int[] msgnums)959     public synchronized Message[] getMessages(int[] msgnums)
960 			throws MessagingException {
961 	int len = msgnums.length;
962 	Message[] msgs = new Message[len];
963 	for (int i = 0; i < len; i++)
964 	    msgs[i] = getMessage(msgnums[i]);
965 	return msgs;
966     }
967 
968     /**
969      * Get all Message objects from this Folder. Returns an empty array
970      * if the folder is empty.
971      *
972      * Clients can use Message objects (instead of sequence numbers)
973      * as references to the messages within a folder; this method supplies
974      * the Message objects to the client. Folder implementations are
975      * expected to provide light-weight Message objects, which get
976      * filled on demand. <p>
977      *
978      * This implementation invokes <code>getMessageCount()</code> to get
979      * the current message count and then uses <code>getMessage()</code>
980      * to get Message objects from 1 till the message count.
981      *
982      * @return 		array of Message objects, empty array if folder
983      *			is empty.
984      * @see		#fetch
985      * @exception	FolderNotFoundException if this folder does
986      *			not exist.
987      * @exception	IllegalStateException if this folder is not opened.
988      * @exception 	MessagingException for other failures
989      */
getMessages()990     public synchronized Message[] getMessages() throws MessagingException {
991 	if (!isOpen())	// otherwise getMessageCount might return -1
992 	    throw new IllegalStateException("Folder not open");
993 	int total = getMessageCount();
994 	Message[] msgs = new Message[total];
995 	for (int i = 1; i <= total; i++)
996 	    msgs[i-1] = getMessage(i);
997 	return msgs;
998     }
999 
1000     /**
1001      * Append given Messages to this folder. This method can be
1002      * invoked on a closed Folder. An appropriate MessageCountEvent
1003      * is delivered to any MessageCountListener registered on this
1004      * folder when the messages arrive in the folder. <p>
1005      *
1006      * Folder implementations must not abort this operation if a
1007      * Message in the given message array turns out to be an
1008      * expunged Message.
1009      *
1010      * @param msgs	array of Messages to be appended
1011      * @exception	FolderNotFoundException if this folder does
1012      *			not exist.
1013      * @exception 	MessagingException if the append failed.
1014      */
appendMessages(Message[] msgs)1015     public abstract void appendMessages(Message[] msgs)
1016 				throws MessagingException;
1017 
1018     /**
1019      * Prefetch the items specified in the FetchProfile for the
1020      * given Messages. <p>
1021      *
1022      * Clients use this method to indicate that the specified items are
1023      * needed en-masse for the given message range. Implementations are
1024      * expected to retrieve these items for the given message range in
1025      * a efficient manner. Note that this method is just a hint to the
1026      * implementation to prefetch the desired items. <p>
1027      *
1028      * An example is a client filling its header-view window with
1029      * the Subject, From and X-mailer headers for all messages in the
1030      * folder.
1031      * <blockquote><pre>
1032      *
1033      *  Message[] msgs = folder.getMessages();
1034      *
1035      *  FetchProfile fp = new FetchProfile();
1036      *  fp.add(FetchProfile.Item.ENVELOPE);
1037      *  fp.add("X-mailer");
1038      *  folder.fetch(msgs, fp);
1039      *
1040      *  for (int i = 0; i &lt; folder.getMessageCount(); i++) {
1041      *      display(msg[i].getFrom());
1042      *      display(msg[i].getSubject());
1043      *      display(msg[i].getHeader("X-mailer"));
1044      *  }
1045      *
1046      * </pre></blockquote><p>
1047      *
1048      * The implementation provided here just returns without
1049      * doing anything useful. Providers wanting to provide a real
1050      * implementation for this method should override this method.
1051      *
1052      * @param msgs	fetch items for these messages
1053      * @param fp	the FetchProfile
1054      * @exception	IllegalStateException if this folder is not opened
1055      * @exception	MessagingException for other failures
1056      */
fetch(Message[] msgs, FetchProfile fp)1057     public void fetch(Message[] msgs, FetchProfile fp)
1058 			throws MessagingException {
1059 	return;
1060     }
1061 
1062     /**
1063      * Set the specified flags on the messages specified in the array.
1064      * This will result in appropriate MessageChangedEvents being
1065      * delivered to any MessageChangedListener registered on this
1066      * Message's containing folder. <p>
1067      *
1068      * Note that the specified Message objects <strong>must</strong>
1069      * belong to this folder. Certain Folder implementations can
1070      * optimize the operation of setting Flags for a group of messages,
1071      * so clients might want to use this method, rather than invoking
1072      * <code>Message.setFlags</code> for each Message. <p>
1073      *
1074      * This implementation degenerates to invoking <code>setFlags()</code>
1075      * on each Message object. Specific Folder implementations that can
1076      * optimize this case should do so.
1077      * Also, an implementation must not abort the operation if a Message
1078      * in the array turns out to be an expunged Message.
1079      *
1080      * @param msgs	the array of message objects
1081      * @param flag	Flags object containing the flags to be set
1082      * @param value	set the flags to this boolean value
1083      * @exception	IllegalStateException if this folder is not opened
1084      *			or if it has been opened READ_ONLY.
1085      * @exception 	MessagingException for other failures
1086      * @see		Message#setFlags
1087      * @see		javax.mail.event.MessageChangedEvent
1088      */
setFlags(Message[] msgs, Flags flag, boolean value)1089     public synchronized void setFlags(Message[] msgs,
1090 			Flags flag, boolean value) throws  MessagingException {
1091 	for (int i = 0; i < msgs.length; i++) {
1092 	    try {
1093 		msgs[i].setFlags(flag, value);
1094 	    } catch (MessageRemovedException me) {
1095 		// This message is expunged, skip
1096 	    }
1097 	}
1098     }
1099 
1100     /**
1101      * Set the specified flags on the messages numbered from start
1102      * through end, both start and end inclusive. Note that message
1103      * numbers start at 1, not 0.
1104      * This will result in appropriate MessageChangedEvents being
1105      * delivered to any MessageChangedListener registered on this
1106      * Message's containing folder. <p>
1107      *
1108      * Certain Folder implementations can
1109      * optimize the operation of setting Flags for a group of messages,
1110      * so clients might want to use this method, rather than invoking
1111      * <code>Message.setFlags</code> for each Message. <p>
1112      *
1113      * The default implementation uses <code>getMessage(int)</code> to
1114      * get each <code>Message</code> object and then invokes
1115      * <code>setFlags</code> on that object to set the flags.
1116      * Specific Folder implementations that can optimize this case should do so.
1117      * Also, an implementation must not abort the operation if a message
1118      * number refers to an expunged message.
1119      *
1120      * @param start	the number of the first message
1121      * @param end	the number of the last message
1122      * @param flag	Flags object containing the flags to be set
1123      * @param value	set the flags to this boolean value
1124      * @exception	IllegalStateException if this folder is not opened
1125      *			or if it has been opened READ_ONLY.
1126      * @exception	IndexOutOfBoundsException if the start or end
1127      *			message numbers are out of range.
1128      * @exception 	MessagingException for other failures
1129      * @see		Message#setFlags
1130      * @see		javax.mail.event.MessageChangedEvent
1131      */
setFlags(int start, int end, Flags flag, boolean value)1132     public synchronized void setFlags(int start, int end,
1133 			Flags flag, boolean value) throws MessagingException {
1134 	for (int i = start; i <= end; i++) {
1135 	    try {
1136 		Message msg = getMessage(i);
1137 		msg.setFlags(flag, value);
1138 	    } catch (MessageRemovedException me) {
1139 		// This message is expunged, skip
1140 	    }
1141 	}
1142     }
1143 
1144     /**
1145      * Set the specified flags on the messages whose message numbers
1146      * are in the array.
1147      * This will result in appropriate MessageChangedEvents being
1148      * delivered to any MessageChangedListener registered on this
1149      * Message's containing folder. <p>
1150      *
1151      * Certain Folder implementations can
1152      * optimize the operation of setting Flags for a group of messages,
1153      * so clients might want to use this method, rather than invoking
1154      * <code>Message.setFlags</code> for each Message. <p>
1155      *
1156      * The default implementation uses <code>getMessage(int)</code> to
1157      * get each <code>Message</code> object and then invokes
1158      * <code>setFlags</code> on that object to set the flags.
1159      * Specific Folder implementations that can optimize this case should do so.
1160      * Also, an implementation must not abort the operation if a message
1161      * number refers to an expunged message.
1162      *
1163      * @param msgnums	the array of message numbers
1164      * @param flag	Flags object containing the flags to be set
1165      * @param value	set the flags to this boolean value
1166      * @exception	IllegalStateException if this folder is not opened
1167      *			or if it has been opened READ_ONLY.
1168      * @exception	IndexOutOfBoundsException if any message number
1169      *			in the given array is out of range.
1170      * @exception 	MessagingException for other failures
1171      * @see		Message#setFlags
1172      * @see		javax.mail.event.MessageChangedEvent
1173      */
setFlags(int[] msgnums, Flags flag, boolean value)1174     public synchronized void setFlags(int[] msgnums,
1175 			Flags flag, boolean value) throws MessagingException {
1176 	for (int i = 0; i < msgnums.length; i++) {
1177 	    try {
1178 		Message msg = getMessage(msgnums[i]);
1179 		msg.setFlags(flag, value);
1180 	    } catch (MessageRemovedException me) {
1181 		// This message is expunged, skip
1182 	    }
1183 	}
1184     }
1185 
1186     /**
1187      * Copy the specified Messages from this Folder into another
1188      * Folder. This operation appends these Messages to the
1189      * destination Folder. The destination Folder does not have to
1190      * be opened.  An appropriate MessageCountEvent
1191      * is delivered to any MessageCountListener registered on the
1192      * destination folder when the messages arrive in the folder. <p>
1193      *
1194      * Note that the specified Message objects <strong>must</strong>
1195      * belong to this folder. Folder implementations might be able
1196      * to optimize this method by doing server-side copies. <p>
1197      *
1198      * This implementation just invokes <code>appendMessages()</code>
1199      * on the destination folder to append the given Messages. Specific
1200      * folder implementations that support server-side copies should
1201      * do so, if the destination folder's Store is the same as this
1202      * folder's Store.
1203      * Also, an implementation must not abort the operation if a
1204      * Message in the array turns out to be an expunged Message.
1205      *
1206      * @param msgs	the array of message objects
1207      * @param folder	the folder to copy the messages to
1208      * @exception	FolderNotFoundException if the destination
1209      *			folder does not exist.
1210      * @exception	IllegalStateException if this folder is not opened.
1211      * @exception	MessagingException for other failures
1212      * @see		#appendMessages
1213      */
copyMessages(Message[] msgs, Folder folder)1214     public void copyMessages(Message[] msgs, Folder folder)
1215 				throws MessagingException {
1216 	if (!folder.exists())
1217 	    throw new FolderNotFoundException(
1218 			folder.getFullName() + " does not exist",
1219 			folder);
1220 
1221 	folder.appendMessages(msgs);
1222     }
1223 
1224     /**
1225      * Expunge (permanently remove) messages marked DELETED. Returns an
1226      * array containing the expunged message objects.  The
1227      * <code>getMessageNumber</code> method
1228      * on each of these message objects returns that Message's original
1229      * (that is, prior to the expunge) sequence number. A MessageCountEvent
1230      * containing the expunged messages is delivered to any
1231      * MessageCountListeners registered on the folder. <p>
1232      *
1233      * Expunge causes the renumbering of Message objects subsequent to
1234      * the expunged messages. Clients that use message numbers as
1235      * references to messages should be aware of this and should be
1236      * prepared to deal with the situation (probably by flushing out
1237      * existing message number caches and reloading them). Because of
1238      * this complexity, it is better for clients to use Message objects
1239      * as references to messages, rather than message numbers. Any
1240      * expunged Messages objects still have to be pruned, but other
1241      * Messages in that folder are not affected by the expunge. <p>
1242      *
1243      * After a message is expunged, only the <code>isExpunged</code> and
1244      * <code>getMessageNumber</code> methods are still valid on the
1245      * corresponding Message object; other methods may throw
1246      * <code>MessageRemovedException</code>
1247      *
1248      * @return		array of expunged Message objects
1249      * @exception	FolderNotFoundException if this folder does not
1250      *			exist
1251      * @exception	IllegalStateException if this folder is not opened.
1252      * @exception       MessagingException for other failures
1253      * @see		Message#isExpunged
1254      * @see		javax.mail.event.MessageCountEvent
1255      */
expunge()1256     public abstract Message[] expunge() throws MessagingException;
1257 
1258     /**
1259      * Search this Folder for messages matching the specified
1260      * search criterion. Returns an array containing the matching
1261      * messages . Returns an empty array if no matches were found. <p>
1262      *
1263      * This implementation invokes
1264      * <code>search(term, getMessages())</code>, to apply the search
1265      * over all the messages in this folder. Providers that can implement
1266      * server-side searching might want to override this method to provide
1267      * a more efficient implementation.
1268      *
1269      * @param term	the search criterion
1270      * @return 		array of matching messages
1271      * @exception       javax.mail.search.SearchException if the search
1272      *			term is too complex for the implementation to handle.
1273      * @exception	FolderNotFoundException if this folder does
1274      *			not exist.
1275      * @exception	IllegalStateException if this folder is not opened.
1276      * @exception       MessagingException for other failures
1277      * @see		javax.mail.search.SearchTerm
1278      */
search(SearchTerm term)1279     public Message[] search(SearchTerm term) throws MessagingException {
1280 	return search(term, getMessages());
1281     }
1282 
1283     /**
1284      * Search the given array of messages for those that match the
1285      * specified search criterion. Returns an array containing the
1286      * matching messages. Returns an empty array if no matches were
1287      * found. <p>
1288      *
1289      * Note that the specified Message objects <strong>must</strong>
1290      * belong to this folder. <p>
1291      *
1292      * This implementation iterates through the given array of messages,
1293      * and applies the search criterion on each message by calling
1294      * its <code>match()</code> method with the given term. The
1295      * messages that succeed in the match are returned. Providers
1296      * that can implement server-side searching might want to override
1297      * this method to provide a more efficient implementation. If the
1298      * search term is too complex or contains user-defined terms that
1299      * cannot be executed on the server, providers may elect to either
1300      * throw a SearchException or degenerate to client-side searching by
1301      * calling <code>super.search()</code> to invoke this implementation.
1302      *
1303      * @param term	the search criterion
1304      * @param msgs 	the messages to be searched
1305      * @return 		array of matching messages
1306      * @exception       javax.mail.search.SearchException if the search
1307      *			term is too complex for the implementation to handle.
1308      * @exception	IllegalStateException if this folder is not opened
1309      * @exception       MessagingException for other failures
1310      * @see		javax.mail.search.SearchTerm
1311      */
search(SearchTerm term, Message[] msgs)1312     public Message[] search(SearchTerm term, Message[] msgs)
1313 				throws MessagingException {
1314 	List<Message> matchedMsgs = new ArrayList<>();
1315 
1316 	// Run thru the given messages
1317 	for (Message msg : msgs) {
1318 	    try {
1319 		if (msg.match(term)) // matched
1320 		    matchedMsgs.add(msg); // add it
1321 	    } catch(MessageRemovedException mrex) { }
1322 	}
1323 
1324 	return matchedMsgs.toArray(new Message[matchedMsgs.size()]);
1325     }
1326 
1327     /*
1328      * The set of listeners are stored in Vectors appropriate to their
1329      * type.  We mark all listener Vectors as "volatile" because, while
1330      * we initialize them inside this folder's synchronization lock,
1331      * they are accessed (checked for null) in the "notify" methods,
1332      * which can't be synchronized due to lock ordering constraints.
1333      * Since the listener fields (the handles on the Vector objects)
1334      * are only ever set, and are never cleared, we believe this is
1335      * safe.  The code that dispatches the notifications will either
1336      * see the null and assume there are no listeners or will see the
1337      * Vector and will process the listeners.  There's an inherent race
1338      * between adding a listener and notifying the listeners; the lack
1339      * of synchronization during notification does not make the race
1340      * condition significantly worse.  If one thread is setting a
1341      * listener at the "same" time an event is being dispatched, the
1342      * dispatch code might not see the listener right away.  The
1343      * dispatch code doesn't have to worry about the Vector handle
1344      * being set to null, and thus using an out-of-date set of
1345      * listeners, because we never set the field to null.
1346      */
1347 
1348     // Vector of connection listeners.
1349     private volatile Vector<ConnectionListener> connectionListeners = null;
1350 
1351     /**
1352      * Add a listener for Connection events on this Folder. <p>
1353      *
1354      * The implementation provided here adds this listener
1355      * to an internal list of ConnectionListeners.
1356      *
1357      * @param l 	the Listener for Connection events
1358      * @see		javax.mail.event.ConnectionEvent
1359      */
1360     public synchronized void
addConnectionListener(ConnectionListener l)1361     addConnectionListener(ConnectionListener l) {
1362    	if (connectionListeners == null)
1363 	    connectionListeners = new Vector<>();
1364 	connectionListeners.addElement(l);
1365     }
1366 
1367     /**
1368      * Remove a Connection event listener. <p>
1369      *
1370      * The implementation provided here removes this listener
1371      * from the internal list of ConnectionListeners.
1372      *
1373      * @param l 	the listener
1374      * @see		#addConnectionListener
1375      */
1376     public synchronized void
removeConnectionListener(ConnectionListener l)1377     removeConnectionListener(ConnectionListener l) {
1378    	if (connectionListeners != null)
1379 	    connectionListeners.removeElement(l);
1380     }
1381 
1382     /**
1383      * Notify all ConnectionListeners. Folder implementations are
1384      * expected to use this method to broadcast connection events. <p>
1385      *
1386      * The provided implementation queues the event into
1387      * an internal event queue. An event dispatcher thread dequeues
1388      * events from the queue and dispatches them to the registered
1389      * ConnectionListeners. Note that the event dispatching occurs
1390      * in a separate thread, thus avoiding potential deadlock problems.
1391      *
1392      * @param type	the ConnectionEvent type
1393      * @see		javax.mail.event.ConnectionEvent
1394      */
notifyConnectionListeners(int type)1395     protected void notifyConnectionListeners(int type) {
1396    	if (connectionListeners != null) {
1397 	    ConnectionEvent e = new ConnectionEvent(this, type);
1398 	    queueEvent(e, connectionListeners);
1399 	}
1400 
1401 	/* Fix for broken JDK1.1.x Garbage collector :
1402 	 *  The 'conservative' GC in JDK1.1.x occasionally fails to
1403 	 *  garbage-collect Threads which are in the wait state.
1404 	 *  This would result in thread (and consequently memory) leaks.
1405 	 *
1406 	 * We attempt to fix this by sending a 'terminator' event
1407 	 * to the queue, after we've sent the CLOSED event. The
1408 	 * terminator event causes the event-dispatching thread to
1409 	 * self destruct.
1410 	 */
1411 	if (type == ConnectionEvent.CLOSED)
1412 	    q.terminateQueue();
1413     }
1414 
1415     // Vector of folder listeners
1416     private volatile Vector<FolderListener> folderListeners = null;
1417 
1418     /**
1419      * Add a listener for Folder events on this Folder. <p>
1420      *
1421      * The implementation provided here adds this listener
1422      * to an internal list of FolderListeners.
1423      *
1424      * @param l 	the Listener for Folder events
1425      * @see		javax.mail.event.FolderEvent
1426      */
addFolderListener(FolderListener l)1427     public synchronized void addFolderListener(FolderListener l) {
1428    	if (folderListeners == null)
1429 	    folderListeners = new Vector<>();
1430 	folderListeners.addElement(l);
1431     }
1432 
1433     /**
1434      * Remove a Folder event listener. <p>
1435      *
1436      * The implementation provided here removes this listener
1437      * from the internal list of FolderListeners.
1438      *
1439      * @param l 	the listener
1440      * @see		#addFolderListener
1441      */
removeFolderListener(FolderListener l)1442     public synchronized void removeFolderListener(FolderListener l) {
1443 	if (folderListeners != null)
1444 	    folderListeners.removeElement(l);
1445     }
1446 
1447     /**
1448      * Notify all FolderListeners registered on this Folder and
1449      * this folder's Store. Folder implementations are expected
1450      * to use this method to broadcast Folder events. <p>
1451      *
1452      * The implementation provided here queues the event into
1453      * an internal event queue. An event dispatcher thread dequeues
1454      * events from the queue and dispatches them to the
1455      * FolderListeners registered on this folder. The implementation
1456      * also invokes <code>notifyFolderListeners</code> on this folder's
1457      * Store to notify any FolderListeners registered on the store.
1458      *
1459      * @param type	type of FolderEvent
1460      * @see		#notifyFolderRenamedListeners
1461      */
notifyFolderListeners(int type)1462     protected void notifyFolderListeners(int type) {
1463    	if (folderListeners != null) {
1464 	    FolderEvent e = new FolderEvent(this, this, type);
1465 	    queueEvent(e, folderListeners);
1466 	}
1467 	store.notifyFolderListeners(type, this);
1468     }
1469 
1470     /**
1471      * Notify all FolderListeners registered on this Folder and
1472      * this folder's Store about the renaming of this folder.
1473      * Folder implementations are expected to use this method to
1474      * broadcast Folder events indicating the renaming of folders. <p>
1475      *
1476      * The implementation provided here queues the event into
1477      * an internal event queue. An event dispatcher thread dequeues
1478      * events from the queue and dispatches them to the
1479      * FolderListeners registered on this folder. The implementation
1480      * also invokes <code>notifyFolderRenamedListeners</code> on this
1481      * folder's Store to notify any FolderListeners registered on the store.
1482      *
1483      * @param	folder	Folder representing the new name.
1484      * @see		#notifyFolderListeners
1485      * @since		JavaMail 1.1
1486      */
notifyFolderRenamedListeners(Folder folder)1487     protected void notifyFolderRenamedListeners(Folder folder) {
1488    	if (folderListeners != null) {
1489 	    FolderEvent e = new FolderEvent(this, this, folder,
1490 					    FolderEvent.RENAMED);
1491 	    queueEvent(e, folderListeners);
1492 	}
1493 	store.notifyFolderRenamedListeners(this, folder);
1494     }
1495 
1496     // Vector of MessageCount listeners
1497     private volatile Vector<MessageCountListener> messageCountListeners = null;
1498 
1499     /**
1500      * Add a listener for MessageCount events on this Folder. <p>
1501      *
1502      * The implementation provided here adds this listener
1503      * to an internal list of MessageCountListeners.
1504      *
1505      * @param l 	the Listener for MessageCount events
1506      * @see		javax.mail.event.MessageCountEvent
1507      */
addMessageCountListener(MessageCountListener l)1508     public synchronized void addMessageCountListener(MessageCountListener l) {
1509    	if (messageCountListeners == null)
1510 	    messageCountListeners = new Vector<>();
1511 	messageCountListeners.addElement(l);
1512     }
1513 
1514     /**
1515      * Remove a MessageCount listener. <p>
1516      *
1517      * The implementation provided here removes this listener
1518      * from the internal list of MessageCountListeners.
1519      *
1520      * @param l 	the listener
1521      * @see		#addMessageCountListener
1522      */
1523     public synchronized void
removeMessageCountListener(MessageCountListener l)1524 			removeMessageCountListener(MessageCountListener l) {
1525    	if (messageCountListeners != null)
1526 	    messageCountListeners.removeElement(l);
1527     }
1528 
1529     /**
1530      * Notify all MessageCountListeners about the addition of messages
1531      * into this folder. Folder implementations are expected to use this
1532      * method to broadcast MessageCount events for indicating arrival of
1533      * new messages. <p>
1534      *
1535      * The provided implementation queues the event into
1536      * an internal event queue. An event dispatcher thread dequeues
1537      * events from the queue and dispatches them to the registered
1538      * MessageCountListeners. Note that the event dispatching occurs
1539      * in a separate thread, thus avoiding potential deadlock problems.
1540      *
1541      * @param	msgs	the messages that were added
1542      */
notifyMessageAddedListeners(Message[] msgs)1543     protected void notifyMessageAddedListeners(Message[] msgs) {
1544    	if (messageCountListeners == null)
1545 	    return;
1546 
1547 	MessageCountEvent e = new MessageCountEvent(
1548 					this,
1549 					MessageCountEvent.ADDED,
1550 					false,
1551 					msgs);
1552 
1553    	queueEvent(e, messageCountListeners);
1554     }
1555 
1556     /**
1557      * Notify all MessageCountListeners about the removal of messages
1558      * from this Folder. Folder implementations are expected to use this
1559      * method to broadcast MessageCount events indicating removal of
1560      * messages. <p>
1561      *
1562      * The provided implementation queues the event into
1563      * an internal event queue. An event dispatcher thread dequeues
1564      * events from the queue and dispatches them to the registered
1565      * MessageCountListeners. Note that the event dispatching occurs
1566      * in a separate thread, thus avoiding potential deadlock problems.
1567      *
1568      * @param	removed	was the message removed by this client?
1569      * @param	msgs	the messages that were removed
1570      */
notifyMessageRemovedListeners(boolean removed, Message[] msgs)1571     protected void notifyMessageRemovedListeners(boolean removed,
1572 						 Message[] msgs) {
1573    	if (messageCountListeners == null)
1574 	    return;
1575 
1576 	MessageCountEvent e = new MessageCountEvent(
1577 					this,
1578 					MessageCountEvent.REMOVED,
1579 					removed,
1580 					msgs);
1581    	queueEvent(e, messageCountListeners);
1582     }
1583 
1584     // Vector of MessageChanged listeners.
1585     private volatile Vector<MessageChangedListener> messageChangedListeners
1586 	    = null;
1587 
1588     /**
1589      * Add a listener for MessageChanged events on this Folder. <p>
1590      *
1591      * The implementation provided here adds this listener
1592      * to an internal list of MessageChangedListeners.
1593      *
1594      * @param l 	the Listener for MessageChanged events
1595      * @see		javax.mail.event.MessageChangedEvent
1596      */
1597     public synchronized void
addMessageChangedListener(MessageChangedListener l)1598 			addMessageChangedListener(MessageChangedListener l) {
1599    	if (messageChangedListeners == null)
1600 	    messageChangedListeners = new Vector<>();
1601 	messageChangedListeners.addElement(l);
1602     }
1603 
1604     /**
1605      * Remove a MessageChanged listener. <p>
1606      *
1607      * The implementation provided here removes this listener
1608      * from the internal list of MessageChangedListeners.
1609      *
1610      * @param l 	the listener
1611      * @see		#addMessageChangedListener
1612      */
1613     public synchronized void
removeMessageChangedListener(MessageChangedListener l)1614 		removeMessageChangedListener(MessageChangedListener l) {
1615    	if (messageChangedListeners != null)
1616 	    messageChangedListeners.removeElement(l);
1617     }
1618 
1619     /**
1620      * Notify all MessageChangedListeners. Folder implementations are
1621      * expected to use this method to broadcast MessageChanged events. <p>
1622      *
1623      * The provided implementation queues the event into
1624      * an internal event queue. An event dispatcher thread dequeues
1625      * events from the queue and dispatches them to registered
1626      * MessageChangedListeners. Note that the event dispatching occurs
1627      * in a separate thread, thus avoiding potential deadlock problems.
1628      *
1629      * @param	type	the MessageChangedEvent type
1630      * @param	msg	the message that changed
1631      */
notifyMessageChangedListeners(int type, Message msg)1632     protected void notifyMessageChangedListeners(int type, Message msg) {
1633 	if (messageChangedListeners == null)
1634 	    return;
1635 
1636 	MessageChangedEvent e = new MessageChangedEvent(this, type, msg);
1637 	queueEvent(e, messageChangedListeners);
1638     }
1639 
1640     /*
1641      * Add the event and vector of listeners to the queue to be delivered.
1642      */
1643     @SuppressWarnings("unchecked")
queueEvent(MailEvent event, Vector<? extends EventListener> vector)1644     private void queueEvent(MailEvent event,
1645 	    Vector<? extends EventListener> vector) {
1646 	/*
1647          * Copy the vector in order to freeze the state of the set
1648          * of EventListeners the event should be delivered to prior
1649          * to delivery.  This ensures that any changes made to the
1650          * Vector from a target listener's method during the delivery
1651          * of this event will not take effect until after the event is
1652          * delivered.
1653          */
1654 	Vector<? extends EventListener> v = (Vector)vector.clone();
1655 	q.enqueue(event, v);
1656     }
1657 
1658     @Override
finalize()1659     protected void finalize() throws Throwable {
1660 	try {
1661 	    q.terminateQueue();
1662 	} finally {
1663 	    super.finalize();
1664 	}
1665     }
1666 
1667     /**
1668      * override the default toString(), it will return the String
1669      * from Folder.getFullName() or if that is null, it will use
1670      * the default toString() behavior.
1671      */
1672 
1673     @Override
toString()1674     public String toString() {
1675 	String s = getFullName();
1676 	if (s != null)
1677 	    return s;
1678 	else
1679 	    return super.toString();
1680     }
1681 }
1682