13469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project/*
23469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
33469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project *
43469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
53469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * you may not use this file except in compliance with the License.
63469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * You may obtain a copy of the License at
73469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project *
83469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
93469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project *
103469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
113469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
123469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * See the License for the specific language governing permissions and
143469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * limitations under the License.
153469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project */
163469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1731d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankpackage com.android.emailcommon.utility;
183469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
1931d9acbf0623872f9d4a2b3210b5970854b654c7Marc Blankimport com.android.emailcommon.Logging;
20560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils;
213469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
22dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onukiimport java.io.FilterInputStream;
233469902379242c723b871d1dcb09b02d0998d538The Android Open Source Projectimport java.io.IOException;
243469902379242c723b871d1dcb09b02d0998d538The Android Open Source Projectimport java.io.InputStream;
253469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
263469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project/**
273469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * Simple class used for debugging only that affords us a view of the raw IMAP or POP3 stream,
283469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * in addition to the tokenized version.
29560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy *
303469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project * Use of this class *MUST* be restricted to logging-enabled situations only.
313469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project */
32dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onukipublic class LoggingInputStream extends FilterInputStream {
33dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    private StringBuilder mSb;
34dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    private boolean mDumpEmptyLines;
35dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    private final String mTag;
363469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
373469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    public LoggingInputStream(InputStream in) {
38dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        this(in, "RAW", false);
39dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    }
40dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki
41dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    public LoggingInputStream(InputStream in, String tag, boolean dumpEmptyLines) {
42dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        super(in);
43dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        mTag = tag + " ";
44dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        mDumpEmptyLines = dumpEmptyLines;
45dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        initBuffer();
46560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy        LogUtils.d(Logging.LOG_TAG, mTag + "dump start");
47dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    }
48dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki
49dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    private void initBuffer() {
50dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        mSb = new StringBuilder(mTag);
513469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    }
523469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
533469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    /**
543469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     * Collect chars as read, and log them when EOL reached.
553469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     */
563469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    @Override
573469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    public int read() throws IOException {
58dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        int oneByte = super.read();
593469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        logRaw(oneByte);
603469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        return oneByte;
613469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    }
623469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
633469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    /**
643469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     * Collect chars as read, and log them when EOL reached.
653469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     */
663469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    @Override
673469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    public int read(byte[] b, int offset, int length) throws IOException {
68dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        int bytesRead = super.read(b, offset, length);
693469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        int copyBytes = bytesRead;
703469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        while (copyBytes > 0) {
71dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki            logRaw(b[offset] & 0xFF);
723469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project            copyBytes--;
733469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project            offset++;
743469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        }
753469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
763469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        return bytesRead;
773469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    }
783469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project
793469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    /**
803469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     * Write and clear the buffer
813469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project     */
823469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    private void logRaw(int oneByte) {
83dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        if (oneByte == '\r') {
84dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki            // Don't log.
85dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        } else if (oneByte == '\n') {
86dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki            flushLog();
87dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        } else if (0x20 <= oneByte && oneByte <= 0x7e) { // Printable ASCII.
883469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project            mSb.append((char)oneByte);
89dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        } else {
90dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki            // email protocols are supposed to be all 7bits, but there are wrong implementations
91dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki            // that do send 8 bit characters...
92dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki            mSb.append("\\x" + Utility.byteToHex(oneByte));
933469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project        }
943469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project    }
95dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki
96dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    private void flushLog() {
97dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        if (mDumpEmptyLines || (mSb.length() > mTag.length())) {
98560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy            LogUtils.d(Logging.LOG_TAG, mSb.toString());
99dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki            initBuffer();
100dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        }
101dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    }
102dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki
103dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    @Override
104dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    public void close() throws IOException {
105dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        super.close();
106dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki        flushLog();
107dfeb1184ebf6c59fc6e617149e03edb73b7e0df7Makoto Onuki    }
1083469902379242c723b871d1dcb09b02d0998d538The Android Open Source Project}
109