Search in sources :

Example 1 with ImapConnection

use of com.zimbra.cs.mailclient.imap.ImapConnection in project zm-mailbox by Zimbra.

the class ImapProxy method proxyCommand.

private boolean proxyCommand(byte[] payload, boolean includeTaggedResponse, boolean isIdle) throws ImapProxyException {
    ImapConnection conn = writeRequest(payload);
    MailInputStream min = conn.getInputStream();
    OutputStream out = handler.output;
    if (out == null) {
        dropConnection();
        throw new ImapProxyException("client connection already closed");
    }
    // copy the response back to the handler's output (i.e. the original client)
    boolean success = false;
    int first;
    try {
        while ((first = min.peek()) != -1) {
            // XXX: may want to check that the "tagged" response's tag actually matches the request's tag...
            boolean tagged = first != '*' && first != '+';
            boolean structured = first == '*';
            boolean proxy = (first != '+' || isIdle) && (!tagged || includeTaggedResponse);
            ByteArrayOutputStream line = proxy ? new ByteArrayOutputStream() : null;
            StringBuilder debug = proxy && ZimbraLog.imap.isDebugEnabled() ? new StringBuilder("  pxy: ") : null;
            StringBuilder condition = new StringBuilder(10);
            boolean quoted = false;
            boolean escaped = false;
            boolean space1 = false;
            boolean space2 = false;
            int c;
            int literal = -1;
            while ((c = min.read()) != -1) {
                // check for success and also determine whether we should be paying attention to structure
                if (!space2) {
                    if (c == ' ' && !space1) {
                        space1 = true;
                    } else if (c == ' ') {
                        space2 = true;
                        String code = condition.toString().toUpperCase();
                        if ("BYE".equals(code)) {
                            // unexpected BYE
                            dropConnection();
                            throw new ImapProxyException("proxy connection already closed");
                        }
                        if (tagged) {
                            success = "OK".equals(code) || (isIdle && "BAD".equals(code));
                        }
                        structured &= !UNSTRUCTURED_CODES.contains(code);
                    } else if (space1) {
                        condition.append((char) c);
                    }
                }
                // if it's a structured response, pay attention to quoting, literals, etc.
                if (structured) {
                    if (escaped)
                        escaped = false;
                    else if (quoted && c == '\\')
                        escaped = true;
                    else if (c == '"')
                        quoted = !quoted;
                    else if (!quoted && c == '{')
                        literal = 0;
                    else if (literal != -1 && c >= '0' && c <= '9')
                        literal = literal * 10 + (c - '0');
                }
                if (!quoted && c == '\r' && min.peek() == '\n') {
                    // skip the terminal LF
                    min.read();
                    // write the line back to the client
                    if (proxy) {
                        out.write(line.toByteArray());
                        out.write(ImapHandler.LINE_SEPARATOR_BYTES);
                        line.reset();
                        if (isIdle)
                            out.flush();
                    }
                    // if it's end of line (i.e. no literal), we're done
                    if (literal == -1)
                        break;
                    // if there's a literal, copy it and then handle the following line
                    byte[] buffer = literal == 0 ? null : new byte[Math.min(literal, 65536)];
                    while (literal > 0) {
                        int read = min.read(buffer, 0, Math.min(literal, buffer.length));
                        if (read == -1)
                            break;
                        if (proxy)
                            out.write(buffer, 0, read);
                        literal -= read;
                    }
                    literal = -1;
                    if (isIdle)
                        out.flush();
                } else if (proxy) {
                    line.write(c);
                    if (debug != null)
                        debug.append((char) c);
                }
            }
            if (debug != null)
                ZimbraLog.imap.debug(debug.toString());
            if (tagged)
                break;
        }
        out.flush();
    } catch (ImapProxyException e) {
        throw e;
    } catch (IOException e) {
        throw new ImapProxyException(e);
    }
    return success;
}
Also used : MailInputStream(com.zimbra.cs.mailclient.MailInputStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) OutputStream(java.io.OutputStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) ImapConnection(com.zimbra.cs.mailclient.imap.ImapConnection)

