151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.net.www.protocol.gopher;
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.*;
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.*;
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.net.*;
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.net.www.*;
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.net.NetworkClient;
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.net.URL;
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.net.URLStreamHandler;
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.security.action.GetBooleanAction;
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/** Class to maintain the state of a gopher fetch and handle the protocol */
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic class GopherClient extends NetworkClient implements Runnable {
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* The following three data members are left in for binary
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * backwards-compatibility.  Unfortunately, HotJava sets them directly
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * when it wants to change the settings.  The new design has us not
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * cache these, so this is unnecessary, but eliminating the data members
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * would break HJB 1.1 under JDK 1.2.
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * These data members are not used, and their values are meaningless.
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * REMIND:  Take them out for JDK 2.0!
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @deprecated
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    @Deprecated
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static boolean       useGopherProxy;
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @deprecated
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    @Deprecated
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static String        gopherProxyHost;
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @deprecated
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    @Deprecated
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static int           gopherProxyPort;
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static {
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        useGopherProxy = java.security.AccessController.doPrivileged(
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new sun.security.action.GetBooleanAction("gopherProxySet"))
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            .booleanValue();
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        gopherProxyHost = java.security.AccessController.doPrivileged(
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new sun.security.action.GetPropertyAction("gopherProxyHost"));
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        gopherProxyPort = java.security.AccessController.doPrivileged(
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new sun.security.action.GetIntegerAction("gopherProxyPort", 80))
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            .intValue();
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    PipedOutputStream os;
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    URL u;
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    int gtype;
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    String gkey;
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    sun.net.www.URLConnection connection;
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    GopherClient(sun.net.www.URLConnection connection) {
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.connection = connection;
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return true if gopher connections should go through a proxy, according
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *          to system properties.
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static boolean getUseGopherProxy() {
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return java.security.AccessController.doPrivileged(
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new GetBooleanAction("gopherProxySet")).booleanValue();
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the proxy host to use, or null if nothing is set.
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static String getGopherProxyHost() {
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String host = java.security.AccessController.doPrivileged(
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                new sun.security.action.GetPropertyAction("gopherProxyHost"));
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ("".equals(host)) {
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            host = null;
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return host;
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the proxy port to use.  Will default reasonably.
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static int getGopherProxyPort() {
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return java.security.AccessController.doPrivileged(
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new sun.security.action.GetIntegerAction("gopherProxyPort", 80))
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            .intValue();
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Given a url, setup to fetch the gopher document it refers to */
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    InputStream openStream(URL u) throws IOException {
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.u = u;
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.os = os;
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int i = 0;
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String s = u.getFile();
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int limit = s.length();
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int c = '1';
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while (i < limit && (c = s.charAt(i)) == '/')
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            i++;
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        gtype = c == '/' ? '1' : c;
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (i < limit)
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            i++;
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        gkey = s.substring(i);
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        openServer(u.getHost(), u.getPort() <= 0 ? 70 : u.getPort());
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        MessageHeader msgh = new MessageHeader();
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        switch (gtype) {
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski          case '0':
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski          case '7':
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            msgh.add("content-type", "text/plain");
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski          case '1':
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            msgh.add("content-type", "text/html");
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski          case 'g':
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski          case 'I':
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            msgh.add("content-type", "image/gif");
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski          default:
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            msgh.add("content-type", "content/unknown");
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (gtype != '7') {
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            serverOutput.print(decodePercent(gkey) + "\r\n");
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            serverOutput.flush();
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else if ((i = gkey.indexOf('?')) >= 0) {
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            serverOutput.print(decodePercent(gkey.substring(0, i) + "\t" +
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                           gkey.substring(i + 1) + "\r\n"));
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            serverOutput.flush();
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            msgh.add("content-type", "text/html");
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            msgh.add("content-type", "text/html");
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        connection.setProperties(msgh);
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (msgh.findValue("content-type") == "text/html") {
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            os = new PipedOutputStream();
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            PipedInputStream ret = new PipedInputStream();
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ret.connect(os);
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new Thread(this).start();
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return ret;
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new GopherInputStream(this, serverInput);
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Translate all the instances of %NN into the character they represent */
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private String decodePercent(String s) {
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (s == null || s.indexOf('%') < 0)
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return s;
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int limit = s.length();
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char d[] = new char[limit];
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int dp = 0;
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int sp = 0; sp < limit; sp++) {
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int c = s.charAt(sp);
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (c == '%' && sp + 2 < limit) {
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int s1 = s.charAt(sp + 1);
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int s2 = s.charAt(sp + 2);
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if ('0' <= s1 && s1 <= '9')
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    s1 = s1 - '0';
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                else if ('a' <= s1 && s1 <= 'f')
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    s1 = s1 - 'a' + 10;
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                else if ('A' <= s1 && s1 <= 'F')
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    s1 = s1 - 'A' + 10;
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                else
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    s1 = -1;
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if ('0' <= s2 && s2 <= '9')
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    s2 = s2 - '0';
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                else if ('a' <= s2 && s2 <= 'f')
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    s2 = s2 - 'a' + 10;
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                else if ('A' <= s2 && s2 <= 'F')
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    s2 = s2 - 'A' + 10;
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                else
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    s2 = -1;
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (s1 >= 0 && s2 >= 0) {
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    c = (s1 << 4) | s2;
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    sp += 2;
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            d[dp++] = (char) c;
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new String(d, 0, dp);
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** Turn special characters into the %NN form */
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private String encodePercent(String s) {
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (s == null)
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return s;
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int limit = s.length();
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char d[] = null;
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int dp = 0;
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int sp = 0; sp < limit; sp++) {
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int c = s.charAt(sp);
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (c <= ' ' || c == '"' || c == '%') {
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (d == null)
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    d = s.toCharArray();
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (dp + 3 >= d.length) {
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    char nd[] = new char[dp + 10];
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    System.arraycopy(d, 0, nd, 0, dp);
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    d = nd;
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                d[dp] = '%';
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int dig = (c >> 4) & 0xF;
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                d[dp + 1] = (char) (dig < 10 ? '0' + dig : 'A' - 10 + dig);
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                dig = c & 0xF;
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                d[dp + 2] = (char) (dig < 10 ? '0' + dig : 'A' - 10 + dig);
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                dp += 3;
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (d != null) {
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (dp >= d.length) {
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        char nd[] = new char[dp + 10];
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        System.arraycopy(d, 0, nd, 0, dp);
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        d = nd;
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    d[dp] = (char) c;
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                dp++;
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return d == null ? s : new String(d, 0, dp);
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /** This method is run as a seperate thread when an incoming gopher
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        document requires translation to html */
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void run() {
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int qpos = -1;
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (gtype == '7' && (qpos = gkey.indexOf('?')) < 0) {
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                PrintStream ps = new PrintStream(os, false, encoding);
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ps.print("<html><head><title>Searchable Gopher Index</title></head>\n<body><h1>Searchable Gopher Index</h1><isindex>\n</body></html>\n");
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else if (gtype != '1' && gtype != '7') {
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                byte buf[] = new byte[2048];
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                try {
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int n;
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    while ((n = serverInput.read(buf)) >= 0)
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            os.write(buf, 0, n);
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } catch(Exception e) {
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                PrintStream ps = new PrintStream(os, false, encoding);
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String title = null;
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (gtype == '7')
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    title = "Results of searching for \"" + gkey.substring(qpos + 1)
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        + "\" on " + u.getHost();
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                else
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    title = "Gopher directory " + gkey + " from " + u.getHost();
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ps.print("<html><head><title>");
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ps.print(title);
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ps.print("</title></head>\n<body>\n<H1>");
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ps.print(title);
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ps.print("</h1><dl compact>\n");
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                DataInputStream ds = new DataInputStream(serverInput);
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String s;
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                while ((s = ds.readLine()) != null) {
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int len = s.length();
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    while (len > 0 && s.charAt(len - 1) <= ' ')
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        len--;
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (len <= 0)
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        continue;
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int key = s.charAt(0);
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int t1 = s.indexOf('\t');
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int t2 = t1 > 0 ? s.indexOf('\t', t1 + 1) : -1;
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int t3 = t2 > 0 ? s.indexOf('\t', t2 + 1) : -1;
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (t3 < 0) {
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // ps.print("<br><i>"+s+"</i>\n");
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        continue;
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    String port = t3 + 1 < len ? ":" + s.substring(t3 + 1, len) : "";
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    String host = t2 + 1 < t3 ? s.substring(t2 + 1, t3) : u.getHost();
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    ps.print("<dt><a href=\"gopher://" + host + port + "/"
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                             + s.substring(0, 1) + encodePercent(s.substring(t1 + 1, t2)) + "\">\n");
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    ps.print("<img align=middle border=0 width=25 height=32 src=");
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    switch (key) {
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                      default:
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        ps.print(System.getProperty("java.net.ftp.imagepath.file"));
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break;
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                      case '0':
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        ps.print(System.getProperty("java.net.ftp.imagepath.text"));
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break;
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                      case '1':
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        ps.print(System.getProperty("java.net.ftp.imagepath.directory"));
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break;
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                      case 'g':
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        ps.print(System.getProperty("java.net.ftp.imagepath.gif"));
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break;
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    ps.print(".gif align=middle><dd>\n");
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    ps.print(s.substring(1, t1) + "</a>\n");
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ps.print("</dl></body>\n");
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ps.close();
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           }
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       } catch (UnsupportedEncodingException e) {
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new InternalError(encoding+ " encoding not found");
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       } catch (IOException e) {
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       } finally {
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           try {
33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski               closeServer();
33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski               os.close();
33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           } catch (IOException e2) {
33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski           }
33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/** An input stream that does nothing more than hold on to the NetworkClient
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    that created it.  This is used when only the input stream is needed, and
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    the network client needs to be closed when the input stream is closed. */
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiclass GopherInputStream extends FilterInputStream {
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    NetworkClient parent;
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    GopherInputStream(NetworkClient o, InputStream fd) {
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        super(fd);
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        parent = o;
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void close() {
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            parent.closeServer();
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            super.close();
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (IOException e) {
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
358