1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.emailcommon.utility;
18
19import com.android.emailcommon.Logging;
20import com.android.mail.utils.LogUtils;
21
22import java.io.FilterInputStream;
23import java.io.IOException;
24import java.io.InputStream;
25
26/**
27 * Simple class used for debugging only that affords us a view of the raw IMAP or POP3 stream,
28 * in addition to the tokenized version.
29 *
30 * Use of this class *MUST* be restricted to logging-enabled situations only.
31 */
32public class LoggingInputStream extends FilterInputStream {
33    private StringBuilder mSb;
34    private boolean mDumpEmptyLines;
35    private final String mTag;
36
37    public LoggingInputStream(InputStream in) {
38        this(in, "RAW", false);
39    }
40
41    public LoggingInputStream(InputStream in, String tag, boolean dumpEmptyLines) {
42        super(in);
43        mTag = tag + " ";
44        mDumpEmptyLines = dumpEmptyLines;
45        initBuffer();
46        LogUtils.d(Logging.LOG_TAG, mTag + "dump start");
47    }
48
49    private void initBuffer() {
50        mSb = new StringBuilder(mTag);
51    }
52
53    /**
54     * Collect chars as read, and log them when EOL reached.
55     */
56    @Override
57    public int read() throws IOException {
58        int oneByte = super.read();
59        logRaw(oneByte);
60        return oneByte;
61    }
62
63    /**
64     * Collect chars as read, and log them when EOL reached.
65     */
66    @Override
67    public int read(byte[] b, int offset, int length) throws IOException {
68        int bytesRead = super.read(b, offset, length);
69        int copyBytes = bytesRead;
70        while (copyBytes > 0) {
71            logRaw(b[offset] & 0xFF);
72            copyBytes--;
73            offset++;
74        }
75
76        return bytesRead;
77    }
78
79    /**
80     * Write and clear the buffer
81     */
82    private void logRaw(int oneByte) {
83        if (oneByte == '\r') {
84            // Don't log.
85        } else if (oneByte == '\n') {
86            flushLog();
87        } else if (0x20 <= oneByte && oneByte <= 0x7e) { // Printable ASCII.
88            mSb.append((char)oneByte);
89        } else {
90            // email protocols are supposed to be all 7bits, but there are wrong implementations
91            // that do send 8 bit characters...
92            mSb.append("\\x" + Utility.byteToHex(oneByte));
93        }
94    }
95
96    private void flushLog() {
97        if (mDumpEmptyLines || (mSb.length() > mTag.length())) {
98            LogUtils.d(Logging.LOG_TAG, mSb.toString());
99            initBuffer();
100        }
101    }
102
103    @Override
104    public void close() throws IOException {
105        super.close();
106        flushLog();
107    }
108}
109