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 + -
显示快捷键?