Search in sources :

Example 1 with MailInputStream

use of com.zimbra.cs.mailclient.MailInputStream 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)

Aggregations

MailInputStream (com.zimbra.cs.mailclient.MailInputStream)1 ImapConnection (com.zimbra.cs.mailclient.imap.ImapConnection)1 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 IOException (java.io.IOException)1 OutputStream (java.io.OutputStream)1