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.BufferedReader;
020import java.io.IOException;
021import java.io.InputStream;
022import java.io.InputStreamReader;
023import java.io.BufferedOutputStream;
024import java.io.DataOutputStream;
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 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(boolean longOutput, String username) throws IOException
085    {
086        int read;
087        StringBuilder result = new StringBuilder(__buffer.length);
088        BufferedReader input;
089
090        input =
091            new BufferedReader(new InputStreamReader(getInputStream(longOutput,
092                               username), getCharset()));
093
094        try {
095            while (true)
096            {
097                read = input.read(__buffer, 0, __buffer.length);
098                if (read <= 0) {
099                    break;
100                }
101                result.append(__buffer, 0, read);
102            }
103        } finally {
104            input.close();
105        }
106
107        return result.toString();
108    }
109
110
111    /***
112     * Fingers the connected host and returns the output
113     * as a String.  You must first connect to a finger server before
114     * calling this method, and you should disconnect afterward.
115     * This is equivalent to calling <code> query(longOutput, "") </code>.
116     *
117     * @param longOutput Set to true if long output is requested, false if not.
118     * @return The result of the finger query.
119     * @throws IOException If an I/O error occurs while reading the socket.
120     ***/
121    public String query(boolean longOutput) throws IOException
122    {
123        return query(longOutput, "");
124    }
125
126
127    /***
128     * Fingers a user and returns the input stream from the network connection
129     * of the finger query.  You must first connect to a finger server before
130     * calling this method, and you should disconnect after finishing reading
131     * the stream.
132     *
133     * @param longOutput Set to true if long output is requested, false if not.
134     * @param username  The name of the user to finger.
135     * @return The InputStream of the network connection of the finger query.
136     *         Can be read to obtain finger results.
137     * @throws IOException If an I/O error during the operation.
138     ***/
139    public InputStream getInputStream(boolean longOutput, String username)
140    throws IOException
141    {
142        return getInputStream(longOutput, username, null);
143    }
144
145    /***
146     * Fingers a user and returns the input stream from the network connection
147     * of the finger query.  You must first connect to a finger server before
148     * calling this method, and you should disconnect after finishing reading
149     * the stream.
150     *
151     * @param longOutput Set to true if long output is requested, false if not.
152     * @param username  The name of the user to finger.
153     * @param encoding the character encoding that should be used for the query,
154     *        null for the platform's default encoding
155     * @return The InputStream of the network connection of the finger query.
156     *         Can be read to obtain finger results.
157     * @throws IOException If an I/O error during the operation.
158     ***/
159    public InputStream getInputStream(boolean longOutput, String username, String encoding)
160    throws IOException
161    {
162        DataOutputStream output;
163        StringBuilder buffer = new StringBuilder(64);
164        if (longOutput) {
165            buffer.append(__LONG_FLAG);
166        }
167        buffer.append(username);
168        buffer.append(SocketClient.NETASCII_EOL);
169
170        // Note: Charsets.toCharset() returns the platform default for null input
171        byte[] encodedQuery = buffer.toString().getBytes(Charsets.toCharset(encoding).name()); // Java 1.6 can use charset directly
172
173        output = new DataOutputStream(new BufferedOutputStream(_output_, 1024));
174        output.write(encodedQuery, 0, encodedQuery.length);
175        output.flush();
176
177        return _input_;
178    }
179
180
181    /***
182     * Fingers the connected host and returns the input stream from
183     * the network connection of the finger query.  This is equivalent to
184     * calling getInputStream(longOutput, "").  You must first connect to a
185     * finger server before calling this method, and you should disconnect
186     * after finishing reading the stream.
187     *
188     * @param longOutput Set to true if long output is requested, false if not.
189     * @return The InputStream of the network connection of the finger query.
190     *         Can be read to obtain finger results.
191     * @throws IOException If an I/O error during the operation.
192     ***/
193    public InputStream getInputStream(boolean longOutput) throws IOException
194    {
195        return getInputStream(longOutput, "");
196    }
197
198}