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