|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
Folder.java | 0% | 12.9% | 7.7% | 9.2% |
|
1 | /** | |
2 | * | |
3 | * Copyright 2003-2004 The Apache Software Foundation | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | ||
18 | package javax.mail; | |
19 | ||
20 | import java.util.ArrayList; | |
21 | import java.util.List; | |
22 | import javax.mail.Flags.Flag; | |
23 | import javax.mail.event.ConnectionEvent; | |
24 | import javax.mail.event.ConnectionListener; | |
25 | import javax.mail.event.FolderEvent; | |
26 | import javax.mail.event.FolderListener; | |
27 | import javax.mail.event.MessageChangedEvent; | |
28 | import javax.mail.event.MessageChangedListener; | |
29 | import javax.mail.event.MessageCountEvent; | |
30 | import javax.mail.event.MessageCountListener; | |
31 | import javax.mail.search.SearchTerm; | |
32 | ||
33 | /** | |
34 | * An abstract representation of a folder in a mail system; subclasses would | |
35 | * implement Folders for each supported protocol. | |
36 | * <p/> | |
37 | * Depending on protocol and implementation, folders may contain other folders, messages, | |
38 | * or both as indicated by the {@link Folder#HOLDS_FOLDERS} and {@link Folder#HOLDS_MESSAGES} flags. | |
39 | * If the immplementation supports hierarchical folders, the format of folder names is | |
40 | * implementation dependent; however, components of the name are separated by the | |
41 | * delimiter character returned by {@link Folder#getSeparator()}. | |
42 | * <p/> | |
43 | * The case-insensitive folder name "INBOX" is reserved to refer to the primary folder | |
44 | * for the current user on the current server; not all stores will provide an INBOX | |
45 | * and it may not be available at all times. | |
46 | * | |
47 | * @version $Rev: 126350 $ $Date: 2005-01-24 22:35:47 -0800 (Mon, 24 Jan 2005) $ | |
48 | */ | |
49 | public abstract class Folder { | |
50 | /** | |
51 | * Flag that indicates that a folder can contain messages. | |
52 | */ | |
53 | public static final int HOLDS_MESSAGES = 1; | |
54 | /** | |
55 | * Flag that indicates that a folder can contain other folders. | |
56 | */ | |
57 | public static final int HOLDS_FOLDERS = 2; | |
58 | ||
59 | /** | |
60 | * Flag indicating that this folder cannot be modified. | |
61 | */ | |
62 | public static final int READ_ONLY = 1; | |
63 | /** | |
64 | * Flag indictaing that this folder can be modified. | |
65 | * Question: what does it mean if both are set? | |
66 | */ | |
67 | public static final int READ_WRITE = 2; | |
68 | ||
69 | /** | |
70 | * The store that this folder is part of. | |
71 | */ | |
72 | protected Store store; | |
73 | /** | |
74 | * The current mode of this folder. | |
75 | * When open, this can be {@link #READ_ONLY} or {@link #READ_WRITE}; | |
76 | * otherwise is set to -1. | |
77 | */ | |
78 | protected int mode = -1; | |
79 | ||
80 | private final List connectionListeners = new ArrayList(2); | |
81 | private final List folderListeners = new ArrayList(2); | |
82 | private final List messageChangedListeners = new ArrayList(2); | |
83 | private final List messageCountListeners = new ArrayList(2); | |
84 | private final EventQueue queue = new EventQueue(); | |
85 | ||
86 | /** | |
87 | * Constructor that initializes the Store. | |
88 | * | |
89 | * @param store the store that this folder is part of | |
90 | */ | |
91 | 9 | protected Folder(Store store) { |
92 | 9 | this.store = store; |
93 | } | |
94 | ||
95 | /** | |
96 | * Return the name of this folder. | |
97 | * This can be invoked when the folder is closed. | |
98 | * | |
99 | * @return this folder's name | |
100 | */ | |
101 | public abstract String getName(); | |
102 | ||
103 | /** | |
104 | * Return the full absolute name of this folder. | |
105 | * This can be invoked when the folder is closed. | |
106 | * | |
107 | * @return the full name of this folder | |
108 | */ | |
109 | public abstract String getFullName(); | |
110 | ||
111 | /** | |
112 | * Return the URLName for this folder, which includes the location of the store. | |
113 | * | |
114 | * @return the URLName for this folder | |
115 | * @throws MessagingException | |
116 | */ | |
117 | 0 | public URLName getURLName() throws MessagingException { |
118 | // todo shouldn't this include the full name of the folder? | |
119 | 0 | return store.getURLName(); |
120 | } | |
121 | ||
122 | /** | |
123 | * Return the store that this folder is part of. | |
124 | * | |
125 | * @return the store this folder is part of | |
126 | */ | |
127 | 3 | public Store getStore() { |
128 | 3 | return store; |
129 | } | |
130 | ||
131 | /** | |
132 | * Return the parent for this folder; if the folder is at the root of a heirarchy | |
133 | * this returns null. | |
134 | * This can be invoked when the folder is closed. | |
135 | * | |
136 | * @return this folder's parent | |
137 | * @throws MessagingException | |
138 | */ | |
139 | public abstract Folder getParent() throws MessagingException; | |
140 | ||
141 | /** | |
142 | * Check to see if this folder physically exists in the store. | |
143 | * This can be invoked when the folder is closed. | |
144 | * | |
145 | * @return true if the folder really exists | |
146 | * @throws MessagingException if there was a problem accessing the store | |
147 | */ | |
148 | public abstract boolean exists() throws MessagingException; | |
149 | ||
150 | /** | |
151 | * Return a list of folders from this Folder's namespace that match the supplied pattern. | |
152 | * Patterns may contain the following wildcards: | |
153 | * <ul><li>'%' which matches any characater except hierarchy delimiters</li> | |
154 | * <li>'*' which matches any character including hierarchy delimiters</li> | |
155 | * </ul> | |
156 | * This can be invoked when the folder is closed. | |
157 | * | |
158 | * @param pattern the pattern to search for | |
159 | * @return a, possibly empty, array containing Folders that matched the pattern | |
160 | * @throws MessagingException if there was a problem accessing the store | |
161 | */ | |
162 | public abstract Folder[] list(String pattern) throws MessagingException; | |
163 | ||
164 | /** | |
165 | * Return a list of folders to which the user is subscribed and which match the supplied pattern. | |
166 | * If the store does not support the concept of subscription then this should match against | |
167 | * all folders; the default implementation of this method achieves this by defaulting to the | |
168 | * {@link #list(String)} method. | |
169 | * | |
170 | * @param pattern the pattern to search for | |
171 | * @return a, possibly empty, array containing subscribed Folders that matched the pattern | |
172 | * @throws MessagingException if there was a problem accessing the store | |
173 | */ | |
174 | 0 | public Folder[] listSubscribed(String pattern) throws MessagingException { |
175 | 0 | return list(pattern); |
176 | } | |
177 | ||
178 | /** | |
179 | * Convenience method that invokes {@link #list(String)} with the pattern "%". | |
180 | * | |
181 | * @return a, possibly empty, array of subfolders | |
182 | * @throws MessagingException if there was a problem accessing the store | |
183 | */ | |
184 | 0 | public Folder[] list() throws MessagingException { |
185 | 0 | return list("%"); |
186 | } | |
187 | ||
188 | /** | |
189 | * Convenience method that invokes {@link #listSubscribed(String)} with the pattern "%". | |
190 | * | |
191 | * @return a, possibly empty, array of subscribed subfolders | |
192 | * @throws MessagingException if there was a problem accessing the store | |
193 | */ | |
194 | 0 | public Folder[] listSubscribed() throws MessagingException { |
195 | 0 | return listSubscribed("%"); |
196 | } | |
197 | ||
198 | /** | |
199 | * Return the character used by this folder's Store to separate path components. | |
200 | * | |
201 | * @return the name separater character | |
202 | * @throws MessagingException if there was a problem accessing the store | |
203 | */ | |
204 | public abstract char getSeparator() throws MessagingException; | |
205 | ||
206 | /** | |
207 | * Return the type of this folder, indicating whether it can contain subfolders, | |
208 | * messages, or both. The value returned is a bitmask with the appropriate bits set. | |
209 | * | |
210 | * @return the type of this folder | |
211 | * @throws MessagingException if there was a problem accessing the store | |
212 | * @see #HOLDS_FOLDERS | |
213 | * @see #HOLDS_MESSAGES | |
214 | */ | |
215 | public abstract int getType() throws MessagingException; | |
216 | ||
217 | /** | |
218 | * Create a new folder capable of containing subfoldera and/or messages as | |
219 | * determined by the type parameter. Any hierarchy defined by the folder | |
220 | * name will be recursively created. | |
221 | * If the folder was sucessfully created, a {@link FolderEvent#CREATED CREATED FolderEvent} | |
222 | * is sent to all FolderListeners registered with this Folder or with the Store. | |
223 | * | |
224 | * @param type the type, indicating if this folder should contain subfolders, messages or both | |
225 | * @return true if the folder was sucessfully created | |
226 | * @throws MessagingException if there was a problem accessing the store | |
227 | */ | |
228 | public abstract boolean create(int type) throws MessagingException; | |
229 | ||
230 | /** | |
231 | * Determine if the user is subscribed to this Folder. The default implementation in | |
232 | * this class always returns true. | |
233 | * | |
234 | * @return true is the user is subscribed to this Folder | |
235 | */ | |
236 | 0 | public boolean isSubscribed() { |
237 | 0 | return true; |
238 | } | |
239 | ||
240 | /** | |
241 | * Set the user's subscription to this folder. | |
242 | * Not all Stores support subscription; the default implementation in this class | |
243 | * always throws a MethodNotSupportedException | |
244 | * | |
245 | * @param subscribed whether to subscribe to this Folder | |
246 | * @throws MessagingException if there was a problem accessing the store | |
247 | * @throws MethodNotSupportedException if the Store does not support subscription | |
248 | */ | |
249 | 0 | public void setSubscribed(boolean subscribed) throws MessagingException { |
250 | 0 | throw new MethodNotSupportedException(); |
251 | } | |
252 | ||
253 | /** | |
254 | * Check to see if this Folder conatins messages with the {@link Flag.RECENT} flag set. | |
255 | * This can be used when the folder is closed to perform a light-weight check for new mail; | |
256 | * to perform an incremental check for new mail the folder must be opened. | |
257 | * | |
258 | * @return true if the Store has recent messages | |
259 | * @throws MessagingException if there was a problem accessing the store | |
260 | */ | |
261 | public abstract boolean hasNewMessages() throws MessagingException; | |
262 | ||
263 | /** | |
264 | * Get the Folder determined by the supplied name; if the name is relative | |
265 | * then it is interpreted relative to this folder. This does not check that | |
266 | * the named folder actually exists. | |
267 | * | |
268 | * @param name the name of the folder to return | |
269 | * @return the named folder | |
270 | * @throws MessagingException if there was a problem accessing the store | |
271 | */ | |
272 | public abstract Folder getFolder(String name) throws MessagingException; | |
273 | ||
274 | /** | |
275 | * Delete this folder and possibly any subfolders. This operation can only be | |
276 | * performed on a closed folder. | |
277 | * If recurse is true, then all subfolders are deleted first, then any messages in | |
278 | * this folder are removed and it is finally deleted; {@link FolderEvent#DELETED} | |
279 | * events are sent as appropriate. | |
280 | * If recurse is false, then the behaviour depends on the folder type and store | |
281 | * implementation as followd: | |
282 | * <ul> | |
283 | * <li>If the folder can only conrain messages, then all messages are removed and | |
284 | * then the folder is deleted; a {@link FolderEvent#DELETED} event is sent.</li> | |
285 | * <li>If the folder can onlu contain subfolders, then if it is empty it will be | |
286 | * deleted and a {@link FolderEvent#DELETED} event is sent; if the folder is not | |
287 | * empty then the delete fails and this method returns false.</li> | |
288 | * <li>If the folder can contain both subfolders and messages, then if the folder | |
289 | * does not contain any subfolders, any messages are deleted, the folder itself | |
290 | * is deleted and a {@link FolderEvent#DELETED} event is sent; if the folder does | |
291 | * contain subfolders then the implementation may choose from the following three | |
292 | * behaviors: | |
293 | * <ol> | |
294 | * <li>it may return false indicting the operation failed</li> | |
295 | * <li>it may remove all messages within the folder, send a {@link FolderEvent#DELETED} | |
296 | * event, and then return true to indicate the delete was performed. Note this does | |
297 | * not delete the folder itself and the {@link #exists()} operation for this folder | |
298 | * will return true</li> | |
299 | * <li>it may remove all messages within the folder as per the previous option; in | |
300 | * addition it may change the type of the Folder to only HOLDS_FOLDERS indictaing | |
301 | * that messages may no longer be added</li> | |
302 | * </li> | |
303 | * </ul> | |
304 | * FolderEvents are sent to all listeners registered with this folder or | |
305 | * with the Store. | |
306 | * | |
307 | * @param recurse whether subfolders should be recursively deleted as well | |
308 | * @return true if the delete operation succeeds | |
309 | * @throws MessagingException if there was a problem accessing the store | |
310 | */ | |
311 | public abstract boolean delete(boolean recurse) throws MessagingException; | |
312 | ||
313 | /** | |
314 | * Rename this folder; the folder must be closed. | |
315 | * If the rename is successfull, a {@link FolderEvent#RENAMED} event is sent to | |
316 | * all listeners registered with this folder or with the store. | |
317 | * | |
318 | * @param newName the new name for this folder | |
319 | * @return true if the rename succeeded | |
320 | * @throws MessagingException if there was a problem accessing the store | |
321 | */ | |
322 | public abstract boolean renameTo(Folder newName) throws MessagingException; | |
323 | ||
324 | /** | |
325 | * Open this folder; the folder must be able to contain messages and | |
326 | * must currently be closed. If the folder is opened successfully then | |
327 | * a {@link ConnectionEvent#OPENED} event is sent to listeners registered | |
328 | * with this Folder. | |
329 | * <p/> | |
330 | * Whether the Store allows multiple connections or if it allows multiple | |
331 | * writers is implementation defined. | |
332 | * | |
333 | * @param mode READ_ONLY or READ_WRITE | |
334 | * @throws MessagingException if there was a problem accessing the store | |
335 | */ | |
336 | public abstract void open(int mode) throws MessagingException; | |
337 | ||
338 | /** | |
339 | * Close this folder; it must already be open. | |
340 | * A {@link ConnectionEvent#CLOSED} event is sent to all listeners registered | |
341 | * with this folder. | |
342 | * | |
343 | * @param expunge whether to expunge all deleted messages | |
344 | * @throws MessagingException if there was a problem accessing the store; the folder is still closed | |
345 | */ | |
346 | public abstract void close(boolean expunge) throws MessagingException; | |
347 | ||
348 | /** | |
349 | * Indicates that the folder has been opened. | |
350 | * | |
351 | * @return true if the folder is open | |
352 | */ | |
353 | public abstract boolean isOpen(); | |
354 | ||
355 | /** | |
356 | * Return the mode of this folder ass passed to {@link #open(int)}, or -1 if | |
357 | * the folder is closed. | |
358 | * | |
359 | * @return the mode this folder was opened with | |
360 | */ | |
361 | 0 | public int getMode() { |
362 | 0 | return mode; |
363 | } | |
364 | ||
365 | /** | |
366 | * Get the flags supported by this folder. | |
367 | * | |
368 | * @return the flags supported by this folder, or null if unknown | |
369 | * @see Flags | |
370 | */ | |
371 | public abstract Flags getPermanentFlags(); | |
372 | ||
373 | /** | |
374 | * Return the number of messages this folder contains. | |
375 | * If this operation is invoked on a closed folder, the implementation | |
376 | * may choose to return -1 to avoid the expense of opening the folder. | |
377 | * | |
378 | * @return the number of messages, or -1 if unknown | |
379 | * @throws MessagingException if there was a problem accessing the store | |
380 | */ | |
381 | public abstract int getMessageCount() throws MessagingException; | |
382 | ||
383 | /** | |
384 | * Return the numbew of messages in this folder that have the {@link Flag.RECENT} flag set. | |
385 | * If this operation is invoked on a closed folder, the implementation | |
386 | * may choose to return -1 to avoid the expense of opening the folder. | |
387 | * The default implmentation of this method iterates over all messages | |
388 | * in the folder; subclasses should override if possible to provide a more | |
389 | * efficient implementation. | |
390 | * | |
391 | * @return the number of new messages, or -1 if unknown | |
392 | * @throws MessagingException if there was a problem accessing the store | |
393 | */ | |
394 | 0 | public int getNewMessageCount() throws MessagingException { |
395 | 0 | return getCount(Flags.Flag.RECENT, true); |
396 | } | |
397 | ||
398 | /** | |
399 | * Return the numbew of messages in this folder that do not have the {@link Flag.SEEN} flag set. | |
400 | * If this operation is invoked on a closed folder, the implementation | |
401 | * may choose to return -1 to avoid the expense of opening the folder. | |
402 | * The default implmentation of this method iterates over all messages | |
403 | * in the folder; subclasses should override if possible to provide a more | |
404 | * efficient implementation. | |
405 | * | |
406 | * @return the number of new messages, or -1 if unknown | |
407 | * @throws MessagingException if there was a problem accessing the store | |
408 | */ | |
409 | 0 | public int getUnreadMessageCount() throws MessagingException { |
410 | 0 | return getCount(Flags.Flag.SEEN, false); |
411 | } | |
412 | ||
413 | /** | |
414 | * Return the numbew of messages in this folder that have the {@link Flag.DELETED} flag set. | |
415 | * If this operation is invoked on a closed folder, the implementation | |
416 | * may choose to return -1 to avoid the expense of opening the folder. | |
417 | * The default implmentation of this method iterates over all messages | |
418 | * in the folder; subclasses should override if possible to provide a more | |
419 | * efficient implementation. | |
420 | * | |
421 | * @return the number of new messages, or -1 if unknown | |
422 | * @throws MessagingException if there was a problem accessing the store | |
423 | */ | |
424 | 0 | public int getDeletedMessageCount() throws MessagingException { |
425 | 0 | return getCount(Flags.Flag.DELETED, true); |
426 | } | |
427 | ||
428 | 0 | private int getCount(Flag flag, boolean value) throws MessagingException { |
429 | 0 | if (!isOpen()) { |
430 | 0 | return -1; |
431 | } | |
432 | 0 | Message[] messages = getMessages(); |
433 | 0 | int total = 0; |
434 | 0 | for (int i = 0; i < messages.length; i++) { |
435 | 0 | if (messages[i].getFlags().contains(flag) == value) { |
436 | 0 | total++; |
437 | } | |
438 | } | |
439 | 0 | return total; |
440 | } | |
441 | ||
442 | /** | |
443 | * Retrieve the message with the specified index in this Folder; | |
444 | * messages indices start at 1 not zero. | |
445 | * Clients should note that the index for a specific message may change | |
446 | * if the folder is expunged; {@link Message} objects should be used as | |
447 | * references instead. | |
448 | * | |
449 | * @param index the index of the message to fetch | |
450 | * @return the message | |
451 | * @throws MessagingException if there was a problem accessing the store | |
452 | */ | |
453 | public abstract Message getMessage(int index) throws MessagingException; | |
454 | ||
455 | /** | |
456 | * Retrieve messages with index between start and end inclusive | |
457 | * | |
458 | * @param start index of first message | |
459 | * @param end index of last message | |
460 | * @return an array of messages from start to end inclusive | |
461 | * @throws MessagingException if there was a problem accessing the store | |
462 | */ | |
463 | 0 | public Message[] getMessages(int start, int end) throws MessagingException { |
464 | 0 | Message[] result = new Message[end - start + 1]; |
465 | 0 | for (int i = 0; i < result.length; i++) { |
466 | 0 | result[i] = getMessage(start++); |
467 | } | |
468 | 0 | return result; |
469 | } | |
470 | ||
471 | /** | |
472 | * Retrieve messages with the specified indices. | |
473 | * | |
474 | * @param ids the indices of the messages to fetch | |
475 | * @return the specified messages | |
476 | * @throws MessagingException if there was a problem accessing the store | |
477 | */ | |
478 | 0 | public Message[] getMessages(int ids[]) throws MessagingException { |
479 | 0 | Message[] result = new Message[ids.length]; |
480 | 0 | for (int i = 0; i < ids.length; i++) { |
481 | 0 | result[i] = getMessage(ids[i]); |
482 | } | |
483 | 0 | return result; |
484 | } | |
485 | ||
486 | /** | |
487 | * Retrieve all messages. | |
488 | * | |
489 | * @return all messages in this folder | |
490 | * @throws MessagingException if there was a problem accessing the store | |
491 | */ | |
492 | 0 | public Message[] getMessages() throws MessagingException { |
493 | 0 | return getMessages(1, getMessageCount()); |
494 | } | |
495 | ||
496 | /** | |
497 | * Append the supplied messages to this folder. A {@link MessageCountEvent} is sent | |
498 | * to all listeners registered with this folder when all messages have been appended. | |
499 | * If the array contains a previously expunged message, it must be re-appended to the Store | |
500 | * and implementations must not abort this operation. | |
501 | * | |
502 | * @param messages the messages to append | |
503 | * @throws MessagingException if there was a problem accessing the store | |
504 | */ | |
505 | public abstract void appendMessages(Message[] messages) throws MessagingException; | |
506 | ||
507 | /** | |
508 | * Hint to the store to prefetch information on the supplied messaged. | |
509 | * Subclasses should override this method to provide an efficient implementation; | |
510 | * the default implementation in this class simply returns. | |
511 | * | |
512 | * @param messages messages for which information should be fetched | |
513 | * @param profile the information to fetch | |
514 | * @throws MessagingException if there was a problem accessing the store | |
515 | * @see FetchProfile | |
516 | */ | |
517 | 0 | public void fetch(Message[] messages, FetchProfile profile) throws MessagingException { |
518 | 0 | return; |
519 | } | |
520 | ||
521 | /** | |
522 | * Set flags on the messages to the supplied value; all messages must belong to this folder. | |
523 | * This method may be overridden by subclasses that can optimize the setting | |
524 | * of flags on multiple messages at once; the default implementation simply calls | |
525 | * {@link Message#setFlags(Flags, boolean)} for each supplied messages. | |
526 | * | |
527 | * @param messages whose flags should be set | |
528 | * @param flags the set of flags to modify | |
529 | * @param value the value the flags should be set to | |
530 | * @throws MessagingException if there was a problem accessing the store | |
531 | */ | |
532 | 0 | public void setFlags(Message[] messages, Flags flags, boolean value) throws MessagingException { |
533 | 0 | for (int i = 0; i < messages.length; i++) { |
534 | 0 | Message message = messages[i]; |
535 | 0 | message.setFlags(flags, value); |
536 | } | |
537 | } | |
538 | ||
539 | /** | |
540 | * Set flags on a range of messages to the supplied value. | |
541 | * This method may be overridden by subclasses that can optimize the setting | |
542 | * of flags on multiple messages at once; the default implementation simply | |
543 | * gets each message and then calls {@link Message#setFlags(Flags, boolean)}. | |
544 | * | |
545 | * @param start first message end set | |
546 | * @param end last message end set | |
547 | * @param flags the set of flags end modify | |
548 | * @param value the value the flags should be set end | |
549 | * @throws MessagingException if there was a problem accessing the store | |
550 | */ | |
551 | 0 | public void setFlags(int start, int end, Flags flags, boolean value) throws MessagingException { |
552 | 0 | for (int i = start; i <= end; i++) { |
553 | 0 | Message message = getMessage(i); |
554 | 0 | message.setFlags(flags, value); |
555 | } | |
556 | } | |
557 | ||
558 | /** | |
559 | * Set flags on a set of messages to the supplied value. | |
560 | * This method may be overridden by subclasses that can optimize the setting | |
561 | * of flags on multiple messages at once; the default implementation simply | |
562 | * gets each message and then calls {@link Message#setFlags(Flags, boolean)}. | |
563 | * | |
564 | * @param ids the indexes of the messages to set | |
565 | * @param flags the set of flags end modify | |
566 | * @param value the value the flags should be set end | |
567 | * @throws MessagingException if there was a problem accessing the store | |
568 | */ | |
569 | 0 | public void setFlags(int ids[], Flags flags, boolean value) throws MessagingException { |
570 | 0 | for (int i = 0; i < ids.length; i++) { |
571 | 0 | Message message = getMessage(ids[i]); |
572 | 0 | message.setFlags(flags, value); |
573 | } | |
574 | } | |
575 | ||
576 | /** | |
577 | * Copy the specified messages to another folder. | |
578 | * The default implementation simply appends the supplied messages to the | |
579 | * target folder using {@link #appendMessages(Message[])}. | |
580 | * @param messages the messages to copy | |
581 | * @param folder the folder to copy to | |
582 | * @throws MessagingException if there was a problem accessing the store | |
583 | */ | |
584 | 0 | public void copyMessages(Message[] messages, Folder folder) throws MessagingException { |
585 | 0 | folder.appendMessages(messages); |
586 | } | |
587 | ||
588 | /** | |
589 | * Permanently delete all supplied messages that have the DELETED flag set from the Store. | |
590 | * The original message indices of all messages actually deleted are returned and a | |
591 | * {@link MessageCountEvent} event is sent to all listeners with this folder. The expunge | |
592 | * may cause the indices of all messaged that remain in the folder to change. | |
593 | * | |
594 | * @return the original indices of messages that were actually deleted | |
595 | * @throws MessagingException if there was a problem accessing the store | |
596 | */ | |
597 | public abstract Message[] expunge() throws MessagingException; | |
598 | ||
599 | /** | |
600 | * Search this folder for messages matching the supplied search criteria. | |
601 | * The default implementation simply invoke <code>search(term, getMessages()) | |
602 | * applying the search over all messages in the folder; subclasses may provide | |
603 | * a more efficient mechanism. | |
604 | * | |
605 | * @param term the search criteria | |
606 | * @return an array containing messages that match the criteria | |
607 | * @throws MessagingException if there was a problem accessing the store | |
608 | */ | |
609 | 0 | public Message[] search(SearchTerm term) throws MessagingException { |
610 | 0 | return search(term, getMessages()); |
611 | } | |
612 | ||
613 | /** | |
614 | * Search the supplied messages for those that match the supplied criteria; | |
615 | * messages must belong to this folder. | |
616 | * The default implementation iterates through the messages, returning those | |
617 | * whose {@link Message#match(javax.mail.search.SearchTerm)} method returns true; | |
618 | * subclasses may provide a more efficient implementation. | |
619 | * | |
620 | * @param term the search criteria | |
621 | * @param messages the messages to search | |
622 | * @return an array containing messages that match the criteria | |
623 | * @throws MessagingException if there was a problem accessing the store | |
624 | */ | |
625 | 0 | public Message[] search(SearchTerm term, Message[] messages) throws MessagingException { |
626 | 0 | List result = new ArrayList(messages.length); |
627 | 0 | for (int i = 0; i < messages.length; i++) { |
628 | 0 | Message message = messages[i]; |
629 | 0 | if (message.match(term)) { |
630 | 0 | result.add(message); |
631 | } | |
632 | } | |
633 | 0 | return (Message[]) result.toArray(new Message[result.size()]); |
634 | } | |
635 | ||
636 | 0 | public void addConnectionListener(ConnectionListener listener) { |
637 | 0 | connectionListeners.add(listener); |
638 | } | |
639 | ||
640 | 0 | public void removeConnectionListener(ConnectionListener listener) { |
641 | 0 | connectionListeners.remove(listener); |
642 | } | |
643 | ||
644 | 0 | protected void notifyConnectionListeners(int type) { |
645 | 0 | queue.queueEvent(new ConnectionEvent(this, type), connectionListeners); |
646 | } | |
647 | ||
648 | 0 | public void addFolderListener(FolderListener listener) { |
649 | 0 | folderListeners.add(listener); |
650 | } | |
651 | ||
652 | 0 | public void removeFolderListener(FolderListener listener) { |
653 | 0 | folderListeners.remove(listener); |
654 | } | |
655 | ||
656 | 0 | protected void notifyFolderListeners(int type) { |
657 | 0 | queue.queueEvent(new FolderEvent(this, this, type), folderListeners); |
658 | } | |
659 | ||
660 | 0 | protected void notifyFolderRenamedListeners(Folder newFolder) { |
661 | 0 | queue.queueEvent(new FolderEvent(this, this, newFolder, FolderEvent.RENAMED), folderListeners); |
662 | } | |
663 | ||
664 | 0 | public void addMessageCountListener(MessageCountListener listener) { |
665 | 0 | messageCountListeners.add(listener); |
666 | } | |
667 | ||
668 | 0 | public void removeMessageCountListener(MessageCountListener listener) { |
669 | 0 | messageCountListeners.remove(listener); |
670 | } | |
671 | ||
672 | 0 | protected void notifyMessageAddedListeners(Message[] messages) { |
673 | 0 | queue.queueEvent(new MessageCountEvent(this, MessageCountEvent.ADDED, false, messages), messageChangedListeners); |
674 | } | |
675 | ||
676 | 0 | protected void notifyMessageRemovedListeners(boolean removed, Message[] messages) { |
677 | 0 | queue.queueEvent(new MessageCountEvent(this, MessageCountEvent.REMOVED, removed, messages), messageChangedListeners); |
678 | } | |
679 | ||
680 | 0 | public void addMessageChangedListener(MessageChangedListener listener) { |
681 | 0 | messageChangedListeners.add(listener); |
682 | } | |
683 | ||
684 | 0 | public void removeMessageChangedListener(MessageChangedListener listener) { |
685 | 0 | messageChangedListeners.remove(listener); |
686 | } | |
687 | ||
688 | 0 | protected void notifyMessageChangedListeners(int type, Message message) { |
689 | 0 | queue.queueEvent(new MessageChangedEvent(this, type, message), messageChangedListeners); |
690 | } | |
691 | ||
692 | /** | |
693 | * Unregisters all listeners. | |
694 | */ | |
695 | 5 | protected void finalize() throws Throwable { |
696 | 5 | queue.stop(); |
697 | 5 | connectionListeners.clear(); |
698 | 5 | folderListeners.clear(); |
699 | 5 | messageChangedListeners.clear(); |
700 | 5 | messageCountListeners.clear(); |
701 | 5 | store = null; |
702 | 5 | super.finalize(); |
703 | } | |
704 | ||
705 | /** | |
706 | * Returns the full name of this folder; if null, returns the value from the superclass. | |
707 | * @return a string form of this folder | |
708 | */ | |
709 | 0 | public String toString() { |
710 | 0 | String name = getFullName(); |
711 | 0 | return name == null ? super.toString() : name; |
712 | } | |
713 | } |
|