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