Example 2 with ImapConnection

use of com.zimbra.cs.mailclient.imap.ImapConnection in project zm-mailbox by Zimbra.

the class ImapFolderSync method refetchPurgedMsgsInConversation.

protected void refetchPurgedMsgsInConversation(ParsedMessage pm) throws ServiceException, IOException {
    if (!mailbox.getAccount().isFeatureDataSourcePurgingEnabled()) {
        return;
    }
    Threader threader = pm.getThreader(ds.getMailbox());
    List<PurgedConversation> purgedConvs = threader.lookupPurgedConversations(ds);
    if (purgedConvs.size() == 0) {
        return;
    } else {
        for (PurgedConversation conv : purgedConvs) {
            ImapConnection conn;
            try {
                conn = getRefetchConnection();
            } catch (ServiceException e) {
                ZimbraLog.datasource.warn("could not establish IMAP connection to refetch purged messages");
                return;
            }
            for (PurgedMessage msg : conv.getMessages()) {
                String remoteFolderId = msg.getRemoteFolder();
                String msgUid = msg.getUid();
                final Integer folderId = msg.getLocalFolderId();
                ZimbraLog.datasource.info("restoring message " + msgUid + " in remote folder " + remoteFolderId);
                conn.select(remoteFolderId);
                final Map<Long, MessageData> msgFlags = conn.uidFetch(msgUid, "(FLAGS INTERNALDATE)");
                FetchResponseHandler handler = new FetchResponseHandler() {

                    @Override
                    public void handleFetchResponse(MessageData md) throws Exception {
                        long uid = md.getUid();
                        IOExceptionHandler.getInstance().trackSyncItem(mailbox, uid);
                        try {
                            handleFetch(md, msgFlags, folderId, false, false);
                            clearError(uid);
                        } catch (OutOfMemoryError e) {
                            Zimbra.halt("Out of memory", e);
                        } catch (Exception e) {
                            if (!IOExceptionHandler.getInstance().isRecoverable(mailbox, uid, "Exception re-fetching UID " + uid, e)) {
                                syncFailed("re-fetch failed for uid " + uid, e);
                                SyncErrorManager.incrementErrorCount(ds, remoteId(uid));
                            }
                        }
                    }
                };
                conn.uidFetch(msgUid, "BODY.PEEK[]", handler);
            }
            conv.unpurge();
        }
    }
}
Also used : MessageData(com.zimbra.cs.mailclient.imap.MessageData) Threader(com.zimbra.cs.mailbox.Threader) ImapConnection(com.zimbra.cs.mailclient.imap.ImapConnection) MailException(com.zimbra.cs.mailclient.MailException) ServiceException(com.zimbra.common.service.ServiceException) SQLException(java.sql.SQLException) CommandFailedException(com.zimbra.cs.mailclient.CommandFailedException) IOException(java.io.IOException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) RemoteServiceException(com.zimbra.common.service.RemoteServiceException) PurgedConversation(com.zimbra.cs.db.DbDataSource.PurgedConversation) PurgedMessage(com.zimbra.cs.db.DbDataSource.PurgedMessage) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) RemoteServiceException(com.zimbra.common.service.RemoteServiceException) FetchResponseHandler(com.zimbra.cs.mailclient.imap.FetchResponseHandler)

Example 3 with ImapConnection

use of com.zimbra.cs.mailclient.imap.ImapConnection in project zm-mailbox by Zimbra.

the class ConnectionManager method closeConnection.

/**
 * Closes any suspended connection associated with specified data source.
 * This must be called whenever data source is modified or deleted in order
 * to force a reconnect upon next use.
 *
 * @param dataSourceId the data source id for the connection
 */
