📄 imapfolder.java
字号:
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. * Sun designates this particular file as subject to the "Classpath" exception * as provided by Sun in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own * identifying information: "Portions Copyrighted [year] * [name of copyright owner]" * * Contributor(s): * * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. *//* * @(#)IMAPFolder.java 1.85 07/09/05 */package com.sun.mail.imap;import java.util.Date;import java.util.Vector;import java.util.Hashtable;import java.util.NoSuchElementException;import java.io.*;import javax.mail.*;import javax.mail.event.*;import javax.mail.internet.*;import javax.mail.search.*;import com.sun.mail.util.*;import com.sun.mail.iap.*;import com.sun.mail.imap.protocol.*;/** * This class implements an IMAP folder. <p> * * A closed IMAPFolder object shares a protocol connection with its IMAPStore * object. When the folder is opened, it gets its own protocol connection. <p> * * Applications that need to make use of IMAP-specific features may cast * a <code>Folder</code> object to an <code>IMAPFolder</code> object and * use the methods on this class. The {@link #getQuota getQuota} and * {@link #setQuota setQuota} methods support the IMAP QUOTA extension. * Refer to <A HREF="http://www.ietf.org/rfc/rfc2087.txt">RFC 2087</A> * for more information. <p> * * The {@link #getACL getACL}, {@link #addACL addACL}, * {@link #removeACL removeACL}, {@link #addRights addRights}, * {@link #removeRights removeRights}, {@link #listRights listRights}, and * {@link #myRights myRights} methods support the IMAP ACL extension. * Refer to <A HREF="http://www.ietf.org/rfc/rfc2086.txt">RFC 2086</A> * for more information. <p> * * The {@link #doCommand doCommand} method and * {@link IMAPFolder.ProtocolCommand IMAPFolder.ProtocolCommand} * interface support use of arbitrary IMAP protocol commands. <p> * * See the <a href="package-summary.html">com.sun.mail.imap</a> package * documentation for further information on the IMAP protocol provider. <p> * * <strong>WARNING:</strong> The APIs unique to this class should be * considered <strong>EXPERIMENTAL</strong>. They may be changed in the * future in ways that are incompatible with applications using the * current APIs. * * @version 1.85, 07/09/05 * @author John Mani * @author Bill Shannon * @author Jim Glennon *//* * The folder object itself serves as a lock for the folder's state * EXCEPT for the message cache (see below), typically by using * synchronized methods. When checking that a folder is open or * closed, the folder's lock must be held. It's important that the * folder's lock is acquired before the messageCacheLock (see below). * Thus, the locking hierarchy is that the folder lock, while optional, * must be acquired before the messageCacheLock, if it's acquired at * all. Be especially careful of callbacks that occur while holding * the messageCacheLock into (e.g.) superclass Folder methods that are * synchronized. Note that methods in IMAPMessage will acquire the * messageCacheLock without acquiring the folder lock. <p> * * When a folder is opened, it creates a messageCache (a Vector) of * empty IMAPMessage objects. Each Message has a messageNumber - which * is its index into the messageCache, and a sequenceNumber - which is * its IMAP sequence-number. All operations on a Message which involve * communication with the server, use the message's sequenceNumber. <p> * * The most important thing to note here is that the server can send * unsolicited EXPUNGE notifications as part of the responses for "most" * commands. Refer RFC2060, sections 5.3 & 5.5 for gory details. Also, * the server sends these notifications AFTER the message has been * expunged. And once a message is expunged, the sequence-numbers of * those messages after the expunged one are renumbered. This essentially * means that the mapping between *any* Message and its sequence-number * can change in the period when a IMAP command is issued and its responses * are processed. Hence we impose a strict locking model as follows: <p> * * We define one mutex per folder - this is just a Java Object (named * messageCacheLock). Any time a command is to be issued to the IMAP * server (i.e., anytime the corresponding IMAPProtocol method is * invoked), follow the below style: * * synchronized (messageCacheLock) { // ACQUIRE LOCK * issue command () * * // The response processing is typically done within * // the handleResponse() callback. A few commands (Fetch, * // Expunge) return *all* responses and hence their * // processing is done here itself. Now, as part of the * // processing unsolicited EXPUNGE responses, we renumber * // the necessary sequence-numbers. Thus the renumbering * // happens within this critical-region, surrounded by * // locks. * process responses () * } // RELEASE LOCK * * This technique is used both by methods in IMAPFolder and by methods * in IMAPMessage and other classes that operate on data in the folder. * Note that holding the messageCacheLock has the side effect of * preventing the folder from being closed, and thus ensuring that the * folder's protocol object is still valid. The protocol object should * only be accessed while holding the messageCacheLock (except for calls * to IMAPProtocol.isREV1(), which don't need to be protected because it * doesn't access the server). * * Note that interactions with the Store's protocol connection do * not have to be protected as above, since the Store's protocol is * never in a "meaningful" SELECT-ed state. */public class IMAPFolder extends Folder implements UIDFolder, ResponseHandler { protected String fullName; // full name protected String name; // name protected int type; // folder type. protected char separator; // separator protected Flags availableFlags; // available flags protected Flags permanentFlags; // permanent flags protected boolean exists = false; // whether this folder really exists ? protected boolean isNamespace = false; // folder is a namespace name protected String[] attributes; // name attributes from LIST response protected IMAPProtocol protocol; // this folder's own protocol object protected Vector messageCache; // message cache protected Object messageCacheLock; // accessor lock for message cache protected Hashtable uidTable; // UID->Message hashtable /* An IMAP delimiter is a 7bit US-ASCII character. (except NUL). * We use '\uffff' (a non 7bit character) to indicate that we havent * yet determined what the separator character is. * We use '\u0000' (NUL) to indicate that no separator character * exists, i.e., a flat hierarchy */ static final protected char UNKNOWN_SEPARATOR = '\uffff'; private boolean opened = false; // is this folder opened ? /* This field tracks the state of this folder. If the folder is closed * due to external causes (i.e, not thru the close() method), then * this field will remain false. If the folder is closed thru the * close() method, then this field is set to true. * * If reallyClosed is false, then a FolderClosedException is * generated when a method is invoked on any Messaging object * owned by this folder. If reallyClosed is true, then the * IllegalStateException runtime exception is thrown. */ private boolean reallyClosed = true; /* * The idleState field supports the IDLE command. * Normally when executing an IMAP command we hold the * messageCacheLock and often the folder lock (see above). * While executing the IDLE command we can't hold either * of these locks or it would prevent other threads from * entering Folder methods even far enough to check whether * an IDLE command is in progress. We need to check before * issuing another command so that we can abort the IDLE * command. * * The idleState field is protected by the messageCacheLock. * The RUNNING state is the normal state and means no IDLE * command is in progress. The IDLE state means we've issued * an IDLE command and are reading responses. The ABORTING * state means we've sent the DONE continuation command and * are waiting for the thread running the IDLE command to * break out of its read loop. * * When an IDLE command is in progress, the thread calling * the idle method will be reading from the IMAP connection * while holding neither the folder lock nor the messageCacheLock. * It's obviously critical that no other thread try to send a * command or read from the connection while in this state. * However, other threads can send the DONE continuation * command that will cause the server to break out of the IDLE * loop and send the ending tag response to the IDLE command. * The thread in the idle method that's reading the responses * from the IDLE command will see this ending response and * complete the idle method, setting the idleState field back * to RUNNING, and notifying any threads waiting to use the * connection. * * All uses of the IMAP connection (IMAPProtocol object) must * be done while holding the messageCacheLock and must be * preceeded by a check to make sure an IDLE command is not * running, and abort the IDLE command if necessary. While * waiting for the IDLE command to complete, these other threads * will give up the messageCacheLock, but might still be holding * the folder lock. This check is done by the getProtocol() * method, resulting in a typical usage pattern of: * * synchronized (messageCacheLock) { * IMAPProtocol p = getProtocol(); // may block waiting for IDLE * // ... use protocol * } */ private static final int RUNNING = 0; // not doing IDLE command private static final int IDLE = 1; // IDLE command in effect private static final int ABORTING = 2; // IDLE command aborting private int idleState = RUNNING; private int total = -1; // total number of messages in the // message cache private int recent = -1; // number of recent messages private int realTotal = -1; // total number of messages on // the server private long uidvalidity = -1; // UIDValidity private long uidnext = -1; // UIDNext private boolean doExpungeNotification = true; // used in expunge handler private Status cachedStatus = null; private long cachedStatusTime = 0; private boolean debug = false; private PrintStream out; // debug output stream private boolean connectionPoolDebug; /** * A fetch profile item for fetching headers. * This inner class extends the <code>FetchProfile.Item</code> * class to add new FetchProfile item types, specific to IMAPFolders. * * @see FetchProfile */ public static class FetchProfileItem extends FetchProfile.Item { protected FetchProfileItem(String name) { super(name); } /** * HEADERS is a fetch profile item that can be included in a * <code>FetchProfile</code> during a fetch request to a Folder. * This item indicates that the headers for messages in the specified * range are desired to be prefetched. <p> * * An example of how a client uses this is below: <p> * <blockquote><pre> * * FetchProfile fp = new FetchProfile(); * fp.add(IMAPFolder.FetchProfileItem.HEADERS); * folder.fetch(msgs, fp); * * </pre></blockquote><p> */ public static final FetchProfileItem HEADERS = new FetchProfileItem("HEADERS"); /** * SIZE is a fetch profile item that can be included in a * <code>FetchProfile</code> during a fetch request to a Folder. * This item indicates that the sizes of the messages in the specified * range are desired to be prefetched. <p> * * SIZE should move to FetchProfile.Item in JavaMail 1.3. */ public static final FetchProfileItem SIZE = new FetchProfileItem("SIZE"); } /** * Constructor used to create a possibly non-existent folder. * * @param fullName fullname of this folder * @param separator the default separator character for this * folder's namespace * @param store the Store */ protected IMAPFolder(String fullName, char separator, IMAPStore store) { super(store); if (fullName == null) throw new NullPointerException("Folder name is null"); this.fullName = fullName; this.separator = separator; messageCacheLock = new Object(); debug = store.getSession().getDebug(); connectionPoolDebug = ((IMAPStore)store).getConnectionPoolDebug(); out = store.getSession().getDebugOut(); if (out == null) // should never happen out = System.out; /* * Work around apparent bug in Exchange. Exchange * will return a name of "Public Folders/" from * LIST "%". * * If name has one separator, and it's at the end, * assume this is a namespace name and treat it * accordingly. Usually this will happen as a result * of the list method, but this also allows getFolder * to work with namespace names. */ this.isNamespace = false; if (separator != UNKNOWN_SEPARATOR && separator != '\0') { int i = this.fullName.indexOf(separator); if (i > 0 && i == this.fullName.length() - 1) { this.fullName = this.fullName.substring(0, i); this.isNamespace = true; } } } /** * Constructor used to create a possibly non-existent folder. * * @param fullName fullname of this folder * @param separator the default separator character for this * folder's namespace * @param store the Store */ protected IMAPFolder(String fullName, char separator, IMAPStore store, boolean isNamespace) { this(fullName, separator, store); this.isNamespace = isNamespace; } /** * Constructor used to create an existing folder. */ protected IMAPFolder(ListInfo li, IMAPStore store) { this(li.name, li.separator, store); if (li.hasInferiors) type |= HOLDS_FOLDERS; if (li.canOpen) type |= HOLDS_MESSAGES; exists = true; attributes = li.attrs; } /* * Ensure that this folder exists. If 'exists' has been set to true, * we don't attempt to validate it with the server again. Note that * this can result in a possible loss of sync with the server. */ private void checkExists() throws MessagingException { // If the boolean field 'exists' is false, check with the // server by invoking exists() .. if (!exists && !exists()) throw new FolderNotFoundException( this, fullName + " not found"); } /* * Ensure the folder is closed. * ASSERT: Must be called with this folder's synchronization lock held. */ private void checkClosed() { if (opened) throw new IllegalStateException( "This operation is not allowed on an open folder" ); } /* * Ensure the folder is open. * ASSERT: Must be called with this folder's synchronization lock held. */ private void checkOpened() throws FolderClosedException { assert Thread.holdsLock(this); if (!opened) { if (reallyClosed) throw new IllegalStateException( "This operation is not allowed on a closed folder" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -