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