📄 imapstore.java
字号:
// folder-connection pool locking hierarchy. synchronized (pool) { if (pool.folders != null) { done = false; foldersCopy = pool.folders; pool.folders = null; } else { done = true; } } if (done) break; // Close and remove any open folders under this Store. for (int i = 0, fsize = foldersCopy.size(); i < fsize; i++) { IMAPFolder f = (IMAPFolder)foldersCopy.elementAt(i); try { if (force) { if (debug) out.println("DEBUG: force folder to close"); // Don't want to wait for folder connection to timeout // (if, for example, the server is down) so we close // folders abruptly. f.forceClose(); } else { if (debug) out.println("DEBUG: close folder"); f.close(false); } } catch (MessagingException mex) { // Who cares ?! Ignore 'em. } catch (IllegalStateException ex) { // Ditto } } } synchronized (pool) { emptyConnectionPool(force); } connected = false; notifyConnectionListeners(ConnectionEvent.CLOSED); if (debug) out.println("DEBUG: IMAPStore cleanup done"); } /** * Get the default folder, representing the root of this user's * namespace. Returns a closed DefaultFolder object. */ public synchronized Folder getDefaultFolder() throws MessagingException { checkConnected(); return new DefaultFolder(this); } /** * Get named folder. Returns a new, closed IMAPFolder. */ public synchronized Folder getFolder(String name) throws MessagingException { checkConnected(); return new IMAPFolder(name, IMAPFolder.UNKNOWN_SEPARATOR, this); } /** * Get named folder. Returns a new, closed IMAPFolder. */ public synchronized Folder getFolder(URLName url) throws MessagingException { checkConnected(); return new IMAPFolder(url.getFile(), IMAPFolder.UNKNOWN_SEPARATOR, this); } /** * Using the IMAP NAMESPACE command (RFC 2342), return a set * of folders representing the Personal namespaces. */ public Folder[] getPersonalNamespaces() throws MessagingException { Namespaces ns = getNamespaces(); if (ns == null || ns.personal == null) return super.getPersonalNamespaces(); return namespaceToFolders(ns.personal, null); } /** * Using the IMAP NAMESPACE command (RFC 2342), return a set * of folders representing the User's namespaces. */ public Folder[] getUserNamespaces(String user) throws MessagingException { Namespaces ns = getNamespaces(); if (ns == null || ns.otherUsers == null) return super.getUserNamespaces(user); return namespaceToFolders(ns.otherUsers, user); } /** * Using the IMAP NAMESPACE command (RFC 2342), return a set * of folders representing the Shared namespaces. */ public Folder[] getSharedNamespaces() throws MessagingException { Namespaces ns = getNamespaces(); if (ns == null || ns.shared == null) return super.getSharedNamespaces(); return namespaceToFolders(ns.shared, null); } private synchronized Namespaces getNamespaces() throws MessagingException { checkConnected(); IMAPProtocol p = null; if (namespaces == null) { try { p = getStoreProtocol(); namespaces = p.namespace(); } catch (BadCommandException bex) { // NAMESPACE not supported, ignore it } catch (ConnectionException cex) { throw new StoreClosedException(this, cex.getMessage()); } catch (ProtocolException pex) { throw new MessagingException(pex.getMessage(), pex); } finally { releaseStoreProtocol(p); if (p == null) { // failed to get a Store connection // have to force Store to be closed cleanup(); } } } return namespaces; } private Folder[] namespaceToFolders(Namespaces.Namespace[] ns, String user) { Folder[] fa = new Folder[ns.length]; for (int i = 0; i < fa.length; i++) { String name = ns[i].prefix; if (user == null) { // strip trailing delimiter int len = name.length(); if ( len > 0 && name.charAt(len - 1) == ns[i].delimiter) name = name.substring(0, len - 1); } else { // add user name += user; } fa[i] = new IMAPFolder(name, ns[i].delimiter, this, user == null); } return fa; } /** * Get the quotas for the named quota root. * Quotas are controlled on the basis of a quota root, not * (necessarily) a folder. The relationship between folders * and quota roots depends on the IMAP server. Some servers * might implement a single quota root for all folders owned by * a user. Other servers might implement a separate quota root * for each folder. A single folder can even have multiple * quota roots, perhaps controlling quotas for different * resources. * * @param root the name of the quota root * @return array of Quota objects * @exception MessagingException if the server doesn't support the * QUOTA extension */ public synchronized Quota[] getQuota(String root) throws MessagingException { checkConnected(); Quota[] qa = null; IMAPProtocol p = null; try { p = getStoreProtocol(); qa = p.getQuotaRoot(root); } catch (BadCommandException bex) { throw new MessagingException("QUOTA not supported", bex); } catch (ConnectionException cex) { throw new StoreClosedException(this, cex.getMessage()); } catch (ProtocolException pex) { throw new MessagingException(pex.getMessage(), pex); } finally { releaseStoreProtocol(p); if (p == null) { // failed to get a Store connection // have to force Store to be closed cleanup(); } } return qa; } /** * Set the quotas for the quota root specified in the quota argument. * Typically this will be one of the quota roots obtained from the * <code>getQuota</code> method, but it need not be. * * @param quota the quota to set * @exception MessagingException if the server doesn't support the * QUOTA extension */ public synchronized void setQuota(Quota quota) throws MessagingException { checkConnected(); IMAPProtocol p = null; try { p = getStoreProtocol(); p.setQuota(quota); } catch (BadCommandException bex) { throw new MessagingException("QUOTA not supported", bex); } catch (ConnectionException cex) { throw new StoreClosedException(this, cex.getMessage()); } catch (ProtocolException pex) { throw new MessagingException(pex.getMessage(), pex); } finally { releaseStoreProtocol(p); if (p == null) { // failed to get a Store connection // have to force Store to be closed cleanup(); } } } private void checkConnected() { assert Thread.holdsLock(this); if (!connected) { super.setConnected(false); // just in case throw new IllegalStateException("Not connected"); } } /** * Response handler method. */ public void handleResponse(Response r) { // Any of these responses may have a response code. if (r.isOK() || r.isNO() || r.isBAD() || r.isBYE()) handleResponseCode(r); if (r.isBYE()) { if (debug) out.println("DEBUG: IMAPStore connection dead"); // Store's IMAP connection is dead, cleanup. if (connected) // Check if its already closed cleanup(r.isSynthetic()); return; } } /** * Use the IMAP IDLE command (see * <A HREF="http://www.ietf.org/rfc/rfc2177.txt">RFC 2177</A>), * if supported by the server, to enter idle mode so that the server * can send unsolicited notifications * without the need for the client to constantly poll the server. * Use a <code>ConnectionListener</code> to be notified of * events. When another thread (e.g., the listener thread) * needs to issue an IMAP comand for this Store, the idle mode will * be terminated and this method will return. Typically the caller * will invoke this method in a loop. <p> * * If the mail.imap.enableimapevents property is set, notifications * received while the IDLE command is active will be delivered to * <code>ConnectionListener</code>s as events with a type of * <code>IMAPStore.RESPONSE</code>. The event's message will be * the raw IMAP response string. * Note that most IMAP servers will not deliver any events when * using the IDLE command on a connection with no mailbox selected * (i.e., this method). In most cases you'll want to use the * <code>idle</code> method on <code>IMAPFolder</code>. <p> * * NOTE: This capability is highly experimental and likely will change * in future releases. <p> * * The mail.imap.minidletime property enforces a minimum delay * before returning from this method, to ensure that other threads * have a chance to issue commands before the caller invokes this * method again. The default delay is 10 milliseconds. * * @exception MessagingException if the server doesn't support the * IDLE extension * @exception IllegalStateException if the store isn't connected * * @since JavaMail 1.4.1 */ public void idle() throws MessagingException { IMAPProtocol p = null; // ASSERT: Must NOT be called with the connection pool // synchronization lock held. assert !Thread.holdsLock(pool); synchronized (this) { checkConnected(); } try { synchronized (pool) { p = getStoreProtocol(); if (pool.idleState == ConnectionPool.RUNNING) { p.idleStart(); pool.idleState = ConnectionPool.IDLE; } else { // some other thread must be running the IDLE // command, we'll just wait for it to finish // without aborting it ourselves try { // give up lock and wait to be not idle pool.wait(); } catch (InterruptedException ex) { } return; } pool.idleProtocol = p; } /* * We gave up the pool lock so that other threads * can get into the pool far enough to see that we're * in IDLE and abort the IDLE. * * Now we read responses from the IDLE command, especially * including unsolicited notifications from the server. * We don't hold the pool lock while reading because * it protects the idleState and other threads need to be * able to examine the state. * * We hold the pool lock while processing the responses. */ for (;;) { Response r = p.readIdleResponse(); synchronized (pool) { if (r == null || !p.processIdleResponse(r)) { pool.idleState = ConnectionPool.RUNNING; pool.notifyAll(); break; } } if (enableImapEvents && r.isUnTagged()) { notifyStoreListeners(IMAPStore.RESPONSE, r.toString()); } } /* * Enforce a minimum delay to give time to threads * processing the responses that came in while we * were idle. */ int minidle = getMinIdleTime(); if (minidle > 0) { try { Thread.sleep(minidle); } catch (InterruptedException ex) { } } } catch (BadCommandException bex) { throw new MessagingException("IDLE not supported", bex); } catch (ConnectionException cex) { throw new StoreClosedException(this, cex.getMessage()); } catch (ProtocolException pex) { throw new MessagingException(pex.getMessage(), pex); } finally { synchronized (pool) { pool.idleProtocol = null; } releaseStoreProtocol(p); if (p == null) { // failed to get a Store connection // have to force Store to be closed cleanup(); } } } /* * If an IDLE command is in progress, abort it if necessary, * and wait until it completes. * ASSERT: Must be called with the pool's lock held. */ private void waitIfIdle() throws ProtocolException { assert Thread.holdsLock(pool); while (pool.idleState != ConnectionPool.RUNNING) { if (pool.idleState == ConnectionPool.IDLE) { pool.idleProtocol.idleAbort(); pool.idleState = ConnectionPool.ABORTING; } try { // give up lock and wait to be not idle pool.wait(); } catch (InterruptedException ex) { } } } /** * Handle notifications and alerts. * Response must be an OK, NO, BAD, or BYE response. */ void handleResponseCode(Response r) { String s = r.getRest(); // get the text after the response boolean isAlert = false; if (s.startsWith("[")) { // a response code int i = s.indexOf(']'); // remember if it's an alert if (i > 0 && s.substring(0, i + 1).equalsIgnoreCase("[ALERT]")) isAlert = true; // strip off the response code in any event s = s.substring(i + 1).trim(); } if (isAlert) notifyStoreListeners(StoreEvent.ALERT, s); else if (r.isUnTagged() && s.length() > 0) // Only send notifications that come with untagged // responses, and only if there is actually some // text there. notifyStoreListeners(StoreEvent.NOTICE, s); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -