boolean idle(final ImapRequest req, final boolean begin) throws IOException { if (begin == ImapHandler.IDLE_STOP) { // check state -- don't want to send DONE if we're somehow not in IDLE ImapHandler handler = mHandler; if (handler == null) throw new IOException("proxy connection already closed"); Thread idle = mIdleThread; if (idle == null) throw new IOException("bad proxy state: no IDLE thread active when attempting DONE"); // send the DONE, which elicits the tagged response that causes the IDLE thread (below) to // exit writeRequest(req.toByteArray()); // make sure that the idle thread actually exits; otherwise we're in a bad place and we must // kill the whole session mIdleThread = null; try { idle.join(5 * Constants.MILLIS_PER_SECOND); } catch (InterruptedException ie) { } if (idle.isAlive()) handler.dropConnection(false); } else { final ImapHandler handler = mHandler; final ImapConnection conn = mConnection; if (conn == null) throw new IOException("proxy connection already closed"); ImapConfig config = conn.getImapConfig(); final int oldTimeout = config != null ? config.getReadTimeout() : LC.javamail_imap_timeout.intValue(); // necessary because of subsequent race condition with req.cleanup() final byte[] payload = req.toByteArray(); mIdleThread = new Thread() { @Override public void run() { boolean success = false; try { // the standard aggressive read timeout is inappropriate for IDLE conn.setReadTimeout(mHandler.getConfig().getAuthenticatedMaxIdleSeconds()); // send the IDLE command; this call waits until the subsequent DONE is acknowledged boolean ok = proxyCommand(req.getTag(), payload, true, true); // restore the old read timeout conn.setReadTimeout(oldTimeout); // don't set <code>success</code> until we're past things that can throw // IOExceptions success = ok; } catch (IOException e) { ZimbraLog.imap.warn("error encountered during IDLE; dropping connection", e); } if (!success) handler.dropConnection(); } }; mIdleThread.setName("Imap-Idle-Proxy-" + Thread.currentThread().getName()); mIdleThread.start(); } return true; }
/** * Proxies the request to the remote server and writes all tagged and untagged responses back to * the handler's output stream. * * @return <tt>true</tt> in all cases. */ boolean proxy(final ImapRequest req) throws IOException { proxyCommand(req.getTag(), req.toByteArray(), true, false); return true; }