home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / pr8adpl7 / jfsclient.java < prev    next >
Encoding:
Java Source  |  1996-08-14  |  13.7 KB  |  542 lines

  1. // JFSclient.java
  2. // A connection to a jfs server, for use by JFS applets
  3. import java.io.*;
  4. import java.net.*;
  5. import java.util.Vector;
  6. import java.util.StringTokenizer;
  7. import CryptConnection;
  8. import Message;
  9. import BufferInputStream;
  10. import BufferOutputStream;
  11.  
  12. public class JFSclient
  13. {
  14.     String serverhost;            // server we are connected to
  15.     String authname, authpass;        // name and password, or null
  16.     CryptConnection con;
  17.     CryptInputStream in;            // data from server
  18.     CryptOutputStream out;            // data to server
  19.     CutBuffer cb;                // shared cut buffer
  20.     String currentdir = "/",        // default dir for load/save
  21.            currentfile = "",        // default filename
  22.            currenttype = null;        // last saved mime type
  23.  
  24.     // Create a client object and connect to the given JFS server
  25.     JFSclient(String host) throws IOException
  26.     {
  27.     Socket s = new Socket(host, 9888);
  28.     try {
  29.         con = new CryptConnection(s.getInputStream(),
  30.                       s.getOutputStream());
  31.         }
  32.     catch(IOException e);
  33.     in = con.getInputStream();
  34.     out = con.getOutputStream();
  35.     serverhost = host;
  36.     cb = new CutBuffer();
  37.     }
  38.  
  39.     // Create a client object with the given host, name, password and
  40.     // cutbuffer. This only exists for calling from newclient().
  41.     JFSclient(String host, String n, String p, CutBuffer c)
  42.         throws IOException
  43.     {
  44.     this(host);
  45.     if (n != null && p != null) {
  46.         auth(n,p);
  47.         authname = n;
  48.         authpass = p;
  49.         }
  50.     cb = c;
  51.     }
  52.  
  53.     // newclient
  54.     // Create a new JFSclient object, with a new connection to the
  55.     // server. If this client was authenticated, the new one will be too.
  56.     JFSclient newclient() throws RequestException
  57.     {
  58.     try return new JFSclient(serverhost, authname, authpass, cb);
  59.     catch(IOException e)
  60.         throw new RequestException("Error reconnecting to server");
  61.     }
  62.  
  63.     // setbuf & getbuf
  64.     // Set and get the shared cut buffer selection used by this client
  65.     void setbuf(Object o) { cb.buf = o; }
  66.     Object getbuf() { return cb.buf; }
  67.  
  68.     // close
  69.     // Disconnect from the server
  70.     void close()
  71.     {
  72.     Message m = new Message();
  73.     m.add("Request","Close");
  74.     m.send(out);
  75.     try {
  76.         out.close();
  77.         in.close();
  78.         }
  79.     catch(IOException e);
  80.     }
  81.  
  82.     // auth
  83.     // Send an Auth request to the server and wait for a reply.
  84.     void auth(String name, String pass) throws RequestException
  85.     {
  86.     Message m = new Message();
  87.     m.add("Request","Auth");
  88.     m.add("Username",name);
  89.     m.add("Password",pass);
  90.     m.send(out);
  91.     Message r = getreply();
  92.     authname = name;
  93.     authpass = pass;
  94.     currentdir = uinfo(authname).home;
  95.     }
  96.  
  97.     // getdir
  98.     // Returns a JFSdirectory structure containing info about the files
  99.     // in the given directory.
  100.     JFSdirectory getdir(String path) throws RequestException
  101.     {
  102.     byte dirdata[] = getsect(path, 0, -1, -1);
  103.     BufferInputStream buf = new BufferInputStream(dirdata);
  104.     try return new JFSdirectory(buf);
  105.     catch(IOException e)
  106.         throw new RequestException("Error parsing directory : "+
  107.                        e.getMessage());
  108.     }
  109.  
  110.     // statfile
  111.     // Returns the JFSfile structure for a given filename
  112.     JFSfile statfile(String path) throws RequestException
  113.     {
  114.     Message m = new Message();
  115.     m.add("Request","Stat");
  116.     m.add("File",path);
  117.     m.send(out);
  118.     Message r = getreply();
  119.     BufferInputStream buf = new BufferInputStream(r.getdata());
  120.     JFSdirectory tmpdir = null;
  121.     try tmpdir = new JFSdirectory(buf);
  122.     catch(IOException e)
  123.         throw new RequestException("Error parsing file details");
  124.     return (JFSfile)tmpdir.files.elementAt(0);
  125.     }
  126.  
  127.     // get
  128.     // Returns the data from the given file and version. If ver is 0,
  129.     // then the latest version should be received.
  130.     // At the moment, the file is requested in 8k chunks, as trying to read
  131.     // more than that at one go hangs some java implementations (such
  132.     // as netscape).
  133.     byte []get(String path, int ver) throws RequestException
  134.     {
  135.     BufferOutputStream buf = new BufferOutputStream();
  136.     byte sect[] = null;
  137.     int pos = 0, chunk = 8000;
  138.     do {
  139.         sect = getsect(path, ver, pos, pos+chunk-1);
  140.         buf.write(sect);
  141.         pos += chunk;
  142.         } while(sect.length == chunk);
  143.     return buf.getarray();
  144.     }
  145.  
  146.     // getsect
  147.     // Returns the data from part of a given file and version, or the
  148.     // whole file is start == -1
  149.     byte []getsect(String path, int ver, int st, int en)
  150.         throws RequestException
  151.     {
  152.     Message m = new Message();
  153.     if (ver != 0)
  154.         m.add("Version",String.valueOf(ver));
  155.     if (st >= 0) {
  156.         m.add("Start",String.valueOf(st));
  157.         m.add("End",String.valueOf(en));
  158.         }
  159.     return devget(path, m).getdata();
  160.     }
  161.  
  162.     // devget
  163.     // Sends a Get request, but with the headers from the given message
  164.     // added. Useful for reading from device drivers.
  165.     Message devget(String file, Message head) throws RequestException
  166.     {
  167.     Message m = new Message();
  168.     m.add("Request", "Get");
  169.     m.add("File", file);
  170.     for(int i=0; i<head.size(); i++)
  171.         m.add(head.name(i), head.value(i));
  172.     m.send(out);
  173.     return getreply();
  174.     }
  175.  
  176.     // put
  177.     // Sends data to be stored under the given name, version and mime type
  178.     void put(String path, int ver, byte data[], String type)
  179.         throws RequestException
  180.     {
  181.     Message m = new Message();
  182.     if (ver != 0)
  183.         m.add("Version",String.valueOf(ver));
  184.     m.add("Content-type",type);
  185.     devput(path, data, m);
  186.     }
  187.  
  188.     // devput
  189.     // Sends a Put request, but with the headers from the given message
  190.     // added. Useful for writing to device drivers.
  191.     void devput(String file, byte d[], Message head) throws RequestException
  192.     {
  193.     Message m = new Message();
  194.     m.add("Request","Put");
  195.     m.add("File", file);
  196.     m.setdata(d);
  197.     for(int i=0; i<head.size(); i++)
  198.         m.add(head.name(i), head.value(i));
  199.     m.send(out);
  200.     getreply();
  201.     }
  202.  
  203.     // gethandler
  204.     // Returns the handler class (from the file /etc/programs) for the
  205.     // given mime type.
  206.     String gethandler(String typestr) throws RequestException
  207.     {
  208.     MimeType type = new MimeType(typestr);
  209.     if (!type.exact())
  210.         throw new RequestException("Mime type "+typestr+
  211.                        " contains wildcards");
  212.     Vector pr = new Vector(), ty = new Vector();
  213.     getprograms(pr, ty);
  214.     for(int i=0; i<pr.size(); i++) {
  215.         String hprog = (String)pr.elementAt(i);
  216.         MimeType htype = (MimeType)ty.elementAt(i);
  217.         if (htype != null && htype.equals(type))
  218.             return hprog;
  219.         }
  220.     return null;
  221.     }
  222.  
  223.     // getprograms
  224.     // Fills in the p vector with the list of known programs
  225.     // from the server, and the t vector with the mime types for those
  226.     // programs (or null)
  227.     void getprograms(Vector p, Vector t) throws RequestException
  228.     {
  229.     BufferInputStream buf = new BufferInputStream(get("/etc/programs", 0));
  230.     while(true) {
  231.         String line = null;
  232.         try line = buf.gets();
  233.         catch(IOException e)
  234.             break;
  235.         StringTokenizer tok = new StringTokenizer(line," \t");
  236.         if (tok.countTokens() < 1)
  237.             continue;
  238.         String prog = tok.nextToken();
  239.         MimeType type = null;
  240.         if (tok.countTokens() > 0) {
  241.             type = new MimeType(tok.nextToken());
  242.             if (!type.valid())
  243.                 throw new RequestException("Bogus mime type "+
  244.                                "in /etc/programs");
  245.             }
  246.         p.addElement(prog);
  247.         t.addElement(type);
  248.         }
  249.     }
  250.  
  251.     // getprinters
  252.     // Fill the given vectors with the names, types, descriptions and
  253.     // print commands for all printers on the server.
  254.     void getprinters(Vector name, Vector type, Vector desc, Vector cmd)
  255.         throws RequestException
  256.     {
  257.     BufferInputStream pfile = new BufferInputStream(get("/etc/printers",0));
  258.     try {
  259.         while(true) {
  260.             String line = pfile.gets();
  261.             StringSplitter tok = new StringSplitter(line,':');
  262.             if (tok.countTokens() != 4)
  263.                 continue;
  264.             name.addElement(tok.nextToken());
  265.             type.addElement(tok.nextToken());
  266.             desc.addElement(tok.nextToken());
  267.             cmd.addElement(tok.nextToken());
  268.             }
  269.         }
  270.     catch(IOException e);
  271.     }
  272.  
  273.     // delete
  274.     // Requests the deletion of the given file and version. If the version
  275.     // is 0, all versions of this file will be deleted.
  276.     void delete(String file, int v) throws RequestException
  277.     {
  278.     Message m = new Message();
  279.     m.add("Request","Delete");
  280.     m.add("File",file);
  281.     if (v != 0)
  282.         m.add("Version",String.valueOf(v));
  283.     m.send(out);
  284.     getreply();
  285.     }
  286.  
  287.     // mkdir
  288.     // Send a request to create the given directory.
  289.     void mkdir(String dir) throws RequestException
  290.     {
  291.     Message m = new Message();
  292.     m.add("Request","Mkdir");
  293.     m.add("Directory",dir);
  294.     m.send(out);
  295.     getreply();
  296.     }
  297.  
  298.     // copy
  299.     // Send a request to copy one file to another
  300.     void copy(String src, String dst) throws RequestException
  301.     {
  302.     Message m = new Message();
  303.     m.add("Request","Copy");
  304.     m.add("Source",src);
  305.     m.add("Destination",dst);
  306.     m.send(out);
  307.     getreply();
  308.     }
  309.  
  310.     // uinfo
  311.     // Returns a JFSuser structure for the given username, with the
  312.     // password field cleared. If the username is null, then the name
  313.     // of the current user is used.
  314.     JFSuser uinfo(String u) throws RequestException
  315.     {
  316.     Message m = new Message();
  317.     m.add("Request", "Uinfo");
  318.     m.add("Username", u==null ? authname : u);
  319.     m.send(out);
  320.  
  321.     Message r = getreply();
  322.     byte ba[] = r.getdata();
  323.     char ca[] = new char[ba.length];
  324.     for(int i=0; i<ba.length; i++)
  325.         ca[i] = (char)ba[i];
  326.     String str = new String(ca);
  327.     try return new JFSuser(str);
  328.     catch(IOException e)
  329.         throw new RequestException("User format error");
  330.     }
  331.  
  332.     // ulist
  333.     // Returns a vector of JFSuser structures for all the users on the
  334.     // server (minus the password fields).
  335.     Vector ulist() throws RequestException
  336.     {
  337.     // send request
  338.     Message m = new Message();
  339.     m.add("Request", "Ulist");
  340.     m.send(out);
  341.  
  342.     // read and parse reply
  343.     Message r = getreply();
  344.     BufferInputStream buf = new BufferInputStream(r.getdata());
  345.     Vector ul = new Vector();
  346.     try while(true) ul.addElement(new JFSuser(buf.gets()));
  347.     catch(IOException e);
  348.     return ul;
  349.     }
  350.  
  351.     // ginfo
  352.     // Returns a list of users belonging to the given group
  353.     Vector ginfo(String g) throws RequestException
  354.     {
  355.     Message m = new Message();
  356.     m.add("Request","Ginfo");
  357.     m.add("Group",g);
  358.     m.send(out);
  359.  
  360.     Message r = getreply();
  361.     BufferInputStream buf = new BufferInputStream(r.getdata());
  362.     Vector uv = new Vector();
  363.     while(true) {
  364.         try uv.addElement(buf.gets());
  365.         catch(IOException e) break;
  366.         }
  367.     return uv;
  368.     }
  369.  
  370.     // chmod
  371.     // Sends a Chmod request to the server. Can be used to add, delete
  372.     // or change the permissions of a user.
  373.     void chmod(String f, String u, String p) throws RequestException
  374.     {
  375.     Message m = new Message();
  376.     m.add("Request","Chmod");
  377.     m.add("File",f);
  378.     m.add("User",u);
  379.     if (p != null) m.add("Perms",p);
  380.     m.send(out);
  381.     getreply();
  382.     }
  383.  
  384.     // getprop
  385.     // Get one property from the server identified by the given name
  386.     // and user. If the user parameter is null, then the name of the
  387.     // current user is used.
  388.     ServerProperty getprop(String name, String user)
  389.     {
  390.     Message m = new Message();
  391.     m.add("Request", "Getprop");
  392.     m.add("Property", name);
  393.     m.add("User", user==null ? authname : user);
  394.     m.send(out);
  395.  
  396.     try return new ServerProperty(new String(getreply().getdata(),0));
  397.     catch(Exception e)
  398.         return null;
  399.     }
  400.  
  401.     // putprop
  402.     // Attempt to store a property on the server. If the property's
  403.     // user field is null, then the name of the current user is used
  404.     void putprop(ServerProperty p) 
  405.     {
  406.     Message m = new Message();
  407.     m.add("Request","Putprop");
  408.     if (p.user == null) p.user = authname;
  409.     String pstr = p.output();
  410.     byte pb[] = new byte[pstr.length()];
  411.     pstr.getBytes(0, pstr.length(), pb, 0);
  412.     m.setdata(pb);
  413.     m.send(out);
  414.  
  415.     try new Message(in);    // errors are ignored
  416.     catch(IOException e);
  417.     }
  418.  
  419.     // delprop
  420.     // Delete a property from the server. If the user parameter is null,
  421.     // the name of the current user is used.
  422.     void delprop(String name, String user)
  423.     {
  424.     Message m = new Message();
  425.     m.add("Request", "Delprop");
  426.     m.add("Property", name);
  427.     m.add("User", user==null ? authname : user);
  428.     m.send(out);
  429.  
  430.     try new Message(in);    // errors are ignored
  431.     catch(IOException e);
  432.     }
  433.  
  434.     // rename
  435.     // Send a request to rename one file to another
  436.     void rename(String src, String dst) throws RequestException
  437.     {
  438.     Message m = new Message();
  439.     m.add("Request", "Rename");
  440.     m.add("Source", src);
  441.     m.add("Destination", dst);
  442.     m.send(out);
  443.     getreply();
  444.     }
  445.  
  446.     // purge
  447.     // Delete all versions of a file except for the latest
  448.     void purge(String file) throws RequestException
  449.     {
  450.     Message m = new Message();
  451.     m.add("Request", "Purge");
  452.     m.add("File", file);
  453.     m.send(out);
  454.     getreply();
  455.     }
  456.  
  457.     // chtype
  458.     // Change the MIME type of an existing file
  459.     void chtype(String file, String type) throws RequestException
  460.     {
  461.     Message m = new Message();
  462.     m.add("Request", "Chtype");
  463.     m.add("File", file);
  464.     m.add("Type", type);
  465.     m.send(out);
  466.     getreply();
  467.     }
  468.  
  469.     // send
  470.     // Send an arbitrary message to the server, and read back a reply
  471.     Message send(String req, Message m) throws RequestException
  472.     {
  473.     m.add("Request",req);
  474.     m.send(out);
  475.     return getreply();
  476.     }
  477.  
  478.     // getreply
  479.     // Read a reply from the server, throwing an exception if the
  480.     // reply was a Fail.
  481.     Message getreply() throws RequestException
  482.     {
  483.     Message r = null;
  484.     try r = new Message(in);
  485.     catch(IOException e)
  486.         throw new RequestException("Error reading reply : "+
  487.                        e.getMessage());
  488.     if (r.find("Reply").equals("Fail"))
  489.         throw new RequestException(r.find("Reason"));
  490.     return r;
  491.     }
  492.  
  493.     // canaccess
  494.     // Returns true if the current user can access the given file
  495.     // with the given access type.
  496.     boolean canaccess(String file, char p) throws RequestException
  497.     {
  498.     JFSfile fl = statfile(file);
  499.     JFSuser u = uinfo(authname);
  500.     return u.perms(fl).indexOf(p) != -1;
  501.     }
  502.  
  503.     // setcurrent
  504.     // Update the current file, directory and type based on a filename
  505.     void setcurrent(String full) throws RequestException
  506.     {
  507.     setcurrent(full, statfile(full).type);
  508.     }
  509.  
  510.     // setcurrent
  511.     // Update the current file, directory and type based on a filename
  512.     // and type.
  513.     void setcurrent(String full, String type)
  514.     {
  515.     currentdir = full.substring(0, full.lastIndexOf('/')+1);
  516.     currentfile = full.substring(full.lastIndexOf('/')+1);
  517.     currenttype = type;
  518.     }
  519. }
  520.  
  521. // RequestException
  522. // Thrown if a request fails for some reason
  523. class RequestException extends IOException
  524. {
  525.     RequestException() { }
  526.     RequestException(String s)
  527.     {
  528.     super(s);
  529.     }
  530. }
  531.  
  532. // CutBuffer
  533. // A buffer shared among multiple JFSclients started (typically) from the
  534. // same FileBrowser. The buf member points to an object of some type,
  535. // such as an Image, String or whatever. It should never be null.
  536. class CutBuffer
  537. {
  538.     Object buf;
  539.     CutBuffer() { buf = ""; }
  540. }
  541.  
  542.