home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / win95 / sieciowe / hotja32.lzh / hotjava / classsrc / net / www / protocol / gopher / handler.java
Text File  |  1995-08-11  |  8KB  |  282 lines

  1. /*
  2.  * @(#)Handler.java    1.2 95/03/29
  3.  * 
  4.  * Copyright (c) 1995 Sun Microsystems, Inc.  All Rights reserved Permission to
  5.  * use, copy, modify, and distribute this software and its documentation for
  6.  * NON-COMMERCIAL purposes and without fee is hereby granted provided that
  7.  * this copyright notice appears in all copies. Please refer to the file
  8.  * copyright.html for further important copyright and licensing information.
  9.  * 
  10.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  11.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  12.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  13.  * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
  14.  * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
  15.  * ITS DERIVATIVES.
  16.  */
  17.  
  18. package net.www.protocol.gopher;
  19.  
  20. import java.io.*;
  21. import java.util.*;
  22. import net.*;
  23. import net.www.html.URL;
  24. import net.www.html.URLStreamHandler;
  25.  
  26. /**
  27.  * A class to handle the gopher protocol.
  28.  */
  29.  
  30. class Handler extends URLStreamHandler {
  31.     public InputStream openStream(URL u) {
  32.     return new gopherFetcher().openStream(u);
  33.     }
  34. }
  35.  
  36. /** Class to maintain the state of a gopher fetch and handle the protocol */
  37. class gopherFetcher extends NetworkClient implements Runnable {
  38.     PipedOutputStream os;
  39.     URL u;
  40.     int gtype;
  41.     String gkey;
  42.  
  43.     /** Given a url, setup to fetch the gopher document it refers to */
  44.     InputStream openStream(URL u) {
  45.     this.u = u;
  46.     this.os = os;
  47.     int i = 0;
  48.     String s = u.file;
  49.     int limit = s.length();
  50.     int c = '1';
  51.     while (i < limit && (c = s.charAt(i)) == '/')
  52.         i++;
  53.     gtype = c == '/' ? '1' : c;
  54.     if (i < limit)
  55.         i++;
  56.     gkey = s.substring(i);
  57.     try {
  58.         openServer(u.host, u.port <= 0 ? 70 : u.port);
  59.     } catch(UnknownHostException e) {
  60.  
  61.         /*
  62.          * We may have to punch through the sun firewall
  63.          */
  64.         openServer("sun-barr.ebay.sun.com", 3666);
  65.         serverOutput.print(u.host + " " + (u.port <= 0 ? 70 : u.port) + "\n");
  66.         serverOutput.flush();
  67.         /* Now we have to read two bogus lines from the front */
  68.         i = 0;
  69.         while ((c = serverInput.read()) >= 0)
  70.         if (c == '\n' && ++i >= 2)
  71.             break;
  72.         if (c < 0) {
  73.         closeServer();
  74.         throw new UnknownHostException(u.host);
  75.         }
  76.     }
  77.     switch (gtype) {
  78.       case '0':
  79.       case '7':
  80.         u.setType(URL.content_plain);
  81.         break;
  82.       case '1':
  83.         u.setType(URL.content_html);
  84.         break;
  85.       case 'g':
  86.       case 'I':
  87.         u.setType(URL.content_gif);
  88.         break;
  89.       default:
  90.         u.setType(URL.content_unknown);
  91.         break;
  92.     }
  93.     if (gtype != '7') {
  94.         serverOutput.print(decodePercent(gkey) + "\r\n");
  95.         serverOutput.flush();
  96.     } else if ((i = gkey.indexOf('?')) >= 0) {
  97.         serverOutput.print(decodePercent(gkey.substring(0, i) + "\t" +
  98.                        gkey.substring(i + 1) + "\r\n"));
  99.         serverOutput.flush();
  100.         u.setType(URL.content_html);
  101.     } else
  102.         u.setType(URL.content_html);
  103.     if (u.content_type == URL.content_html) {
  104.         os = new PipedOutputStream();
  105.         PipedInputStream ret = new PipedInputStream();
  106.         ret.connect(os);
  107.         new Thread(this).start();
  108.         return ret;
  109.     }
  110.     return new GopherInputStream(this, serverInput);
  111.     }
  112.  
  113.     /** Translate all the instances of %NN into the character they represent */
  114.     private String decodePercent(String s) {
  115.     if (s == null || s.indexOf('%') < 0)
  116.         return s;
  117.     int limit = s.length();
  118.     char d[] = new char[limit];
  119.     int dp = 0;
  120.     for (int sp = 0; sp < limit; sp++) {
  121.         int c = s.charAt(sp);
  122.         if (c == '%' && sp + 2 < limit) {
  123.         int s1 = s.charAt(sp + 1);
  124.         int s2 = s.charAt(sp + 2);
  125.         if ('0' <= s1 && s1 <= '9')
  126.             s1 = s1 - '0';
  127.         else if ('a' <= s1 && s1 <= 'f')
  128.             s1 = s1 - 'a' + 10;
  129.         else if ('A' <= s1 && s1 <= 'F')
  130.             s1 = s1 - 'A' + 10;
  131.         else
  132.             s1 = -1;
  133.         if ('0' <= s2 && s2 <= '9')
  134.             s2 = s2 - '0';
  135.         else if ('a' <= s2 && s2 <= 'f')
  136.             s2 = s2 - 'a' + 10;
  137.         else if ('A' <= s2 && s2 <= 'F')
  138.             s2 = s2 - 'A' + 10;
  139.         else
  140.             s2 = -1;
  141.         if (s1 >= 0 && s2 >= 0) {
  142.             c = (s1 << 4) | s2;
  143.             sp += 2;
  144.         }
  145.         }
  146.         d[dp++] = (char) c;
  147.     }
  148.     return new String(d, 0, dp);
  149.     }
  150.  
  151.     /** Turn special characters into the %NN form */
  152.     private String encodePercent(String s) {
  153.     if (s == null)
  154.         return s;
  155.     int limit = s.length();
  156.     char d[] = null;
  157.     int dp = 0;
  158.     for (int sp = 0; sp < limit; sp++) {
  159.         int c = s.charAt(sp);
  160.         if (c <= ' ' || c == '"' || c == '%') {
  161.         if (d == null)
  162.             d = s.toCharArray();
  163.         if (dp + 3 >= d.length) {
  164.             char nd[] = new char[dp + 10];
  165.             System.arraycopy(d, 0, nd, 0, dp);
  166.             d = nd;
  167.         }
  168.         d[dp] = '%';
  169.         int dig = (c >> 4) & 0xF;
  170.         d[dp + 1] = (char) (dig < 10 ? '0' + dig : 'A' - 10 + dig);
  171.         dig = c & 0xF;
  172.         d[dp + 2] = (char) (dig < 10 ? '0' + dig : 'A' - 10 + dig);
  173.         dp += 3;
  174.         } else {
  175.         if (d != null) {
  176.             if (dp >= d.length) {
  177.             char nd[] = new char[dp + 10];
  178.             System.arraycopy(d, 0, nd, 0, dp);
  179.             d = nd;
  180.             }
  181.             d[dp] = (char) c;
  182.         }
  183.         dp++;
  184.         }
  185.     }
  186.     return d == null ? s : new String(d, 0, dp);
  187.     }
  188.  
  189.     /** This method is run as a seperate thread when an incoming gopher
  190.     document requires translation to html */
  191.     public void run() {
  192.     int qpos = -1;
  193.     try {
  194.         if (gtype == '7' && (qpos = gkey.indexOf('?')) < 0) {
  195.         PrintStream ps = new PrintStream(os);
  196.         ps.print("<html><head><title>Searchable Gopher Index</title></head>\n<body><h1>Searchable Gopher Index</h1><isindex>\n</body></html>\n");
  197.         } else if (gtype != '1' && gtype != '7') {
  198.         byte buf[] = new byte[2048];
  199.         try {
  200.             int n;
  201.             while ((n = serverInput.read(buf)) >= 0)
  202.                 os.write(buf, 0, n);
  203.         } catch(Exception e) {
  204.         }
  205.         } else {
  206.         PrintStream ps = new PrintStream(os);
  207.         String title = null;
  208.         if (gtype == '7')
  209.             title = "Results of searching for \"" + gkey.substring(qpos + 1)
  210.             + "\" on " + u.host;
  211.         else
  212.             title = "Gopher directory " + gkey + " from " + u.host;
  213.         ps.print("<html><head><title>");
  214.         ps.print(title);
  215.         ps.print("</title></head>\n<body>\n<H1>");
  216.         ps.print(title);
  217.         ps.print("</h1><dl compact>\n");
  218.         DataInputStream ds = new DataInputStream(serverInput);
  219.         String s;
  220.         while ((s = ds.readLine()) != null) {
  221.             int len = s.length();
  222.             while (len > 0 && s.charAt(len - 1) <= ' ')
  223.             len--;
  224.             if (len <= 0)
  225.             continue;
  226.             int key = s.charAt(0);
  227.             int t1 = s.indexOf('\t');
  228.             int t2 = t1 > 0 ? s.indexOf('\t', t1 + 1) : -1;
  229.             int t3 = t2 > 0 ? s.indexOf('\t', t2 + 1) : -1;
  230.             if (t3 < 0) {
  231.             // ps.print("<br><i>"+s+"</i>\n");
  232.             continue;
  233.             }
  234.             String port = t3 + 1 < len ? ":" + s.substring(t3 + 1, len) : "";
  235.             String host = t2 + 1 < t3 ? s.substring(t2 + 1, t3) : u.host;
  236.             ps.print("<dt><a href=\"gopher://" + host + port + "/"
  237.                  + s.substring(0, 1) + encodePercent(s.substring(t1 + 1, t2)) + "\">\n");
  238.             ps.print("<img align=middle border=0 width=25 height=32 src=doc:/demo/images/ftp/");
  239.             switch (key) {
  240.               default:
  241.             ps.print("file");
  242.             break;
  243.               case '0':
  244.             ps.print("text");
  245.             break;
  246.               case '1':
  247.             ps.print("directory");
  248.             break;
  249.               case 'g':
  250.             ps.print("gif");
  251.             break;
  252.             }
  253.             ps.print(".gif align=middle><dd>\n");
  254.             ps.print(s.substring(1, t1) + "</a>\n");
  255.         }
  256.         ps.print("</dl></body>\n");
  257.         ps.close();
  258.         }
  259.     } finally {
  260.         closeServer();
  261.         os.close();
  262.     }
  263.     }
  264. }
  265.  
  266. /** An input stream that does nothing more than hold on to the NetworkClient
  267.     that created it.  This is used when only the input stream is needed, and
  268.     the network client needs to be closed when the input stream is closed. */
  269. class GopherInputStream extends FilterInputStream {
  270.     NetworkClient parent;
  271.  
  272.     GopherInputStream(NetworkClient o, InputStream fd) {
  273.     super(fd);
  274.     parent = o;
  275.     }
  276.  
  277.     public void close() {
  278.     parent.closeServer();
  279.     super.close();
  280.     }
  281. }
  282.