⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imapfolder.java

📁 此源码是在sun站点上提供的javamail基础上改进。用来解决中文邮件或很多国际间邮件乱码问题。版权属于sun公司。不过当你开发webmail程序时做邮件展示时
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 * 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"
		);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -