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;
20
21import android.util.Log;
22
23import java.io.FilterInputStream;
24import java.io.IOException;
25import java.io.InputStream;
26
27/**
28 * Simple class used for debugging only that affords us a view of the raw IMAP or POP3 stream,
29 * in addition to the tokenized version.
30 *
31 * Use of this class *MUST* be restricted to logging-enabled situations only.
32 */
33public class LoggingInputStream extends FilterInputStream {
34    private StringBuilder mSb;
35    private boolean mDumpEmptyLines;
36    private final String mTag;
37
38    public LoggingInputStream(InputStream in) {
39        this(in, "RAW", false);
40    }
41
42    public LoggingInputStream(InputStream in, String tag, boolean dumpEmptyLines) {
43        super(in);
44        mTag = tag + " ";
45        mDumpEmptyLines = dumpEmptyLines;
46        initBuffer();
47        Log.d(Logging.LOG_TAG, mTag + "dump start");
48    }
49
50    private void initBuffer() {
51        mSb = new StringBuilder(mTag);
52    }
53
54    /**
55     * Collect chars as read, and log them when EOL reached.
56     */
57    @Override
58    public int read() throws IOException {
59        int oneByte = super.read();
60        logRaw(oneByte);
61        return oneByte;
62    }
63
64    /**
65     * Collect chars as read, and log them when EOL reached.
66     */
67    @Override
68    public int read(byte[] b, int offset, int length) throws IOException {
69        int bytesRead = super.read(b, offset, length);
70        int copyBytes = bytesRead;
71        while (copyBytes > 0) {
72            logRaw(b[offset] & 0xFF);
73            copyBytes--;
74            offset++;
75        }
76
77        return bytesRead;
78    }
79
80    /**
81     * Write and clear the buffer
82     */
83    private void logRaw(int oneByte) {
84        if (oneByte == '\r') {
85            // Don't log.
86        } else if (oneByte == '\n') {
87            flushLog();
88        } else if (0x20 <= oneByte && oneByte <= 0x7e) { // Printable ASCII.
89            mSb.append((char)oneByte);
90        } else {
91            // email protocols are supposed to be all 7bits, but there are wrong implementations
92            // that do send 8 bit characters...
93            mSb.append("\\x" + Utility.byteToHex(oneByte));
94        }
95    }
96
97    private void flushLog() {
98        if (mDumpEmptyLines || (mSb.length() > mTag.length())) {
99            Log.d(Logging.LOG_TAG, mSb.toString());
100            initBuffer();
101        }
102    }
103
104    @Override
105    public void close() throws IOException {
106        super.close();
107        flushLog();
108    }
109}
110