169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki/*
269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * Copyright (C) 2010 The Android Open Source Project
369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki *
469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * Licensed under the Apache License, Version 2.0 (the "License");
569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * you may not use this file except in compliance with the License.
669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * You may obtain a copy of the License at
769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki *
869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki *      http://www.apache.org/licenses/LICENSE-2.0
969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki *
1069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * Unless required by applicable law or agreed to in writing, software
1169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * distributed under the License is distributed on an "AS IS" BASIS,
1269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * See the License for the specific language governing permissions and
1469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * limitations under the License.
1569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki */
1669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
1769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onukipackage com.android.email.mail.transport;
1869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
1931d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.Logging;
20560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils;
2169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
2269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onukiimport java.util.ArrayList;
2369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
2469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki/**
2569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * A class to keep last N of lines sent to the server and responses received from the server.
2669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * They are sent to logcat when {@link #logLastDiscourse} is called.
2769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki *
2869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * <p>This class is used to log the recent network activities when a response parser crashes.
2969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki */
3069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onukipublic class DiscourseLogger {
3169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private final int mBufferSize;
3269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private String[] mBuffer;
3369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private int mPos;
3469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private final StringBuilder mReceivingLine = new StringBuilder(100);
3569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
3669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    public DiscourseLogger(int bufferSize) {
3769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        mBufferSize = bufferSize;
3869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        initBuffer();
3969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
4069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
4169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private void initBuffer() {
4269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        mBuffer = new String[mBufferSize];
4369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
4469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
4569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /** Add a single line to {@link #mBuffer}. */
4669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private void addLine(String s) {
4769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        mBuffer[mPos] = s;
4869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        mPos++;
4969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        if (mPos >= mBufferSize) {
5069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            mPos = 0;
5169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
5269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
5369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
5469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private void addReceivingLineToBuffer() {
5569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        if (mReceivingLine.length() > 0) {
5669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            addLine(mReceivingLine.toString());
5769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            mReceivingLine.delete(0, Integer.MAX_VALUE);
5869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
5969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
6069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
6169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /**
6269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     * Store a single byte received from the server in {@link #mReceivingLine}.  When LF is
6369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     * received, the content of {@link #mReceivingLine} is added to {@link #mBuffer}.
6469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     */
6569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    public void addReceivedByte(int b) {
6669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        if (0x20 <= b && b <= 0x7e) { // Append only printable ASCII chars.
6769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            mReceivingLine.append((char) b);
6869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        } else if (b == '\n') { // LF
6969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            addReceivingLineToBuffer();
7069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        } else if (b == '\r') { // CR
7169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        } else {
7269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            final String hex = "00" + Integer.toHexString(b);
7369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            mReceivingLine.append("\\x" + hex.substring(hex.length() - 2, hex.length()));
7469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
7569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
7669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
7769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /** Add a line sent to the server to {@link #mBuffer}. */
7869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    public void addSentCommand(String command) {
7969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        addLine(command);
8069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
8169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
8269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /** @return the contents of {@link #mBuffer} as a String array. */
8369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /* package for testing */ String[] getLines() {
8469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        addReceivingLineToBuffer();
8569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
8669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        ArrayList<String> list = new ArrayList<String>();
8769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
8869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        final int start = mPos;
8969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        int pos = mPos;
9069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        do {
9169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            String s = mBuffer[pos];
9269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            if (s != null) {
9369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki                list.add(s);
9469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            }
9569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            pos = (pos + 1) % mBufferSize;
9669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        } while (pos != start);
9769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
9869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        String[] ret = new String[list.size()];
9969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        list.toArray(ret);
10069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        return ret;
10169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
10269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
10369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /**
10469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     * Log the contents of the {@link mBuffer}, and clears it out.  (So it's okay to call this
10569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     * method successively more than once.  There will be no duplicate log.)
10669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     */
10769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    public void logLastDiscourse() {
10869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        String[] lines = getLines();
10969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        if (lines.length == 0) {
11069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            return;
11169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
11269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
113560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy        LogUtils.w(Logging.LOG_TAG, "Last network activities:");
11469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        for (String r : getLines()) {
1155a3fe57f4e13125a050948a7a5abf629f431f60bPaul Westbrook            LogUtils.w(Logging.LOG_TAG, "%s", r);
11669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
11769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        initBuffer();
11869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
11969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki}
120