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;
2069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
2169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onukiimport android.util.Log;
2269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
2369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onukiimport java.util.ArrayList;
2469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
2569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki/**
2669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * A class to keep last N of lines sent to the server and responses received from the server.
2769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * They are sent to logcat when {@link #logLastDiscourse} is called.
2869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki *
2969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki * <p>This class is used to log the recent network activities when a response parser crashes.
3069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki */
3169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onukipublic class DiscourseLogger {
3269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private final int mBufferSize;
3369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private String[] mBuffer;
3469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private int mPos;
3569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private final StringBuilder mReceivingLine = new StringBuilder(100);
3669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
3769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    public DiscourseLogger(int bufferSize) {
3869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        mBufferSize = bufferSize;
3969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        initBuffer();
4069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
4169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
4269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private void initBuffer() {
4369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        mBuffer = new String[mBufferSize];
4469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
4569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
4669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /** Add a single line to {@link #mBuffer}. */
4769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private void addLine(String s) {
4869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        mBuffer[mPos] = s;
4969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        mPos++;
5069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        if (mPos >= mBufferSize) {
5169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            mPos = 0;
5269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
5369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
5469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
5569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    private void addReceivingLineToBuffer() {
5669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        if (mReceivingLine.length() > 0) {
5769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            addLine(mReceivingLine.toString());
5869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            mReceivingLine.delete(0, Integer.MAX_VALUE);
5969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
6069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
6169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
6269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /**
6369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     * Store a single byte received from the server in {@link #mReceivingLine}.  When LF is
6469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     * received, the content of {@link #mReceivingLine} is added to {@link #mBuffer}.
6569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     */
6669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    public void addReceivedByte(int b) {
6769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        if (0x20 <= b && b <= 0x7e) { // Append only printable ASCII chars.
6869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            mReceivingLine.append((char) b);
6969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        } else if (b == '\n') { // LF
7069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            addReceivingLineToBuffer();
7169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        } else if (b == '\r') { // CR
7269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        } else {
7369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            final String hex = "00" + Integer.toHexString(b);
7469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            mReceivingLine.append("\\x" + hex.substring(hex.length() - 2, hex.length()));
7569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
7669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
7769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
7869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /** Add a line sent to the server to {@link #mBuffer}. */
7969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    public void addSentCommand(String command) {
8069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        addLine(command);
8169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
8269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
8369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /** @return the contents of {@link #mBuffer} as a String array. */
8469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /* package for testing */ String[] getLines() {
8569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        addReceivingLineToBuffer();
8669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
8769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        ArrayList<String> list = new ArrayList<String>();
8869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
8969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        final int start = mPos;
9069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        int pos = mPos;
9169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        do {
9269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            String s = mBuffer[pos];
9369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            if (s != null) {
9469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki                list.add(s);
9569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            }
9669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            pos = (pos + 1) % mBufferSize;
9769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        } while (pos != start);
9869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
9969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        String[] ret = new String[list.size()];
10069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        list.toArray(ret);
10169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        return ret;
10269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
10369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
10469ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    /**
10569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     * Log the contents of the {@link mBuffer}, and clears it out.  (So it's okay to call this
10669ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     * method successively more than once.  There will be no duplicate log.)
10769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki     */
10869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    public void logLastDiscourse() {
10969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        String[] lines = getLines();
11069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        if (lines.length == 0) {
11169ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki            return;
11269ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
11369ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki
11431d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank        Log.w(Logging.LOG_TAG, "Last network activities:");
11569ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        for (String r : getLines()) {
11631d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blank            Log.w(Logging.LOG_TAG, r);
11769ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        }
11869ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki        initBuffer();
11969ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki    }
12069ade70f2d0857f4eadae97734ee8891e77895cbMakoto Onuki}
121