public void closeConnection(String dataSourceId) {
    ImapConnection ic = connections.remove(dataSourceId);
    if (ic != null) {
        LOG.debug("Closing connection: " + ic);
        ic.close();
    }
}
Also used : ImapConnection(com.zimbra.cs.mailclient.imap.ImapConnection)

Example 4 with ImapConnection

use of com.zimbra.cs.mailclient.imap.ImapConnection in project zm-mailbox by Zimbra.

the class ConnectionManager method openConnection.

/**
 * Opens a new IMAP connection or reuses an existing one if available
 * for specified data source. If a new connection is required the optional
 * authenticator, if specified, will be used with AUTHENTICATE, otherwise
 * the LOGIN command will be used. If a suspended connection is reused
 * and has been idling, then IDLE will be automatically terminated.
 *
 * @param ds the data source for the connection
 * @param auth optional authenticator, or null to use LOGIN
 * @return the IMAP connection to use
 * @throws ServiceException if an I/O or auth error occurred
 */
public ImapConnection openConnection(DataSource ds, Authenticator auth) throws ServiceException {
    ImapConnection ic = connections.remove(ds.getId());
    if (ic == null || !resumeConnection(ic)) {
        ic = newConnection(ds, auth);
    }
    ic.getImapConfig().setMaxLiteralMemSize(ds.getMaxTraceSize());
    return ic;
}
Also used : ImapConnection(com.zimbra.cs.mailclient.imap.ImapConnection)

Example 5 with ImapConnection

use of com.zimbra.cs.mailclient.imap.ImapConnection in project zm-mailbox by Zimbra.

the class ConnectionManager method releaseConnection.

/**
 * Releases existing connection so that it can be reused again. If the
 * IMAP server supports IDLE then the connection will go into IDLE state.
 * Otherwise, the connection will be kept active for as long as possible.
 *
 * @param ds the data source for the connection
 * @param ic the connection to release
 */
public void releaseConnection(DataSource ds, ImapConnection ic) {
    LOG.debug("Releasing connection: " + ic);
    if (isReuseConnections(ds) && suspendConnection(ds, ic)) {
        ImapConnection conn = connections.put(ds.getId(), ic);
        if (conn != null) {
            LOG.debug("More than one suspended connection for: %s. closing the oldest: %s", ds, conn);
            // there was another suspended connection; just close it
            conn.close();
        }
    } else {
        LOG.debug("Closing connection: " + ic);
        ic.close();
    }
}
Also used : ImapConnection(com.zimbra.cs.mailclient.imap.ImapConnection)

Aggregations

ImapConnection (com.zimbra.cs.mailclient.imap.ImapConnection)27 ImapConfig (com.zimbra.cs.mailclient.imap.ImapConfig)11 IOException (java.io.IOException)7 CommandFailedException (com.zimbra.cs.mailclient.CommandFailedException)5 ServiceException (com.zimbra.common.service.ServiceException)4 Test (org.junit.Test)4 Account (com.zimbra.cs.account.Account)2 AuthenticatorFactory (com.zimbra.cs.mailclient.auth.AuthenticatorFactory)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)2 OutputStream (java.io.OutputStream)2 Ignore (org.junit.Ignore)2 LocalConfig (com.zimbra.common.localconfig.LocalConfig)1 RemoteServiceException (com.zimbra.common.service.RemoteServiceException)1 ZMimeMessage (com.zimbra.common.zmime.ZMimeMessage)1 AccountServiceException (com.zimbra.cs.account.AccountServiceException)1 CacheEntry (com.zimbra.cs.account.Provisioning.CacheEntry)1 ImapAppender (com.zimbra.cs.datasource.imap.ImapAppender)1 PurgedConversation (com.zimbra.cs.db.DbDataSource.PurgedConversation)1 PurgedMessage (com.zimbra.cs.db.DbDataSource.PurgedMessage)1 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)1