    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 *      https://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 */
    017package org.apache.commons.net.finger;
    018
    019import java.io.BufferedOutputStream;
    020import java.io.DataOutputStream;
    021import java.io.IOException;
    022import java.io.InputStream;
    023
    024import org.apache.commons.io.Charsets;
    025import org.apache.commons.io.IOUtils;
    026import org.apache.commons.net.SocketClient;
    027
    028/**
    029 * The FingerClient class implements the client side of the Internet Finger Protocol defined in RFC 1288. To finger a host you create a FingerClient instance,
    030 * connect to the host, query the host, and finally disconnect from the host. If the finger service you want to query is on a non-standard port, connect to the
    031 * host at that port. Here's a sample use:
    032 *
    033 * <pre>
    034 * FingerClient finger;
    035 * finger = new FingerClient();
    036 * try {
    037 *     finger.connect("foo.bar.com");
    038 *     System.out.println(finger.query("foobar", false));
    039 *     finger.disconnect();
    040 * } catch (IOException e) {
    041 *     System.err.println("Error I/O exception: " + e.getMessage());
    042 *     return;
    043 * }
    044 * </pre>
    045 */
    046public class FingerClient extends SocketClient {
    047
    048    /**
    049     * The default FINGER port. Set to {@value} according to RFC 1288.
    050     */
    051    public static final int DEFAULT_PORT = 79;
    052
    053    private static final String LONG_FLAG = "/W ";
    054
    055    /**
    056     * The default FingerClient constructor. Initializes the default port to {@code DEFAULT_PORT}.
    057     */
    058    public FingerClient() {
    059        setDefaultPort(DEFAULT_PORT);
    060    }
    061
    062    /**
    063     * Fingers the connected host and returns the input stream from the network connection of the finger query. This is equivalent to calling
    064     * getInputStream(longOutput, ""). You must first connect to a finger server before calling this method, and you should disconnect after finishing reading
    065     * the stream.
    066     *
    067     * @param longOutput Set to true if long output is requested, false if not.
    068     * @return The InputStream of the network connection of the finger query. Can be read to obtain finger results.
    069     * @throws IOException If an I/O error during the operation.
    070     */
    071    public InputStream getInputStream(final boolean longOutput) throws IOException {
    072        return getInputStream(longOutput, "");
    073    }
    074
    075    /**
    076     * Fingers a user and returns the input stream from the network connection of the finger query. You must first connect to a finger server before calling
    077     * this method, and you should disconnect after finishing reading the stream.
    078     *
    079     * @param longOutput Set to true if long output is requested, false if not.
    080     * @param user   The name of the user to finger.
    081     * @return The InputStream of the network connection of the finger query. Can be read to obtain finger results.
    082     * @throws IOException If an I/O error during the operation.
    083     */
    084    public InputStream getInputStream(final boolean longOutput, final String user) throws IOException {
    085        return getInputStream(longOutput, user, null);
    086    }
    087
    088    /**
    089     * Fingers a user and returns the input stream from the network connection of the finger query. You must first connect to a finger server before calling
    090     * this method, and you should disconnect after finishing reading the stream.
    091     *
    092     * @param longOutput Set to true if long output is requested, false if not.
    093     * @param user   The name of the user to finger.
    094     * @param encoding   the character encoding that should be used for the query, null for the platform's default encoding
    095     * @return The InputStream of the network connection of the finger query. Can be read to obtain finger results.
    096     * @throws IOException If an I/O error during the operation.
    097     */
    098    public InputStream getInputStream(final boolean longOutput, final String user, final String encoding) throws IOException {
    099        final DataOutputStream output;
    100        final StringBuilder buffer = new StringBuilder(64);
    101        if (longOutput) {
    102            buffer.append(LONG_FLAG);
    103        }
    104        buffer.append(user);
    105        buffer.append(NETASCII_EOL);
    106
    107        // Note: Charsets.toCharset() returns the platform default for null input
    108        final byte[] encodedQuery = buffer.toString().getBytes(Charsets.toCharset(encoding));
    109
    110        output = new DataOutputStream(new BufferedOutputStream(checkOpenOutputStream(), 1024));
    111        output.write(encodedQuery, 0, encodedQuery.length);
    112        output.flush();
    113
    114        return _input_;
    115    }
    116
    117    /**
    118     * Fingers the connected host and returns the output as a String. You must first connect to a finger server before calling this method, and you should
    119     * disconnect afterward. This is equivalent to calling {@code query(longOutput, "")}.
    120     *
    121     * @param longOutput Set to true if long output is requested, false if not.
    122     * @return The result of the finger query.
    123     * @throws IOException If an I/O error occurs while reading the socket.
    124     */
    125    public String query(final boolean longOutput) throws IOException {
    126        return query(longOutput, "");
    127    }
    128
    129    /**
    130     * Fingers a user at the connected host and returns the output as a String. You must first connect to a finger server before calling this method, and you
    131     * should disconnect afterward.
    132     *
    133     * @param longOutput Set to true if long output is requested, false if not.
    134     * @param user   The name of the user to finger.
    135     * @return The result of the finger query.
    136     * @throws IOException If an I/O error occurs while reading the socket.
    137     */
    138    public String query(final boolean longOutput, final String user) throws IOException {
    139        return IOUtils.toString(() -> getInputStream(longOutput, user), getCharset());
    140    }
    141
    142}