001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.net;
019
020import java.io.PrintStream;
021import java.io.PrintWriter;
022
023import org.apache.commons.net.io.Util;
024
025/**
026 * This is a support class for some example programs. It is a sample implementation of the ProtocolCommandListener interface which just prints out to a
027 * specified stream all command/reply traffic.
028 *
029 * @since 2.0
030 */
031public class PrintCommandListener implements ProtocolCommandListener {
032
033    private final PrintWriter writer;
034    private final boolean nologin;
035    private final char eolMarker;
036
037    private final boolean directionMarker;
038
039    /**
040     * Constructs an instance which prints everything using the default Charset.
041     *
042     * @param printStream where to write the commands and responses e.g. System.out
043     * @since 3.0
044     */
045    @SuppressWarnings("resource")
046    public PrintCommandListener(final PrintStream printStream) {
047        this(Util.newPrintWriter(printStream));
048    }
049
050    /**
051     * Constructs an instance which optionally suppresses login command text and indicates where the EOL starts with the specified character.
052     *
053     * @param printStream        where to write the commands and responses
054     * @param suppressLogin if {@code true}, only print command name for login
055     *
056     * @since 3.0
057     */
058    @SuppressWarnings("resource")
059    public PrintCommandListener(final PrintStream printStream, final boolean suppressLogin) {
060        this(Util.newPrintWriter(printStream), suppressLogin);
061    }
062
063    /**
064     * Constructs an instance which optionally suppresses login command text and indicates where the EOL starts with the specified character.
065     *
066     * @param printStream        where to write the commands and responses
067     * @param suppressLogin if {@code true}, only print command name for login
068     * @param eolMarker     if non-zero, add a marker just before the EOL.
069     *
070     * @since 3.0
071     */
072    @SuppressWarnings("resource")
073    public PrintCommandListener(final PrintStream printStream, final boolean suppressLogin, final char eolMarker) {
074        this(Util.newPrintWriter(printStream), suppressLogin, eolMarker);
075    }
076
077    /**
078     * Constructs an instance which optionally suppresses login command text and indicates where the EOL starts with the specified character.
079     *
080     * @param printStream        where to write the commands and responses
081     * @param suppressLogin if {@code true}, only print command name for login
082     * @param eolMarker     if non-zero, add a marker just before the EOL.
083     * @param showDirection if {@code true}, add {@code "> "} or {@code "< "} as appropriate to the output
084     *
085     * @since 3.0
086     */
087    @SuppressWarnings("resource")
088    public PrintCommandListener(final PrintStream printStream, final boolean suppressLogin, final char eolMarker, final boolean showDirection) {
089        this(Util.newPrintWriter(printStream), suppressLogin, eolMarker, showDirection);
090    }
091
092    /**
093     * Constructs the default instance which prints everything.
094     *
095     * @param writer where to write the commands and responses
096     */
097    public PrintCommandListener(final PrintWriter writer) {
098        this(writer, false);
099    }
100
101    /**
102     * Constructs an instance which optionally suppresses login command text.
103     *
104     * @param writer        where to write the commands and responses
105     * @param suppressLogin if {@code true}, only print command name for login
106     *
107     * @since 3.0
108     */
109    public PrintCommandListener(final PrintWriter writer, final boolean suppressLogin) {
110        this(writer, suppressLogin, (char) 0);
111    }
112
113    /**
114     * Constructs an instance which optionally suppresses login command text and indicates where the EOL starts with the specified character.
115     *
116     * @param writer        where to write the commands and responses
117     * @param suppressLogin if {@code true}, only print command name for login
118     * @param eolMarker     if non-zero, add a marker just before the EOL.
119     *
120     * @since 3.0
121     */
122    public PrintCommandListener(final PrintWriter writer, final boolean suppressLogin, final char eolMarker) {
123        this(writer, suppressLogin, eolMarker, false);
124    }
125
126    /**
127     * Constructs an instance which optionally suppresses login command text and indicates where the EOL starts with the specified character.
128     *
129     * @param writer        where to write the commands and responses
130     * @param suppressLogin if {@code true}, only print command name for login
131     * @param eolMarker     if non-zero, add a marker just before the EOL.
132     * @param showDirection if {@code true}, add {@code ">} " or {@code "< "} as appropriate to the output
133     *
134     * @since 3.0
135     */
136    public PrintCommandListener(final PrintWriter writer, final boolean suppressLogin, final char eolMarker, final boolean showDirection) {
137        this.writer = writer;
138        this.nologin = suppressLogin;
139        this.eolMarker = eolMarker;
140        this.directionMarker = showDirection;
141    }
142
143    private String getPrintableString(final String msg) {
144        if (eolMarker == 0) {
145            return msg;
146        }
147        final int pos = msg.indexOf(SocketClient.NETASCII_EOL);
148        if (pos > 0) {
149            final StringBuilder sb = new StringBuilder();
150            sb.append(msg.substring(0, pos));
151            sb.append(eolMarker);
152            sb.append(msg.substring(pos));
153            return sb.toString();
154        }
155        return msg;
156    }
157
158    @Override
159    public void protocolCommandSent(final ProtocolCommandEvent event) {
160        if (directionMarker) {
161            writer.print("> ");
162        }
163        if (nologin) {
164            final String cmd = event.getCommand();
165            if ("PASS".equalsIgnoreCase(cmd) || "USER".equalsIgnoreCase(cmd)) {
166                writer.print(cmd);
167                writer.println(" *******"); // Don't bother with EOL marker for this!
168            } else {
169                final String IMAP_LOGIN = "LOGIN";
170                if (IMAP_LOGIN.equalsIgnoreCase(cmd)) { // IMAP
171                    String msg = event.getMessage();
172                    msg = msg.substring(0, msg.indexOf(IMAP_LOGIN) + IMAP_LOGIN.length());
173                    writer.print(msg);
174                    writer.println(" *******"); // Don't bother with EOL marker for this!
175                } else {
176                    writer.print(getPrintableString(event.getMessage()));
177                }
178            }
179        } else {
180            writer.print(getPrintableString(event.getMessage()));
181        }
182        writer.flush();
183    }
184
185    @Override
186    public void protocolReplyReceived(final ProtocolCommandEvent event) {
187        if (directionMarker) {
188            writer.print("< ");
189        }
190        writer.print(event.getMessage());
191        writer.flush();
192    }
193}