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 * <p>
051 * <p>
052 ***/
053
054public class FingerClient extends SocketClient
055{
056    /***
057     * The default FINGER port.  Set to 79 according to RFC 1288.
058     ***/
059    public static final int DEFAULT_PORT = 79;
060
061    private static final String __LONG_FLAG = "/W ";
062
063    private transient char[] __buffer = new char[1024];
064
065    /***
066     * The default FingerClient constructor.  Initializes the
067     * default port to <code> DEFAULT_PORT </code>.
068     ***/
069    public FingerClient()
070    {
071        setDefaultPort(DEFAULT_PORT);
072    }
073
074
075    /***
076     * Fingers a user at the connected host and returns the output
077     * as a String.  You must first connect to a finger server before
078     * calling this method, and you should disconnect afterward.
079     * <p>
080     * @param longOutput Set to true if long output is requested, false if not.
081     * @param username  The name of the user to finger.
082     * @return The result of the finger query.
083     * @exception IOException If an I/O error occurs while reading the socket.
084     ***/
085    public String query(boolean longOutput, String username) throws IOException
086    {
087        int read;
088        StringBuilder result = new StringBuilder(__buffer.length);
089        BufferedReader input;
090
091        input =
092            new BufferedReader(new InputStreamReader(getInputStream(longOutput,
093                               username), getCharsetName())); // Java 1.6 can use getCharset()
094
095        try {
096            while (true)
097            {
098                read = input.read(__buffer, 0, __buffer.length);
099                if (read <= 0) {
100                    break;
101                }
102                result.append(__buffer, 0, read);
103            }
104        } finally {
105            input.close();
106        }
107
108        return result.toString();
109    }
110
111
112    /***
113     * Fingers the connected host and returns the output
114     * as a String.  You must first connect to a finger server before
115     * calling this method, and you should disconnect afterward.
116     * This is equivalent to calling <code> query(longOutput, "") </code>.
117     * <p>
118     * @param longOutput Set to true if long output is requested, false if not.
119     * @return The result of the finger query.
120     * @exception IOException If an I/O error occurs while reading the socket.
121     ***/
122    public String query(boolean longOutput) throws IOException
123    {
124        return query(longOutput, "");
125    }
126
127
128    /***
129     * Fingers a user and returns the input stream from the network connection
130     * of the finger query.  You must first connect to a finger server before
131     * calling this method, and you should disconnect after finishing reading
132     * the stream.
133     * <p>
134     * @param longOutput Set to true if long output is requested, false if not.
135     * @param username  The name of the user to finger.
136     * @return The InputStream of the network connection of the finger query.
137     *         Can be read to obtain finger results.
138     * @exception IOException If an I/O error during the operation.
139     ***/
140    public InputStream getInputStream(boolean longOutput, String username)
141    throws IOException
142    {
143        return getInputStream(longOutput, username, null);
144    }
145
146    /***
147     * Fingers a user and returns the input stream from the network connection
148     * of the finger query.  You must first connect to a finger server before
149     * calling this method, and you should disconnect after finishing reading
150     * the stream.
151     * <p>
152     * @param longOutput Set to true if long output is requested, false if not.
153     * @param username  The name of the user to finger.
154     * @param encoding the character encoding that should be used for the query,
155     *        null for the platform's default encoding
156     * @return The InputStream of the network connection of the finger query.
157     *         Can be read to obtain finger results.
158     * @exception IOException If an I/O error during the operation.
159     ***/
160    public InputStream getInputStream(boolean longOutput, String username, String encoding)
161    throws IOException
162    {
163        DataOutputStream output;
164        StringBuilder buffer = new StringBuilder(64);
165        if (longOutput) {
166            buffer.append(__LONG_FLAG);
167        }
168        buffer.append(username);
169        buffer.append(SocketClient.NETASCII_EOL);
170
171        // Note: Charsets.toCharset() returns the platform default for null input
172        byte[] encodedQuery = buffer.toString().getBytes(Charsets.toCharset(encoding).name()); // Java 1.6 can use charset directly
173
174        output = new DataOutputStream(new BufferedOutputStream(_output_, 1024));
175        output.write(encodedQuery, 0, encodedQuery.length);
176        output.flush();
177
178        return _input_;
179    }
180
181
182    /***
183     * Fingers the connected host and returns the input stream from
184     * the network connection of the finger query.  This is equivalent to
185     * calling getInputStream(longOutput, "").  You must first connect to a
186     * finger server before calling this method, and you should disconnect
187     * after finishing reading the stream.
188     * <p>
189     * @param longOutput Set to true if long output is requested, false if not.
190     * @return The InputStream of the network connection of the finger query.
191     *         Can be read to obtain finger results.
192     * @exception IOException If an I/O error during the operation.
193     ***/
194    public InputStream getInputStream(boolean longOutput) throws IOException
195    {
196        return getInputStream(longOutput, "");
197    }
198
199}