imapfolder.java

来自「此源码是在sun站点上提供的javamail基础上改进。用来解决中文邮件或很多国」· Java 代码 · 共 1,998 行 · 第 1/5 页

JAVA
1,998
字号
	    throw new FolderNotFoundException(this, fullName + " not found");

	int i = findName(li, lname);
	if (li[i].changeState == ListInfo.CHANGED)
	    return true;
	else if (li[i].changeState == ListInfo.UNCHANGED)
	    return false;

	// LIST didn't work. Try the hard way, using STATUS
	try {
	    Status status = getStatus();
	    if (status.recent > 0)
		return true;
	    else
		return false;
	} catch (BadCommandException bex) {
	    // Probably doesn't support STATUS, tough luck.
	    return false;
	} catch (ConnectionException cex) {
	    throw new StoreClosedException(store, cex.getMessage());
	} catch (ProtocolException pex) {
	    throw new MessagingException(pex.getMessage(), pex);
	}
    }

    /**
     * Get the named subfolder. <p>
     */
    public Folder getFolder(String name) throws MessagingException {
	// If we know that this folder is *not* a directory, don't
	// send the request to the server at all ...
	if (attributes != null && !isDirectory())
	    throw new MessagingException("Cannot contain subfolders");

	char c = getSeparator();
	return new IMAPFolder(fullName + c + name, c, (IMAPStore)store);
    }

    /**
     * Delete this folder.
     */
    public synchronized boolean delete(boolean recurse) 
			throws MessagingException {  
	checkClosed(); // insure that this folder is closed.

	if (recurse) {
	    // Delete all subfolders.
	    Folder[] f = list();
	    for (int i = 0; i < f.length; i++)
		f[i].delete(recurse); // ignore intermediate failures
	}

	// Attempt to delete this folder

	Object ret = doCommandIgnoreFailure(new ProtocolCommand() {
	    public Object doCommand(IMAPProtocol p) throws ProtocolException {
		p.delete(fullName);
		return Boolean.TRUE;
	    }
	});

	if (ret == null)
	    // Non-existent folder/No permission ??
	    return false;

	// DELETE succeeded.
	exists = false;
	attributes = null;

	// Notify listeners on self and our Store
	notifyFolderListeners(FolderEvent.DELETED);
	return true;
    }

    /**
     * Rename this folder. <p>
     */
    public synchronized boolean renameTo(final Folder f)
				throws MessagingException {
	checkClosed(); // insure that we are closed.
	checkExists();
	if (f.getStore() != store)
	    throw new MessagingException("Can't rename across Stores");


	Object ret = doCommandIgnoreFailure(new ProtocolCommand() {
	    public Object doCommand(IMAPProtocol p) throws ProtocolException {
		p.rename(fullName, f.getFullName());
		return Boolean.TRUE;
	    }
	});

	if (ret == null)
	    return false;

	exists = false;
	attributes = null;
	notifyFolderRenamedListeners(f);
	return true;
    }

    /**
     * Open this folder in the given mode.
     */
    public synchronized void open(int mode) throws MessagingException {
	checkClosed(); // insure that we are not already open
	
	MailboxInfo mi = null;
	// Request store for our own protocol connection.
	protocol = ((IMAPStore)store).getProtocol(this);

	CommandFailedException exc = null;
    lock:
	synchronized(messageCacheLock) { // Acquire messageCacheLock

	    /*
	     * Add response handler right away so we get any alerts or
	     * notifications that occur during the SELECT or EXAMINE.
	     * Have to be sure to remove it if we fail to open the
	     * folder.
	     */
	    protocol.addResponseHandler(this);

	    try {
		if (mode == READ_ONLY)
		    mi = protocol.examine(fullName);
		else
		    mi = protocol.select(fullName);
	    } catch (CommandFailedException cex) {
		// got a NO; connection still good, return it
		releaseProtocol(true);
		protocol = null;
		exc = cex;
		break lock;
	    } catch (ProtocolException pex) {
		// got a BAD or a BYE; connection may be bad, close it
		try {
		    protocol.logout();
		} catch (ProtocolException pex2) {
		    // ignore
		} finally {
		    releaseProtocol(false);
		    protocol = null;
		    throw new MessagingException(pex.getMessage(), pex);
		}
	    }

	    if (mi.mode != mode) {
		if (mode == READ_WRITE && mi.mode == READ_ONLY &&
			((IMAPStore)store).allowReadOnlySelect()) {
		    ;		// all ok, allow it
		} else {	// otherwise, it's an error
		    try {
			// close mailbox and return connection
			protocol.close();
			releaseProtocol(true);
		    } catch (ProtocolException pex) {
			// something went wrong, close connection
			try {
			    protocol.logout();
			} catch (ProtocolException pex2) {
			    // ignore
			} finally {
			    releaseProtocol(false);
			}
		    } finally {
			protocol = null;
			throw new ReadOnlyFolderException(this,
				      "Cannot open in desired mode");
		    }

		}
            }
	
	    // Initialize stuff.
	    opened = true;
	    reallyClosed = false;
	    this.mode = mi.mode;
	    availableFlags = mi.availableFlags;
	    permanentFlags = mi.permanentFlags;
	    total = realTotal = mi.total;
	    recent = mi.recent;
	    uidvalidity = mi.uidvalidity;
	    uidnext = mi.uidnext;

	    // Create the message cache vector of appropriate size
	    messageCache = new Vector(total);
	    // Fill up the cache with light-weight IMAPMessage objects
	    for (int i = 0; i < total; i++)
		messageCache.addElement(new IMAPMessage(this, i+1, i+1));

	} // Release lock

	/*
	 * Handle SELECT or EXAMINE failure after lock is released.
	 * Try to figure out why the operation failed so we can
	 * report a more reasonable exception.
	 */
	if (exc != null) {
	    checkExists();	// throw exception if folder doesn't exist

	    if ((type & HOLDS_MESSAGES) == 0)
		throw new MessagingException("folder cannot contain messages");
	    throw new MessagingException(exc.getMessage(), exc);
	}

	exists = true;		// if we opened it, it must exist
	attributes = null;	// but we don't yet know its attributes
	type = HOLDS_MESSAGES;	// lacking more info, we know at least this much

	// notify listeners
	notifyConnectionListeners(ConnectionEvent.OPENED);
    }

    /**
     * Prefetch attributes, based on the given FetchProfile.
     */
    public synchronized void fetch(Message[] msgs, FetchProfile fp)
			throws MessagingException {
	checkOpened();
	IMAPMessage.fetch(this, msgs, fp);
    }

    /**
     * Set the specified flags for the given array of messages.
     */
    public synchronized void setFlags(Message[] msgs, Flags flag, boolean value)
			throws MessagingException {
	checkOpened();
	checkFlags(flag); // validate flags

	if (msgs.length == 0) // boundary condition
	    return;

	synchronized(messageCacheLock) {
	    try {
		IMAPProtocol p = getProtocol();
		MessageSet[] ms = Utility.toMessageSet(msgs, null);
		if (ms == null)
		    throw new MessageRemovedException(
					"Messages have been removed");
		p.storeFlags(ms, flag, value);
	    } catch (ConnectionException cex) {
		throw new FolderClosedException(this, cex.getMessage());
	    } catch (ProtocolException pex) {
		throw new MessagingException(pex.getMessage(), pex);
	    }
	}
    }

    /**
     * Close this folder.
     */
    public synchronized void close(boolean expunge) throws MessagingException {
	close(expunge, false);
    }

    /**
     * Close this folder without waiting for the server.
     */
    public synchronized void forceClose() throws MessagingException {
	close(false, true);
    }

    /*
     * Common close method.
     */
    private void close(boolean expunge, boolean force)
				throws MessagingException {
	assert Thread.holdsLock(this);
	synchronized(messageCacheLock) {
	    /*
	     * If we already know we're closed, this is illegal.
	     * Can't use checkOpened() because if we were forcibly
	     * closed asynchronously we just want to complete the
	     * closing here.
	     */
	    if (!opened && reallyClosed)
		throw new IllegalStateException(
		    "This operation is not allowed on a closed folder"
		);

	    reallyClosed = true; // Ok, lets reset

	    // Maybe this folder is already closed, or maybe another
	    // thread which had the messageCacheLock earlier, found
	    // that our server connection is dead and cleaned up
	    // everything ..
	    if (!opened)
		return;

	    try {
		waitIfIdle();
		if (force) {
                    if (debug)
                        out.println("DEBUG: forcing folder " + fullName +
					" to close");
		    if (protocol != null)
			protocol.disconnect();
                } else if (((IMAPStore)store).isConnectionPoolFull()) {
		    // If the connection pool is full, logout the connection
                    if (debug)
                        out.println("DEBUG: pool is full, not adding " +
                            "an Authenticated connection");

		    // If the expunge flag is set, close the folder first.
		    if (expunge)
			protocol.close();

		    if (protocol != null)
			protocol.logout();
                } else {
		    // If the expunge flag is set or we're open read-only we
		    // can just close the folder, otherwise open it read-only
		    // before closing.
                    if (!expunge && mode == READ_WRITE) {
                        try {
                            MailboxInfo mi = protocol.examine(fullName);
                        } catch (ProtocolException pex2) {
                            if (protocol != null)
				protocol.disconnect();
                        }
                    }
		    if (protocol != null)
			protocol.close();
                }
	    } catch (ProtocolException pex) {
		throw new MessagingException(pex.getMessage(), pex);
	    } finally {
		// cleanup if we haven't already
		if (opened)
		    cleanup(true);
	    }
	}
    }

    // NOTE: this method can currently be invoked from close() or
    // from handleResponses(). Both invocations are conditional,
    // based on the "opened" flag, so we are sure that multiple
    // Connection.CLOSED events are not generated. Also both
    // invocations are from within messageCacheLock-ed areas.
    private void cleanup(boolean returnToPool) {
        releaseProtocol(returnToPool);
        protocol = null;
	messageCache = null;
	uidTable = null;
	exists = false; // to force a recheck in exists().
	attributes = null;
        opened = false;
	idleState = RUNNING;	// just in case
	notifyConnectionListeners(ConnectionEvent.CLOSED);
    }

    /**
     * Check whether this connection is really open.
     */
    public synchronized boolean isOpen() {
	synchronized(messageCacheLock) {
	    // Probe the connection to make sure its really open.
	    if (opened) {
		try {
		    keepConnectionAlive(false);
		} catch (ProtocolException pex) { }
	    }
	}

	return opened;
    }

    /**
     * Return the permanent flags supported by the server.
     */
    public synchronized Flags getPermanentFlags() {
	return (Flags)(permanentFlags.clone());
    }

    /**
     * Get the total message count.
     */
    public synchronized int getMessageCount() throws MessagingException {
	if (!opened) {
	    checkExists();
	    // If this folder is not yet open, we use STATUS to
	    // get the total message count
	    try {
		Status status = getStatus();
		return status.total;
	    } catch (BadCommandException bex) {
		// doesn't support STATUS, probably vanilla IMAP4 ..
		// lets try EXAMINE
                IMAPProtocol p = null;

	        try {
	            p = getStoreProtocol();	// XXX
		    MailboxInfo minfo = p.examine(fullName);
		    p.close();
		    return minfo.total;
		} catch (ProtocolException pex) {
		    // Give up.
		    throw new MessagingException(pex.getMessage(), pex);

⌨️ 快捷键说明

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