diff options
Diffstat (limited to 'tdehtml/java/org/kde/kjas/server')
16 files changed, 4438 insertions, 0 deletions
diff --git a/tdehtml/java/org/kde/kjas/server/Console.java b/tdehtml/java/org/kde/kjas/server/Console.java new file mode 100644 index 000000000..d089f3cd8 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/Console.java @@ -0,0 +1,20 @@ +/* + * Appendable.java + * + * Created on 16. Mai 2002, 23:23 + */ + +package org.kde.kjas.server; + +/** + * + * @author till + */ +public interface Console { + + public void clear(); + public void append(String text); + + public void setVisible(boolean visible); + +} diff --git a/tdehtml/java/org/kde/kjas/server/KJASAppletClassLoader.java b/tdehtml/java/org/kde/kjas/server/KJASAppletClassLoader.java new file mode 100644 index 000000000..c6defa848 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASAppletClassLoader.java @@ -0,0 +1,360 @@ +package org.kde.kjas.server; + +import java.net.*; +import java.io.*; +import java.util.*; +import java.util.zip.*; +import java.util.jar.*; +import java.security.*; +/** + * ClassLoader used to download and instantiate Applets. + * <P> + * NOTE: The class loader extends Java 1.2 specific class. + */ +public final class KJASAppletClassLoader + extends URLClassLoader +{ + private static Hashtable loaders = new Hashtable(); + + public static synchronized void removeLoaders() + { + loaders.clear(); + } + + public static synchronized KJASAppletClassLoader getLoader( String docBase, String codeBase, String archives ) + { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + URL docBaseURL; + KJASAppletClassLoader loader = null; + try + { + docBaseURL = new URL( docBase ); + + URL codeBaseURL = getCodeBaseURL( docBaseURL, codeBase ); + String key = codeBaseURL.toString(); + if (archives != null) + key += archives; + + Main.debug( "CL: getLoader: key = " + key ); + + loader = (KJASAppletClassLoader) loaders.get( key ); + if( loader == null ) + { + URL [] urlList = {}; + loader = new KJASAppletClassLoader( urlList, docBaseURL, codeBaseURL); + loaders.put( key, loader ); + } + else + { + Main.debug( "CL: reusing classloader" ); + } + } catch( MalformedURLException e ) { Main.kjas_err( "bad DocBase URL", e ); } + return loader; + } + + public static URL getCodeBaseURL( URL docBaseURL, String codeBase ) + { + URL codeBaseURL = null; + try + { + //first determine what the real codeBase is: 3 cases + //#1. codeBase is absolute URL- use that + //#2. codeBase is relative to docBase, create url from those + //#3. last resort, use docBase as the codeBase + if(codeBase != null) + { + //we need to do this since codeBase should be a directory + if( !codeBase.endsWith("/") ) + codeBase = codeBase + "/"; + + try + { + codeBaseURL = new URL( codeBase ); + } catch( MalformedURLException mue ) + { + try + { + codeBaseURL = new URL( docBaseURL, codeBase ); + } catch( MalformedURLException mue2 ) {} + } + } + + if(codeBaseURL == null) + { + //fall back to docBase but fix it up... + String file = docBaseURL.getFile(); + if( file == null || (file.length() == 0) ) + codeBaseURL = docBaseURL; + else if( file.endsWith( "/" ) ) + codeBaseURL = docBaseURL; + else + { + //delete up to the ending '/' + String urlString = docBaseURL.toString(); + int dot_index = urlString.lastIndexOf( '/' ); + String newfile = urlString.substring( 0, dot_index+1 ); + codeBaseURL = new URL( newfile ); + } + } + }catch( Exception e ) { Main.kjas_err( "CL: exception ", e ); } + return codeBaseURL; + } + + public static KJASAppletClassLoader getLoader( String key ) + { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkCreateClassLoader(); + } + if( loaders.containsKey( key ) ) + return (KJASAppletClassLoader) loaders.get( key ); + + return null; + } + + /********************************************************************************* + ****************** KJASAppletClassLoader Implementation ************************* + **********************************************************************************/ + private URL docBaseURL; + private URL codeBaseURL; + private Vector archives; + private String dbgID; + private static int globalId = 0; + private int myId = 0; + private Vector statusListeners = new Vector(); + private AccessControlContext acc; + // a mapping JS referenced Java objects + private Hashtable jsReferencedObjects = new Hashtable(); + final static RuntimePermission kjas_access = new RuntimePermission("accessClassInPackage.org.kde.kjas.server"); + + public KJASAppletClassLoader( URL[] urlList, URL _docBaseURL, URL _codeBaseURL) + { + super(urlList); + acc = AccessController.getContext(); + synchronized(KJASAppletClassLoader.class) { + myId = ++globalId; + } + docBaseURL = _docBaseURL; + codeBaseURL = _codeBaseURL; + archives = new Vector(); + + dbgID = "CL-" + myId + "(" + codeBaseURL.toString() + "): "; + } + + protected void addURL(URL url) { + Main.debug(this + " add URL: " + url); + super.addURL(url); + } + + public void addStatusListener(StatusListener lsnr) { + statusListeners.add(lsnr); + } + public void removeStatusListener(StatusListener lsnr) { + statusListeners.remove(lsnr); + } + public void showStatus(String msg) { + Enumeration en = statusListeners.elements(); + while (en.hasMoreElements()) { + StatusListener lsnr = (StatusListener)en.nextElement(); + lsnr.showStatus(msg); + } + } + + public void paramsDone() { + // simply builds up the search path + // put the archives first because they are + // cached. + for( int i = 0; i < archives.size(); ++i ) { + String jar = (String)archives.elementAt( i ); + try { + URL jarURL = new URL(codeBaseURL, jar); + addURL(jarURL); + Main.debug("added archive URL \"" + jarURL + "\" to KJASAppletClassLoader"); + } catch (MalformedURLException e) { + Main.kjas_err("Could not construct URL for jar file: " + codeBaseURL + " + " + jar, e); + } + } + // finally add code base url and docbase url + addURL(codeBaseURL); + + // the docBaseURL has to be fixed. + // strip file part from end otherwise this + // will be interpreted as an archive + // (should this perhaps be done generally ??) + String dbs = docBaseURL.toString(); + int idx = dbs.lastIndexOf("/"); + if (idx > 0) { + dbs = dbs.substring(0, idx+1); + } + URL docDirURL = null; + try { + docDirURL = new URL(dbs); + } catch (MalformedURLException e) { + Main.debug("Could not make a new URL from docBaseURL=" + docBaseURL); + } + if (docDirURL != null && !codeBaseURL.equals(docDirURL)) { + addURL(docDirURL); + } + } + + void addArchiveName( String jarname ) + { + if( !archives.contains( jarname ) ) + { + archives.add( jarname ); + } + } + + + public URL getDocBase() + { + return docBaseURL; + } + + public URL getCodeBase() + { + return codeBaseURL; + } + + Hashtable getJSReferencedObjects() { + return jsReferencedObjects; + } + /*************************************************************************** + **** Class Loading Methods + **************************************************************************/ + public synchronized Class findClass( String name ) throws ClassNotFoundException + { + Class rval = null; + //check the loaded classes + rval = findLoadedClass( name ); + if( rval == null ) { + try { + rval = super.findClass(name); + } catch (ClassFormatError cfe) { + Main.debug(name + ": Catched " + cfe + ". Trying to repair..."); + rval = loadFixedClass( name ); + } catch (Exception ex) { + Main.debug("findClass " + name + " " + ex.getMessage()); + } + } + if (rval == null) { + throw new ClassNotFoundException("Class: " + name); + } + return rval; + } + public Class loadClass(String name) throws ClassNotFoundException { + if (name.startsWith("org.kde.kjas.server")) { + SecurityManager sec = System.getSecurityManager(); + if (sec != null) + sec.checkPermission(kjas_access); + } + return super.loadClass(name); + } + private Hashtable loadedClasses = new Hashtable(); + + private synchronized final Class loadFixedClass(String name) throws ClassNotFoundException { + final String fileName = name.replace('.', '/') + ".class"; + try { + // try to get the class as resource + final URL u = getResource(fileName); + Main.debug(dbgID + name + ": got URL: " + u); + if (u == null) { + throw new ClassNotFoundException(fileName + ": invalid resource URL."); + } + java.security.cert.Certificate[] certs = {}; // FIXME + CodeSource cs = new CodeSource(u, certs); + InputStream instream = (InputStream)AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + try { + return u.openStream(); + } catch (IOException ioe) { + ioe.printStackTrace(); + return null; + } + } + }, acc + ); + if (instream == null) { + throw new ClassNotFoundException(name + ": could not be loaded."); + } + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + int cnt; + int total = 0; + int bufSize = 1024; + byte [] buffer = new byte[bufSize]; + while ((cnt = instream.read(buffer, 0, bufSize)) > 0) { + total += cnt; + byteStream.write(buffer, 0, cnt); + } + Main.debug(dbgID + name + ": " + total + " bytes"); + + Class cl = fixAndDefineClass(name, byteStream.toByteArray(), 0, total, cs); + if (cl != null) { + loadedClasses.put(name, cl); + } + return cl; + + } catch (Throwable e) { + e.printStackTrace(); + throw new ClassNotFoundException("triggered by " + e); + } + } + + public URL findResource( String name) + { + Main.debug( dbgID + "findResource, name = " + name ); + String displayName = name; + try { + URL u = new URL(name); + String filename = u.getFile(); + if (filename != null && filename.length() > 0) { + displayName = filename; + } + } catch (Throwable e) { + } + showStatus("Loading: " + displayName); + URL url = super.findResource( name ); + Main.debug("findResource for " + name + " returns " + url); + return url; + } + + protected PermissionCollection getPermissions(CodeSource cs) { + Main.debug(dbgID + " getPermissions(" + cs + ")"); + PermissionCollection permissions = super.getPermissions(cs); + Enumeration perms_enum = permissions.elements(); + while (perms_enum.hasMoreElements()) { + Main.debug(this + " Permission: " + perms_enum.nextElement()); + } + return permissions; + } + + + /** + * define the class <b>name</b>. If <b>name</b> is broken, try to fix it. + */ + private final Class fixAndDefineClass( + String name, + byte[] b, + int off, + int len, + CodeSource cs) throws ClassFormatError + { + KJASBrokenClassFixer fixer = new KJASBrokenClassFixer(); + if (fixer.process(b, off, len)) { + Main.debug(name + " fixed"); + } else { + Main.info(name + " could not be fixed"); + } + return defineClass(name, + fixer.getProcessedData(), + fixer.getProcessedDataOffset(), + fixer.getProcessedDataLength(), + cs); + } + + +} diff --git a/tdehtml/java/org/kde/kjas/server/KJASAppletContext.java b/tdehtml/java/org/kde/kjas/server/KJASAppletContext.java new file mode 100644 index 000000000..f868b7b64 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASAppletContext.java @@ -0,0 +1,473 @@ +package org.kde.kjas.server; + +import java.applet.*; +import java.util.*; +import java.net.*; +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import org.kde.javascript.JSObject; + +final class KJASAuthenticator extends Authenticator { + private Hashtable authentication; + + KJASAuthenticator() { + authentication = new Hashtable(); + setDefault(this); + } + final void addURL(URL url, String user, String password, String authname) { + String key = new String(url.getProtocol() + ":" + url.getHost() + ":" + + url.getPort() + "_" + authname); + String [] auths = { user, password }; + authentication.put(key, auths); + } + final protected PasswordAuthentication getPasswordAuthentication() { + URL url; + String key = new String(getRequestingProtocol() + ":" + getRequestingHost() + ":" + getRequestingPort() + "_" + getRequestingPrompt()); + String [] auths = (String []) authentication.get(key); + if (auths != null) { + char [] pw = new char[auths[1].length()]; + auths[1].getChars(0, auths[1].length(), pw, 0); + return new PasswordAuthentication(auths[0], pw); + } + return null; + } +} + +/** + * The context in which applets live. + */ +public class KJASAppletContext implements AppletContext +{ + private Hashtable stubs; + private Hashtable images; + private Vector pendingImages; + private Hashtable streams; + private Stack jsobjects; + + private String myID; + private KJASAppletClassLoader loader; + private boolean active; + private final static KJASAuthenticator authenticator = new KJASAuthenticator(); + + /** + * Create a KJASAppletContext + */ + public KJASAppletContext( String _contextID ) + { + stubs = new Hashtable(); + images = new Hashtable(); + pendingImages = new Vector(); + streams = new Hashtable(); + jsobjects = new Stack(); + myID = _contextID; + active = true; + } + + public String getID() + { + return myID; + } + + public String getAppletID(Applet applet) + { + Enumeration e = stubs.keys(); + while ( e.hasMoreElements() ) + { + String appletID = (String) e.nextElement(); + KJASAppletStub stub = (KJASAppletStub) stubs.get(appletID); + if (stub.getApplet() == applet) + return appletID; + } + return null; + } + + public Applet getAppletById(String appletId) { + return ((KJASAppletStub) stubs.get( appletId )).getApplet(); + } + + public String getAppletName(String appletID) { + KJASAppletStub stub = (KJASAppletStub) stubs.get(appletID); + if (stub == null) + return null; + return stub.getAppletName(); + } + public void createApplet( String appletID, String name, + String className, String docBase, + String username, String password, String authname, + String codeBase, String archives, + String width, String height, + String windowName, Hashtable params ) + { + //do kludges to support mess with parameter table and + //the applet variables + String key = new String( "ARCHIVE" ); + if (params.containsKey(key)) { + String param_archive = (String)params.get(key); + if (archives == null) { + // There is no 'archive' attribute + // but a 'archive' param. fix archive list + // from param value + archives = param_archive; + } else { + // there is already an archive attribute. + // just add the value of the param to the list. + // But ignore bill$ personal archive format called + // .cab because java doesn't understand it. + if (!param_archive.toLowerCase().endsWith(".cab")) { + archives = param_archive + "," + archives; + } + } + } else if (archives != null) { + // add param if it is not present + params.put( key, archives); + } + + if( codeBase == null ) + { + key = new String( "CODEBASE" ); + if( params.containsKey( key ) ) + codeBase = (String) params.get( key ); + } + + if (username != null && !username.equals("")) { + try { + URL url = new URL(docBase); + int port = url.getPort(); + if (port < 0) + port = url.getDefaultPort(); + authenticator.addURL(new URL(url.getProtocol(), url.getHost(), port, ""), username, password, authname); + } catch (MalformedURLException muex) { + } + } + try + { + String sorted_archives = ""; + TreeSet archive_set = new TreeSet(); + if( archives != null ) + { + StringTokenizer parser = new StringTokenizer( archives, ",", false ); + while( parser.hasMoreTokens() ) + archive_set.add ( parser.nextToken().trim() ); + } + Iterator it = archive_set.iterator(); + while (it.hasNext()) + sorted_archives += (String) it.next(); + KJASAppletClassLoader loader = + KJASAppletClassLoader.getLoader( docBase, codeBase, sorted_archives ); + it = archive_set.iterator(); + while (it.hasNext()) + loader.addArchiveName( (String) it.next() ); + loader.paramsDone(); + + KJASAppletStub stub = new KJASAppletStub + ( + this, appletID, loader.getCodeBase(), + loader.getDocBase(), name, className, + new Dimension( Integer.parseInt(width), Integer.parseInt(height) ), + params, windowName, loader + ); + stubs.put( appletID, stub ); + + stub.createApplet(); + } + catch ( Exception e ) + { + Main.kjas_err( "Something bad happened in createApplet: " + e, e ); + } + } + + public void initApplet( String appletID ) + { + KJASAppletStub stub = (KJASAppletStub) stubs.get( appletID ); + if( stub == null ) + { + Main.debug( "could not init and show applet: " + appletID ); + } + else + { + stub.initApplet(); + } + } + + public void destroyApplet( String appletID ) + { + KJASAppletStub stub = (KJASAppletStub) stubs.get( appletID ); + + if( stub == null ) + { + Main.debug( "could not destroy applet: " + appletID ); + } + else + { + //Main.debug( "stopping applet: " + appletID ); + stubs.remove( appletID ); + + stub.destroyApplet(); + } + } + + public void startApplet( String appletID ) + { + KJASAppletStub stub = (KJASAppletStub) stubs.get( appletID ); + if( stub == null ) + { + Main.debug( "could not start applet: " + appletID ); + } + else + { + stub.startApplet(); + } + } + + public void stopApplet( String appletID ) + { + KJASAppletStub stub = (KJASAppletStub) stubs.get( appletID ); + if( stub == null ) + { + Main.debug( "could not stop applet: " + appletID ); + } + else + { + stub.stopApplet(); + } + } + + public void destroy() + { + Enumeration e = stubs.elements(); + while ( e.hasMoreElements() ) + { + KJASAppletStub stub = (KJASAppletStub) e.nextElement(); + stub.destroyApplet(); + stub.loader.getJSReferencedObjects().clear(); + } + + stubs.clear(); + active = false; + } + + /*************************************************************************** + **** AppletContext interface + ***************************************************************************/ + public Applet getApplet( String appletName ) + { + if( active ) + { + Enumeration e = stubs.elements(); + while( e.hasMoreElements() ) + { + KJASAppletStub stub = (KJASAppletStub) e.nextElement(); + + if( stub.getAppletName().equals( appletName ) ) + return stub.getApplet(); + } + } + + return null; + } + + public Enumeration getApplets() + { + if( active ) + { + Vector v = new Vector(); + Enumeration e = stubs.elements(); + while( e.hasMoreElements() ) + { + KJASAppletStub stub = (KJASAppletStub) e.nextElement(); + v.add( stub.getApplet() ); + } + + return v.elements(); + } + + return null; + } + + public AudioClip getAudioClip( URL url ) + { + Main.debug( "getAudioClip, url = " + url ); + //AudioClip clip = java.applet.Applet.newAudioClip(url); + AudioClip clip = new KJASAudioClip(url); + Main.debug( "got AudioClip " + clip); + return clip; + // return new KJASSoundPlayer( myID, url ); + } + + public void addImage( String url, byte[] data ) + { + Main.debug( "addImage for url = " + url ); + images.put( url, data ); + if (Main.cacheImages) { + pendingImages.remove(url); + } + } + + public Image getImage( URL url ) + { + if( active && url != null ) + { + // directly load images using JVM + if (true) { + // Main.info("Getting image using ClassLoader:" + url); + if (loader != null) { + url = loader.findResource(url.toString()); + //Main.debug("Resulting URL:" + url); + } + Toolkit kit = Toolkit.getDefaultToolkit(); + Image img = kit.createImage(url); + return img; + } + + //check with the Web Server + String str_url = url.toString(); + Main.debug( "getImage, url = " + str_url ); + if (Main.cacheImages && images.containsKey(str_url)) { + Main.debug("Cached: url=" + str_url); + } + else + { + if (Main.cacheImages) { + if (!pendingImages.contains(str_url)) { + Main.protocol.sendGetURLDataCmd( myID, str_url ); + pendingImages.add(str_url); + } + } else { + Main.protocol.sendGetURLDataCmd( myID, str_url ); + } + while( !images.containsKey( str_url ) && active ) + { + try { Thread.sleep( 200 ); } + catch( InterruptedException e ){} + } + } + if( images.containsKey( str_url ) ) + { + byte[] data = (byte[]) images.get( str_url ); + if( data.length > 0 ) + { + Toolkit kit = Toolkit.getDefaultToolkit(); + return kit.createImage( data ); + } else return null; + } + } + + return null; + } + + public void showDocument( URL url ) + { + //Main.debug( "showDocument, url = " + url ); + + if( active && (url != null) ) + { + Main.protocol.sendShowDocumentCmd( myID, url.toString() ); + } + } + + public void showDocument( URL url, String targetFrame ) + { + //Main.debug( "showDocument, url = " + url + " targetFrame = " + targetFrame ); + + if( active && (url != null) && (targetFrame != null) ) + { + Main.protocol.sendShowDocumentCmd( myID, url.toString(), targetFrame ); + } + } + + public void showStatus( String message ) + { + if( active && (message != null) ) + { + Main.protocol.sendShowStatusCmd( myID, message ); + } + } + public boolean evaluateJavaScript(String script, String appletID, JSObject jso) { + KJASAppletStub stub = (KJASAppletStub) stubs.get( appletID ); + if( active && stub != null && stub.isLoaded ()) { + if( jso != null ) { + synchronized (jsobjects) { + jsobjects.push(jso); + } + } + int [] types = { KJASAppletStub.JString }; + String [] arglist = { script }; + Main.protocol.sendJavaScriptEventCmd(myID, appletID, 0, "eval", types, arglist); + return true; + } + Main.debug( "evaluateJavaScript failure, context active:" + active + " stub:" + stub); + return false; + } + + public boolean getMember(String appletID, int callid, int objid, String name) + { + KJASAppletStub stub = (KJASAppletStub) stubs.get( appletID ); + if (stub == null || !stub.isLoaded()) + return false; + return stub.getMember(callid, objid, name); + } + + public boolean putMember(String appletID, int callid, int objid, String name, String value) + { + if (name.equals("__lc_ret")) { + // special case; return value of JS script evaluation + Main.debug("putValue: applet " + name + "=" + value); + JSObject jso = null; + synchronized (jsobjects) { + if (!jsobjects.empty()) + jso = (JSObject) jsobjects.pop(); + } + if (jso == null) + return false; + jso.returnvalue = value; + try { + jso.thread.interrupt(); + } catch (SecurityException ex) {} + Main.protocol.sendPutMember( myID, callid, true ); + } + KJASAppletStub stub = (KJASAppletStub) stubs.get( appletID ); + if (stub == null || !stub.isLoaded()) + return false; + return stub.putMember(callid, objid, name, value); + } + + public Object getJSReferencedObject(Applet applet, int objid) + { + return ((KJASAppletClassLoader)(applet.getClass().getClassLoader())).getJSReferencedObjects().get(new Integer(objid)); + } + boolean callMember(String appletID, int cid, int oid, String n, java.util.List args) + { + KJASAppletStub stub = (KJASAppletStub) stubs.get( appletID ); + if (stub == null || !stub.isLoaded()) + return false; + return stub.callMember( cid, oid, n, args); + } + public void derefObject(String appletID, int objid) { + if (objid == 0) + return; // that's an applet + KJASAppletStub stub = (KJASAppletStub) stubs.get( appletID ); + if (stub == null) + return; + Hashtable jsRefs = stub.loader.getJSReferencedObjects(); + if (jsRefs.remove(new Integer(objid)) == null) + Main.debug("couldn't remove referenced object"); + } + + public void setStream(String key, InputStream stream) throws IOException { + Main.debug("setStream, key = " + key); + streams.put(key, stream); + } + public InputStream getStream(String key){ + Main.debug("getStream, key = " + key); + return (InputStream) streams.get(key); + } + public Iterator getStreamKeys() { + Main.debug("getStreamKeys"); + return streams.keySet().iterator(); + } + + +} diff --git a/tdehtml/java/org/kde/kjas/server/KJASAppletPanel.java b/tdehtml/java/org/kde/kjas/server/KJASAppletPanel.java new file mode 100644 index 000000000..d7acbdaf9 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASAppletPanel.java @@ -0,0 +1,113 @@ +package org.kde.kjas.server; + +import java.applet.Applet; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.LayoutManager; +import java.awt.Panel; +import java.net.URL; + +/** + * @author till + * + * A panel which embeds the applet and shows some + * information during class loading. + */ +public class KJASAppletPanel extends javax.swing.JPanel implements StatusListener { + private final static int LOADING = 1; + private final static int RUNNING = 2; + private final static int FAILED = 3; + + private Image load_img = null; + private Image fail_img = null; + private int status = LOADING; + private Font font; + private String msg = "Loading Applet..."; + + /** + * Constructor for KJASAppletPanel. + */ + public KJASAppletPanel() { + super(new BorderLayout()); + font = new Font("SansSerif", Font.PLAIN, 10); + URL url = + getClass().getClassLoader().getResource("images/animbean.gif"); + load_img = getToolkit().createImage(url); + //setBackground(Color.white); + } + + void setApplet(Applet applet) { + add("Center", applet); + validate(); + } + + public void showStatus(String msg) { + this.msg = msg; + if (status != RUNNING) + repaint(); + } + + public void paint(Graphics g) { + super.paint(g); + if (status == RUNNING) + return; + Image img = (status == LOADING ? load_img : fail_img); + int x = getWidth() / 2; + int y = getHeight() / 2; + if (img != null) { + //synchronized (img) { + int w = img.getWidth(this); + int h = img.getHeight(this); + int imgx = x - w / 2; + int imgy = y - h / 2; + //g.setClip(imgx, imgy, w, h); + g.drawImage(img, imgx, imgy, this); + y += img.getHeight(this) / 2; + //} + } + if (msg != null) { + //synchronized(msg) { + g.setFont(font); + FontMetrics m = g.getFontMetrics(); + int h = m.getHeight(); + int w = m.stringWidth(msg); + int msgx = x - w / 2; + int msgy = y + h; + //g.setClip(0, y, getWidth(), h); + g.drawString(msg, msgx, msgy); + //} + } + } + void showFailed() { + URL url = + getClass().getClassLoader().getResource("images/brokenbean.gif"); + fail_img = getToolkit().createImage(url); + status = FAILED; + msg = "Applet Failed."; + repaint(); + } + + void showFailed(String message) { + showFailed(); + showStatus(message); + } + + public void stopAnimation() { + status = RUNNING; + } + + public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h) + { + if (img != null && img == load_img && status != LOADING) { + img.flush(); + load_img = null; + Main.debug("flushing image"); + return false; + } + return super.imageUpdate(img, flags, x, y, w, h); + } +} diff --git a/tdehtml/java/org/kde/kjas/server/KJASAppletStub.java b/tdehtml/java/org/kde/kjas/server/KJASAppletStub.java new file mode 100644 index 000000000..e090183d7 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASAppletStub.java @@ -0,0 +1,807 @@ +package org.kde.kjas.server; + +import java.applet.*; +import java.util.*; +import java.net.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.JFrame; +import java.security.PrivilegedAction; +import java.security.AccessController; +import java.security.AccessControlContext; +import java.security.ProtectionDomain; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * The stub used by Applets to communicate with their environment. + * + */ +public final class KJASAppletStub + implements AppletStub +{ + private KJASAppletContext context; // The containing context. + private Hashtable params; // Maps parameter names to values + private URL codeBase; // The URL directory where files are + private URL docBase; // The document that referenced the applet + private boolean active; // Is the applet active? + private String appletName; // The name of this applet instance + private String appletID; // The id of this applet- for use in callbacks + private Dimension appletSize; + private String windowName; + private String className; + private Class appletClass; + private JFrame frame; + + /** + * out of bounds applet state :-), perform an action + */ + public static final int ACTION = -1; + /** + * applet state unknown + */ + public static final int UNKNOWN = 0; + /** + * the applet class has been loaded + */ + public static final int CLASS_LOADED = 1; + /** + * the applet has been instanciated + */ + public static final int INSTANCIATED = 2; + /** + * the applet has been initialized + */ + public static final int INITIALIZED = 3; + /** + * the applet has been started + */ + public static final int STARTED = 4; + /** + * the applet has been stopped + */ + public static final int STOPPED = 5; + /** + * the applet has been destroyed + */ + public static final int DESTROYED = 6; + /** + * request for termination of the applet thread + */ + private static final int TERMINATE = 7; + /** + * like TERMINATE, an end-point state + */ + private static final int FAILED = 8; + + + //private KJASAppletClassLoader loader; + KJASAppletClassLoader loader; + private KJASAppletPanel panel; + private Applet app; + KJASAppletStub me; + + /** + * Interface for so called LiveConnect actions, put-, get- and callMember + */ + // keep this in sync with KParts::LiveConnectExtension::Type + private final static int JError = -1; + private final static int JVoid = 0; + private final static int JBoolean = 1; + private final static int JFunction = 2; + private final static int JNumber = 3; + private final static int JObject = 4; + final static int JString = 5; + + interface AppletAction { + void apply(); + void fail(); + } + + private class RunThread extends Thread { + private int request_state = CLASS_LOADED; + private int current_state = UNKNOWN; + private Vector actions = new Vector(); + private AccessControlContext acc = null; + + RunThread() { + super("KJAS-AppletStub-" + appletID + "-" + appletName); + setContextClassLoader(loader); + } + /** + * Ask applet to go to the next state + */ + synchronized void requestState(int nstate) { + if (nstate > current_state) { + request_state = nstate; + notifyAll(); + } + } + synchronized void requestAction(AppletAction action) { + actions.add(action); + notifyAll(); + } + /** + * Get the asked state + */ + synchronized private int getRequestState() { + while (request_state == current_state) { + if (!actions.isEmpty()) { + if (current_state >= INITIALIZED && current_state < STOPPED) + return ACTION; + else { + AppletAction action = (AppletAction) actions.remove(0); + action.fail(); + } + } else { + try { + wait (); + } catch(InterruptedException ie) { + } + } + } + if (request_state == DESTROYED && current_state == STARTED) + return current_state + 1; // make sure we don't skip stop() + return request_state; + } + /** + * Get the current state + */ + synchronized int getAppletState() { + return current_state; + } + /** + * Set the current state + */ + synchronized private void setState(int nstate) { + current_state = nstate; + } + /** + * Put applet in asked state + * Note, kjavaapletviewer asks for create/start/stop/destroy, the + * missing states instance/init/terminate, we do automatically + */ + private void doState(int nstate) throws ClassNotFoundException, IllegalAccessException, InstantiationException { + switch (nstate) { + case CLASS_LOADED: + appletClass = loader.loadClass( className ); + requestState(INSTANCIATED); + break; + case INSTANCIATED: { + Object object = null; + try { + object = appletClass.newInstance(); + app = (Applet) object; + } + catch ( ClassCastException e ) { + if ( object != null && object instanceof java.awt.Component) { + app = new Applet(); + app.setLayout(new BorderLayout()); + app.add( (Component) object, BorderLayout.CENTER); + } else + throw e; + } + acc = new AccessControlContext(new ProtectionDomain[] {app.getClass().getProtectionDomain()}); + requestState(INITIALIZED); + break; + } + case INITIALIZED: + app.setStub( me ); + app.setVisible(false); + panel.setApplet( app ); + if (appletSize.getWidth() > 0) + app.setBounds( 0, 0, appletSize.width, appletSize.height ); + else + app.setBounds( 0, 0, panel.getSize().width, panel.getSize().height ); + app.init(); + loader.removeStatusListener(panel); + // stop the loading... animation + panel.stopAnimation(); + app.setVisible(true); + break; + case STARTED: + active = true; + app.start(); + frame.validate(); + app.repaint(); + break; + case STOPPED: + active = false; + app.stop(); + if (Main.java_version > 1.399) { + // kill the windowClosing listener(s) + WindowListener[] l = frame.getWindowListeners(); + for (int i = 0; l != null && i < l.length; i++) + frame.removeWindowListener(l[i]); + } + frame.setVisible(false); + break; + case DESTROYED: + if (app != null) + app.destroy(); + frame.dispose(); + app = null; + requestState(TERMINATE); + break; + default: + return; + } + } + /** + * RunThread run(), loop until state is TERMINATE + */ + public void run() { + while (true) { + int nstate = getRequestState(); + if (nstate >= TERMINATE) + return; + if (nstate == ACTION) { + AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + AppletAction action = (AppletAction) actions.remove(0); + try { + action.apply(); + } catch (Exception ex) { + Main.debug("Error during action " + ex); + action.fail(); + } + return null; + } + }, + acc); + } else { // move to nstate + try { + doState(nstate); + } catch (Exception ex) { + Main.kjas_err("Error during state " + nstate, ex); + if (nstate < INITIALIZED) { + setState(FAILED); + setFailed(ex.toString()); + return; + } + } catch (Throwable tr) { + setState(FAILED); + setFailed(tr.toString()); + return; + } + setState(nstate); + stateChange(nstate); + } + } + } + } + private RunThread runThread = null; + + /** + * Create an AppletStub for the specified applet. The stub will be in + * the specified context and will automatically attach itself to the + * passed applet. + */ + public KJASAppletStub( KJASAppletContext _context, String _appletID, + URL _codeBase, URL _docBase, + String _appletName, String _className, + Dimension _appletSize, Hashtable _params, + String _windowName, KJASAppletClassLoader _loader ) + { + context = _context; + appletID = _appletID; + codeBase = _codeBase; + docBase = _docBase; + active = false; + appletName = _appletName; + className = _className.replace( '/', '.' ); + appletSize = _appletSize; + params = _params; + windowName = _windowName; + loader = _loader; + + String fixedClassName = _className; + if (_className.endsWith(".class") || _className.endsWith(".CLASS")) + { + fixedClassName = _className.substring(0, _className.length()-6); + } + else if (_className.endsWith(".java")|| _className.endsWith(".JAVA")) + { + fixedClassName = _className.substring(0, _className.length()-5); + } + className = fixedClassName.replace('/', '.'); + + appletClass = null; + me = this; + + + } + + private void stateChange(int newState) { + Main.protocol.sendAppletStateNotification( + context.getID(), + appletID, + newState); + } + + private void setFailed(String why) { + loader.removeStatusListener(panel); + panel.stopAnimation(); + panel.showFailed(); + Main.protocol.sendAppletFailed(context.getID(), appletID, why); + } + + void createApplet() { + panel = new KJASAppletPanel(); + frame = new JFrame(windowName); + // under certain circumstances, it may happen that the + // applet is not embedded but shown in a separate window. + // think of konqueror running under fvwm or gnome. + // than, the user should have the ability to close the window. + + frame.addWindowListener + ( + new WindowAdapter() { + public void windowClosing(WindowEvent e) { + me.destroyApplet(); + } + } + ); + frame.getContentPane().add( panel, BorderLayout.CENTER ); + try { + if (Main.java_version > 1.399) + frame.setUndecorated(true); + } catch(java.awt.IllegalComponentStateException e) { + // This happens with gcj 4.0.1, ignore for now... + } + frame.setLocation( 0, 0 ); + frame.pack(); + // resize frame for j2sdk1.5beta1.. + if (appletSize.getWidth() > 0) + frame.setBounds( 0, 0, appletSize.width, appletSize.height ); + else + frame.setBounds( 0, 0, 50, 50 ); + frame.setVisible(true); + loader.addStatusListener(panel); + runThread = new RunThread(); + runThread.start(); + } + + /** + * starts the applet managed by this stub by calling the applets start() method. + * Also marks this stub as active. + * @see java.applet.Applet#start() + * @see java.applet.AppletStub#isActive() + * + */ + void startApplet() + { + runThread.requestState(STARTED); + } + + /** + * stops the applet managed by this stub by calling the applets stop() method. + * Also marks this stub as inactive. + * @see java.applet.Applet#stop() + * @see java.applet.AppletStub#isActive() + * + */ + void stopApplet() + { + runThread.requestState(STOPPED); + } + + /** + * initialize the applet managed by this stub by calling the applets init() method. + * @see java.applet.Applet#init() + */ + void initApplet() + { + runThread.requestState(INITIALIZED); + } + + /** + * destroys the applet managed by this stub by calling the applets destroy() method. + * Also marks the the applet as inactive. + * @see java.applet.Applet#init() + */ + synchronized void destroyApplet() + { + runThread.requestState(DESTROYED); + } + + static void waitForAppletThreads() + { + Thread [] ts = new Thread[Thread.activeCount() + 5]; + int len = Thread.enumerate(ts); + for (int i = 0; i < len; i++) { + try { + if (ts[i].getName() != null && + ts[i].getName().startsWith("KJAS-AppletStub-")) { + try { + ((RunThread) ts[i]).requestState(TERMINATE); + ts[i].join(10000); + } catch (InterruptedException ie) {} + } + } catch (Exception e) {} + } + } + + /** + * get the Applet managed by this stub. + * @return the Applet or null if the applet could not be loaded + * or instanciated. + */ + Applet getApplet() + { + if (runThread != null && runThread.getAppletState() > CLASS_LOADED) + return app; + return null; + } + + /** + * get a parameter value given in the <APPLET> tag + * @param name the name of the parameter + * @return the value or null if no parameter with this name exists. + */ + + public String getParameter( String name ) + { + return (String) params.get( name.toUpperCase() ); + } + + /** + * implements the isActive method of the AppletStub interface. + * @return if the applet managed by this stub is currently active. + * @see java.applet.AppletStub#isActive() + */ + public boolean isActive() + { + return active; + } + + /** + * determines if the applet has been loaded and instanciated + * and can hence be used. + * @return true if the applet has been completely loaded. + */ + boolean isLoaded() { + if (runThread == null) + return false; + int state = runThread.getAppletState(); + return (state >= INSTANCIATED && state < DESTROYED); + } + + public void appletResize( int width, int height ) + { + if( active ) + { + if ( (width >= 0) && (height >= 0)) + { + Main.debug( "Applet #" + appletID + ": appletResize to : (" + width + ", " + height + ")" ); + Main.protocol.sendResizeAppletCmd( context.getID(), appletID, width, height ); + appletSize = new Dimension( width, height ); + //pack(); + } + } + } + + /** + * converts Object <b>arg</b> into an object of class <b>cl</b>. + * @param arg Object to convert + * @param cl Destination class + * @return An Object of the specified class with the value specified + * in <b>arg</b> + */ + private static final Object cast(Object arg, Class cl) throws NumberFormatException { + Object ret = arg; + if (arg == null) { + ret = null; + } + else if (cl.isAssignableFrom(arg.getClass())) { + return arg; + } + else if (arg instanceof String) { + String s = (String)arg; + Main.debug("Argument String: \"" + s + "\""); + if (cl == Boolean.TYPE || cl == Boolean.class) { + ret = new Boolean(s); + } else if (cl == Integer.TYPE || cl == Integer.class) { + ret = new Integer(s); + } else if (cl == Long.TYPE || cl == Long.class) { + ret = new Long(s); + } else if (cl == Float.TYPE || cl == Float.class) { + ret = new Float(s); + } else if (cl == Double.TYPE || cl == Double.class) { + ret = new Double(s); + } else if (cl == Short.TYPE || cl == Short.class) { + ret = new Short(s); + } else if (cl == Byte.TYPE || cl == Byte.class) { + ret = new Byte(s); + } else if (cl == Character.TYPE || cl == Character.class) { + ret = new Character(s.charAt(0)); + } + } + return ret; + } + private Method findMethod(Class c, String name, Class [] argcls) { + try { + Method[] methods = c.getMethods(); + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + if (m.getName().equals(name)) { + Main.debug("Candidate: " + m); + Class [] parameterTypes = m.getParameterTypes(); + if (argcls == null) { + if (parameterTypes.length == 0) { + return m; + } + } else { + if (argcls.length == parameterTypes.length) { + for (int j = 0; j < argcls.length; j++) { + // Main.debug("Parameter " + j + " " + parameterTypes[j]); + argcls[j] = parameterTypes[j]; + } + return m; + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + private int[] getJSTypeValue(Hashtable jsRefs, Object obj, int objid, StringBuffer value) { + String val = obj.toString(); + int[] rettype = { JError, objid }; + String type = obj.getClass().getName(); + if (type.equals("boolean") || type.equals("java.lang.Boolean")) + rettype[0] = JBoolean; + else if (type.equals("int") || type.equals("long") || + type.equals("float") || type.equals("double") || + type.equals("byte") || obj instanceof java.lang.Number) + rettype[0] = JNumber; + else if (type.equals("java.lang.String")) + rettype[0] = JString; + else if (!type.startsWith("org.kde.kjas.server") && + !(obj instanceof java.lang.Class && + ((Class)obj).getName().startsWith("org.kde.kjas.server"))) { + rettype[0] = JObject; + rettype[1] = obj.hashCode(); + jsRefs.put(new Integer(rettype[1]), obj); + } + value.insert(0, val); + return rettype; + } + private class PutAction implements AppletAction { + int call_id; + int objid; + String name; + String value; + PutAction(int cid, int oid, String n, String v) { + call_id = cid; + objid = oid; + name = n; + value = v; + } + public void apply() { + Hashtable jsRefs = loader.getJSReferencedObjects(); + Object o = objid==0 ? getApplet() : jsRefs.get(new Integer(objid)); + if (o == null) { + Main.debug("Error in putValue: object " + objid + " not found"); + fail(); + return; + } + Field f; + try { + f = o.getClass().getField(name); + } catch (Exception e) { + fail(); + return; + } + if (f == null) { + Main.debug("Error in putValue: " + name + " not found"); + fail(); + return; + } + try { + String type = f.getType().getName(); + Main.debug("putValue: (" + type + ")" + name + "=" + value); + if (type.equals("boolean")) + f.setBoolean(o, Boolean.getBoolean(value)); + else if (type.equals("java.lang.Boolean")) + f.set(o, Boolean.valueOf(value)); + else if (type.equals("int")) + f.setInt(o, Integer.parseInt(value)); + else if (type.equals("java.lang.Integer")) + f.set(o, Integer.valueOf(value)); + else if (type.equals("byte")) + f.setByte(o, Byte.parseByte(value)); + else if (type.equals("java.lang.Byte")) + f.set(o, Byte.valueOf(value)); + else if (type.equals("char")) + f.setChar(o, value.charAt(0)); + else if (type.equals("java.lang.Character")) + f.set(o, new Character(value.charAt(0))); + else if (type.equals("double")) + f.setDouble(o, Double.parseDouble(value)); + else if (type.equals("java.lang.Double")) + f.set(o, Double.valueOf(value)); + else if (type.equals("float")) + f.setFloat(o, Float.parseFloat(value)); + else if (type.equals("java.lang.Float")) + f.set(o, Float.valueOf(value)); + else if (type.equals("long")) + f.setLong(o, Long.parseLong(value)); + else if (type.equals("java.lang.Long")) + f.set(o, Long.valueOf(value)); + else if (type.equals("short")) + f.setShort(o, Short.parseShort(value)); + else if (type.equals("java.lang.Short")) + f.set(o, Short.valueOf(value)); + else if (type.equals("java.lang.String")) + f.set(o, value); + else { + Main.debug("Error putValue: unsupported type: " + type); + fail(); + return; + } + } catch (Exception e) { + Main.debug("Exception in putValue: " + e.getMessage()); + fail(); + return; + } + Main.protocol.sendPutMember( context.getID(), call_id, true ); + } + public void fail() { + Main.protocol.sendPutMember( context.getID(), call_id, false ); + } + } + private class GetAction implements AppletAction { + int call_id; + int objid; + String name; + GetAction(int cid, int oid, String n) { + call_id = cid; + objid = oid; + name = n; + } + public void apply() { + Main.debug("getMember: " + name); + StringBuffer value = new StringBuffer(); + int ret[] = { JError, objid }; + Hashtable jsRefs = loader.getJSReferencedObjects(); + Object o = objid==0 ? getApplet() : jsRefs.get(new Integer(objid)); + if (o == null) { + fail(); + return; + } + Class c = o.getClass(); + try { + Field field = c.getField(name); + ret = getJSTypeValue(jsRefs, field.get(o), objid, value); + } catch (Exception ex) { + Method [] m = c.getMethods(); + for (int i = 0; i < m.length; i++) + if (m[i].getName().equals(name)) { + ret[0] = JFunction; + break; + } + } + Main.protocol.sendMemberValue(context.getID(), KJASProtocolHandler.GetMember, call_id, ret[0], ret[1], value.toString()); + } + public void fail() { + Main.protocol.sendMemberValue(context.getID(), KJASProtocolHandler.GetMember, call_id, -1, 0, ""); + } + } + private class CallAction implements AppletAction { + int call_id; + int objid; + String name; + java.util.List args; + CallAction(int cid, int oid, String n, java.util.List a) { + call_id = cid; + objid = oid; + name = n; + args = a; + } + public void apply() { + StringBuffer value = new StringBuffer(); + Hashtable jsRefs = loader.getJSReferencedObjects(); + int [] ret = { JError, objid }; + Object o = objid==0 ? getApplet() : jsRefs.get(new Integer(objid)); + if (o == null) { + fail(); + return; + } + + try { + Main.debug("callMember: " + name); + Object obj; + Class c = o.getClass(); + String type; + Class [] argcls = new Class[args.size()]; + for (int i = 0; i < args.size(); i++) + argcls[i] = name.getClass(); // String for now, will be updated by findMethod + Method m = findMethod(c, (String) name, argcls); + Main.debug("Found Method: " + m); + if (m != null) { + Object [] argobj = new Object[args.size()]; + for (int i = 0; i < args.size(); i++) { + argobj[i] = cast(args.get(i), argcls[i]); + } + Object retval = m.invoke(o, argobj); + if (retval == null) + ret[0] = JVoid; + else + ret = getJSTypeValue(jsRefs, retval, objid, value); + } + } catch (Exception e) { + Main.debug("callMember threw exception: " + e.toString()); + } + Main.protocol.sendMemberValue(context.getID(), KJASProtocolHandler.CallMember, call_id, ret[0], ret[1], value.toString()); + } + public void fail() { + Main.protocol.sendMemberValue(context.getID(), KJASProtocolHandler.CallMember, call_id, -1, 0, ""); + } + } + boolean putMember(int callid, int objid, String name, String val) { + if (runThread == null) + return false; + runThread.requestAction( new PutAction( callid, objid, name, val) ); + return true; + } + boolean getMember(int cid, int oid, String name) { + if (runThread == null) + return false; + runThread.requestAction( new GetAction( cid, oid, name) ); + return true; + } + boolean callMember(int cid, int oid, String name, java.util.List args) { + if (runThread == null) + return false; + runThread.requestAction( new CallAction( cid, oid, name, args) ); + return true; + } + /************************************************************************* + ********************** AppletStub Interface ***************************** + *************************************************************************/ + /** + * implements the getAppletContext method of the AppletStub interface. + * @return the AppletContext to which this stub belongs. + * @see java.applet.AppletStub#getAppletContext() + */ + public AppletContext getAppletContext() + { + return context; + } + + /** + * implements the getCodeBase method of the AppletStub interface. + * @return the code base of the applet as given in the <APPLET> tag. + * @see java.applet.AppletStub#getCodeBase() + */ + public URL getCodeBase() + { + return codeBase; + } + + /** + * implements the getDocumentBase method of the AppletStub interface. + * @return the code base of the applet as given in the + * <APPLET> tag or determined by the containing page. + * @see java.applet.AppletStub#getDocumentBase() + */ + public URL getDocumentBase() + { + return docBase; + } + + /** + * get the applet's name + * @return the name of the applet as given in the + * <APPLET> tag or determined by the <em>code</em> parameter. + */ + public String getAppletName() + { + return appletName; + } + +} diff --git a/tdehtml/java/org/kde/kjas/server/KJASAudioClip.java b/tdehtml/java/org/kde/kjas/server/KJASAudioClip.java new file mode 100644 index 000000000..3a40cf6e0 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASAudioClip.java @@ -0,0 +1,98 @@ +package org.kde.kjas.server; + +import java.applet.*; +import java.net.*; +import java.util.*; +/** +* Background Audioclip Loader and Player. +* @author Till Krech (till@snafu.de) +*/ +public class KJASAudioClip implements AudioClip +{ + private AudioClip theClip; + private final static int PLAYING = 1; + private final static int LOOPING = 2; + private final static int STOPPED = 3; + private int state; + private static Hashtable cache = new Hashtable(); + + /** + * creates a new Audioclip. + * The AudioClip is loaded in background. The Constructor returns immediately. + */ + public KJASAudioClip(URL url) + { + state = STOPPED; + theClip = (AudioClip)cache.get(url); + if (theClip == null) { + final URL theUrl = url; + + new Thread + ( + new Runnable() { + public void run() { + theClip = java.applet.Applet.newAudioClip(theUrl); + cache.put(theUrl, theClip); + if (state == LOOPING) { + theClip.loop(); + } else if (state == PLAYING) { + theClip.play(); + } + } + }, "AudioClipLoader " + url.getFile() + ).start(); + } + } + + /** + * play continously when the clip is loaded + */ + public void loop() + { + state = LOOPING; + if (theClip != null) { + new Thread + ( + new Runnable() { + public void run() { + theClip.loop(); + } + }, "AudioClipLooper " + ).start(); + } + } + + /** + * play when the clip is loaded + */ + public void play() + { + state = PLAYING; + if (theClip != null) { + new Thread + ( + new Runnable() { + public void run() { + theClip.play(); + } + }, "AudioClipPlayer " + ).start(); + } + } + + /** + * stop the clip + */ + public void stop() + { + state = STOPPED; + if (theClip != null) { + theClip.stop(); + } + } + + public void finalize() { + stop(); + } +} + diff --git a/tdehtml/java/org/kde/kjas/server/KJASBrokenClassFixer.java b/tdehtml/java/org/kde/kjas/server/KJASBrokenClassFixer.java new file mode 100644 index 000000000..aab1be4af --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASBrokenClassFixer.java @@ -0,0 +1,132 @@ +package org.kde.kjas.server; +import java.lang.reflect.*; +import java.net.URLClassLoader; +import java.net.URL; +/** +* wrapper for the javaplugin.jar Broken11ClassFixer. +* Uses the reflection api to wrap the class <i>sun.plugin.security.Broken11ClassFixer</i> +* from the javaplugin.jar archive which can be found in the jre/lib directory. +*/ +public class KJASBrokenClassFixer { + private static Class fixerClass = null; + private static Method _process; + private static Method _getProcessedData; + private static Method _getProcessedDataOffset; + private static Method _getProcessedDataLength; + private static boolean initialized = false; + private static final String fixerClassName = "sun.plugin.security.Broken11ClassFixer"; + private Object fixer = null; + private byte [] bytes; + private int offset; + private int length; + + /** + * creates a new KJASBrokenClassFixer. + * If it is the first one to be created, it tries to load the class + * <i>sun.plugin.security.Broken11ClassFixer</i> from the jar file + * <i>lib/javaplugin.jar</i> in the java jre directory. + */ + public KJASBrokenClassFixer() { + init(); + if (fixerClass != null) { + try { + fixer = fixerClass.newInstance(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + /** + * loads the class <i>sun.plugin.security.Broken11ClassFixer</i>, + * initializes the methods, ... + */ + private synchronized void init() { + if (initialized) { + return; + } + try { + URL [] urls = { new URL( + "file", "", 0, + System.getProperty("java.home") + + System.getProperty("file.separator") + + "lib" + + System.getProperty("file.separator") + + "javaplugin.jar"), new URL( + "file", "", 0, + System.getProperty("java.home") + + System.getProperty("file.separator") + + "lib" + + System.getProperty("file.separator") + + "plugin.jar") + }; + URLClassLoader loader = new URLClassLoader(urls); + fixerClass = Class.forName(fixerClassName, true, loader); + Main.debug("Loaded " + fixerClass); + final Class [] parameterTypes = { + (new byte[1]).getClass(), + Integer.TYPE, + Integer.TYPE + }; + final Class [] noParameter = new Class[0]; + _process = fixerClass.getMethod("process", parameterTypes); + _getProcessedData = fixerClass.getMethod("getProcessedData", noParameter); + _getProcessedDataOffset = fixerClass.getMethod("getProcessedDataOffset", noParameter); + _getProcessedDataLength = fixerClass.getMethod("getProcessedDataLength", noParameter); + } catch (Throwable e) { + e.printStackTrace(); + } finally { + initialized = true; + } + } + /** + * scan the broken bytes and create new ones. + * If the wrapped class could not be loaded or + * no instance of Broken11ClassFixer could be instantiated, + * this is a noop and later calls to getProcessedData() etc. + * will return the original data passed as arguments in this + * call. + */ + public boolean process(byte [] b, int off, int len) { + if (fixer != null) { + try { + Object [] args = new Object[3]; + args[0] = b; + args[1] = new Integer(off); + args[2] = new Integer(len); + Object [] none = new Object[0]; + + _process.invoke(fixer, args); + this.bytes = (byte[])_getProcessedData.invoke(fixer, none); + this.offset = ((Integer)_getProcessedDataOffset.invoke(fixer, none)).intValue(); + this.length = ((Integer)_getProcessedDataLength.invoke(fixer, none)).intValue(); + return true; + } catch (Throwable e) { + } + } + this.bytes = b; + this.offset = off; + this.length = len; + return false; + } + + /** + * get the offset in the processed byte array + */ + public int getProcessedDataOffset() { + return offset; + } + /** + * get the length of the processed data + */ + public int getProcessedDataLength() { + return length; + } + /** + * get the processed (fixed) data + */ + public byte [] getProcessedData() { + return bytes; + } + +} diff --git a/tdehtml/java/org/kde/kjas/server/KJASConsole.java b/tdehtml/java/org/kde/kjas/server/KJASConsole.java new file mode 100644 index 000000000..51498b59b --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASConsole.java @@ -0,0 +1,93 @@ +package org.kde.kjas.server; + +import java.awt.*; +import java.awt.event.*; +import java.io.*; + +public class KJASConsole + extends Frame + implements Console +{ + private TextArea txt; + + public KJASConsole() + { + super("Konqueror Java Console"); + + txt = new TextArea(); + txt.setEditable(false); + txt.setBackground(Color.white); + txt.setForeground(Color.black); + + Panel main = new Panel(new BorderLayout()); + Panel btns = new Panel(new BorderLayout()); + + Button clear = new Button("Clear"); + Button close = new Button("Close"); + + btns.add(clear, "West"); + btns.add(close, "East"); + + main.add(txt, "Center"); + main.add(btns, "South"); + + add( main ); + + clear.addActionListener + ( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + txt.setText(""); + } + } + ); + + close.addActionListener + ( + new ActionListener() { + public void actionPerformed(ActionEvent e) { + setVisible(false); + } + } + ); + + addWindowListener + ( + new WindowAdapter() { + public void windowClosing(WindowEvent e) { + setVisible(false); + } + } + ); + + setSize(500, 300); + + PrintStream st = new PrintStream( new KJASConsoleStream(this) ); + System.setOut(st); + System.setErr(st); + + System.out.println( "Java VM version: " + + System.getProperty("java.version") ); + System.out.println( "Java VM vendor: " + + System.getProperty("java.vendor") ); + } + + public void clear() { + txt.setText(""); + } + + public void append(String msg) { + if (msg == null) { + return; + } + int length = msg.length(); + synchronized(txt) { + //get the caret position, and then get the new position + int old_pos = txt.getCaretPosition(); + txt.append(msg); + txt.setCaretPosition( old_pos + length ); + } + } +} + + diff --git a/tdehtml/java/org/kde/kjas/server/KJASConsoleStream.java b/tdehtml/java/org/kde/kjas/server/KJASConsoleStream.java new file mode 100644 index 000000000..2c1152ed4 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASConsoleStream.java @@ -0,0 +1,46 @@ +package org.kde.kjas.server; +import java.io.*; + +class KJASConsoleStream + extends OutputStream +{ + private Console console; + private FileOutputStream dbg_log; + + public KJASConsoleStream(Console console) + { + this.console = console; + + try + { + if( Main.log ) + { + dbg_log = new FileOutputStream( "/tmp/kjas.log"); + } + } + catch( FileNotFoundException e ) {} + } + + public void close() {} + public void flush() {} + public void write(byte[] b) {} + public void write(int a) {} + + // Should be enough for the console + public void write( byte[] bytes, int offset, int length ) + { + try // Just in case + { + String msg = new String( bytes, offset, length ); + console.append(msg); + if( Main.log && dbg_log != null ) + { + dbg_log.write( msg.getBytes() ); + dbg_log.flush(); + } + } + catch(Throwable t) {} + } +} + + diff --git a/tdehtml/java/org/kde/kjas/server/KJASProtocolHandler.java b/tdehtml/java/org/kde/kjas/server/KJASProtocolHandler.java new file mode 100644 index 000000000..f8b50a91d --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASProtocolHandler.java @@ -0,0 +1,900 @@ +package org.kde.kjas.server; + +import java.io.*; +import java.util.*; +import java.awt.*; +import java.net.*; + +/** + * Encapsulates the KJAS protocol and manages the contexts + * + */ +public class KJASProtocolHandler +{ + // Command codes- always need to be synced up with + // what's in kjavaappletserver.cpp + private static final int CreateContextCode = 1; + private static final int DestroyContextCode = 2; + private static final int CreateAppletCode = 3; + private static final int DestroyAppletCode = 4; + private static final int StartAppletCode = 5; + private static final int StopAppletCode = 6; + private static final int InitAppletCode = 7; + private static final int ShowDocumentCode = 8; + private static final int ShowURLInFrameCode = 9; + private static final int ShowStatusCode = 10; + private static final int ResizeAppletCode = 11; + private static final int GetURLDataCode = 12; + private static final int URLDataCode = 13; + private static final int ShutdownServerCode = 14; + private static final int JavaScriptEvent = 15; + static final int GetMember = 16; + static final int CallMember = 17; + private static final int PutMember = 18; + private static final int DerefObject = 19; + + private static final int AudioClipPlayCode = 20; + private static final int AudioClipLoopCode = 21; + private static final int AudioClipStopCode = 22; + + private static final int AppletStateNotificationCode = 23; + private static final int AppletFailedCode = 24; + private static final int DataCommand = 25; + private static final int PutURLDataCode = 26; + private static final int PutDataCode = 27; + private static final int SecurityConfirmCode = 28; + private static final int ShowConsole = 29; + + //Holds contexts in contextID-context pairs + private Hashtable contexts; + + private PushbackInputStream commands; //Stream for reading in commands + private PrintStream signals; //Stream for writing out callbacks + + //used for parsing each command as it comes in + private int cmd_index; + private final static char sep = (char) 0; + + public KJASProtocolHandler( InputStream _commands, + OutputStream _signals ) + { + commands = new PushbackInputStream( _commands ); + signals = new PrintStream( _signals ); + contexts = new Hashtable(); + } + + public void commandLoop() + { + try + { + while( true ) + { + try + { + int cmd_length = readPaddedLength( 8 ); + Main.debug( "PH: cmd_length = " + cmd_length ); + + //We need to have this while loop since we're not guaranteed to get + //all the bytes we want back, especially with large jars + byte[] cmd_data = new byte[cmd_length]; + int total_read = 0; + while( total_read < cmd_length ) + { + int numread = commands.read( cmd_data, total_read, cmd_length-total_read ); + Main.debug( "PH: read in " + numread + " bytes for command" ); + total_read += numread; + } + + //parse the rest of the command and execute it + processCommand( cmd_data ); + } + catch( NumberFormatException e ) + { + Main.kjas_err( "Could not parse out message length", e ); + e.printStackTrace(); + System.exit( 1 ); + } + catch( Throwable t ) + { + Main.debug( "commandLoop caught a throwable, still going" ); + t.printStackTrace(); + } + } + } + catch( Exception i ) + { + Main.kjas_err( "commandLoop exited on exception: ", i ); + i.printStackTrace(); + System.exit( 1 ); + } + } + + public void processCommand( byte[] command ) + { + // Sanity checks + if ( command == null ) + return; + + //do all the parsing here and pass arguments as individual variables to the + //handler functions + int cmd_length = command.length; + cmd_index = 0; + + int cmd_code_value = (int) command[cmd_index++]; + if( cmd_code_value == CreateContextCode ) + { + //parse out contextID- 1 argument + String contextID = getArg( command ); + Main.debug( "createContext, id = " + contextID ); + + KJASAppletContext context = new KJASAppletContext( contextID ); + contexts.put( contextID, context ); + } else + if( cmd_code_value == DestroyContextCode ) + { + //parse out contextID- 1 argument + String contextID = getArg( command ); + Main.debug( "destroyContext, id = " + contextID ); + + KJASAppletContext context = (KJASAppletContext) contexts.get( contextID ); + if( contexts != null ) + { + context.destroy(); + contexts.remove( contextID ); + } + } else + if( cmd_code_value == CreateAppletCode ) + { + //9 arguments- this order is important... + final String contextID = getArg( command ); + final String appletID = getArg( command ); + final String appletName = getArg( command ); + final String className = getArg( command ); + final String baseURL = getArg( command ); + final String username = getArg( command ); + final String password = getArg( command ); + final String authname = getArg( command ); + final String codeBase = getArg( command ); + final String archives = getArg( command ); + final String width = getArg( command ); + final String height = getArg( command ); + final String title = getArg( command ); + + //get the number of parameter pairs... + String str_params = getArg( command ); + int num_params = Integer.parseInt( str_params.trim() ); + final Hashtable params = new Hashtable(); + for( int i = 0; i < num_params; i++ ) + { + String name = getArg( command ); // note name is in uppercase + if( name == null ) + name = new String(); + + String value = getArg( command ); + if( value == null ) + value = new String(); + params.put( name, value ); + //Main.debug( "parameter, name = " + name + ", value = " + value ); + } + + Main.debug( "createApplet, context = " + contextID + ", applet = " + appletID ); + Main.debug( " name = " + appletName + ", classname = " + className ); + Main.debug( " baseURL = " + baseURL + ", codeBase = " + codeBase ); + Main.debug( " archives = " + archives + ", width = " + width + + ", height = " + height ); + + final KJASAppletContext context = (KJASAppletContext) contexts.get( contextID ); + if( context != null ) + { + context.createApplet( appletID, appletName, className, + baseURL, username, password, authname, + codeBase, archives, + width, height, title, params ); + } + + } else + if( cmd_code_value == DestroyAppletCode ) + { + //2 arguments + String contextID = getArg( command ); + String appletID = getArg( command ); + Main.debug( "destroyApplet, context = " + contextID + ", applet = " + appletID ); + + KJASAppletContext context = (KJASAppletContext) contexts.get( contextID ); + if ( context != null ) + context.destroyApplet( appletID ); + } else + if( cmd_code_value == StartAppletCode ) + { + //2 arguments + String contextID = getArg( command ); + String appletID = getArg( command ); + Main.debug( "startApplet, context = " + contextID + ", applet = " + appletID ); + + KJASAppletContext context = (KJASAppletContext) contexts.get( contextID ); + if ( context != null ) + context.startApplet( appletID ); + } else + if( cmd_code_value == StopAppletCode ) + { + //2 arguments + String contextID = getArg( command ); + String appletID = getArg( command ); + Main.debug( "stopApplet, context = " + contextID + ", applet = " + appletID ); + + KJASAppletContext context = (KJASAppletContext) contexts.get( contextID ); + if ( context != null ) + context.stopApplet( appletID ); + } else + if( cmd_code_value == ShutdownServerCode ) + { + Main.debug( "shutDownServer received" ); + KJASAppletStub.waitForAppletThreads(); + System.exit( 1 ); + } + else + if( cmd_code_value == URLDataCode ) + { + + String id = getArg( command ); + String code = getArg( command ); + Main.debug( "KIO URLData received(" + id + ") code:" + code ); + + //rest of the command should be the data... + byte[] data = null; + if (cmd_length - cmd_index > 0) { + data = new byte[ cmd_length - cmd_index ]; + System.arraycopy( command, cmd_index, data, 0, data.length ); + } + KIOConnection.setData(id, Integer.parseInt(code), data); + } else + if (cmd_code_value == GetMember) + { + int ticketnr = Integer.parseInt( getArg( command ) ); + String contextID = getArg( command ); + String appletID = getArg( command ); + int objid = Integer.parseInt( getArg( command ) ); + String name = getArg( command ); + KJASAppletContext context = (KJASAppletContext) contexts.get( contextID ); + if ( context == null || !context.getMember(appletID, ticketnr, objid, name)) + sendMemberValue(contextID, GetMember, ticketnr, -1, 0, ""); + } else + if (cmd_code_value == PutMember) + { + int ticketnr = Integer.parseInt( getArg( command ) ); + String contextID = getArg( command ); + String appletID = getArg( command ); + int objid = Integer.parseInt( getArg( command ) ); + String name = getArg( command ); + String value = getArg( command ); + boolean ret = false; + KJASAppletContext context = (KJASAppletContext) contexts.get( contextID ); + if (context == null || !context.putMember(appletID, ticketnr, objid, name, value)) + sendPutMember(contextID, ticketnr, false); + } else + if (cmd_code_value == CallMember) + { + int ticketnr = Integer.parseInt( getArg( command ) ); + String contextID = getArg( command ); + String appletID = getArg( command ); + int objid = Integer.parseInt( getArg( command ) ); + String name = getArg( command ); + int arg_count = Integer.parseInt( getArg( command ) ); + java.util.List args = new java.util.Vector(); + try { // fix getArg + String param = getArg(command); + while (arg_count-- > 0) { + if (param == null) + param = new String(); + args.add(param); + param = getArg(command); + } + } catch (Exception e) {} + + KJASAppletContext context = (KJASAppletContext) contexts.get( contextID ); + if ( context == null || !context.callMember(appletID, ticketnr, objid, name, args)) + Main.protocol.sendMemberValue(contextID, CallMember, ticketnr, -1, 0, ""); + } else + if (cmd_code_value == DerefObject) + { + String contextID = getArg( command ); + String appletID = getArg( command ); + String objid = getArg( command ); + KJASAppletContext context = (KJASAppletContext) contexts.get( contextID ); + if ( context != null ) + context.derefObject(appletID, Integer.parseInt(objid)); + Main.debug( "DerefObject " + objid); + } else + if (cmd_code_value == SecurityConfirmCode) + { + String id = getArg( command ); + String confirm = getArg( command ); + Thread t = (Thread) KJASSecurityManager.confirmRequests.get(id); + Main.debug( "SecurityConfirmCode " + id + " confirm:" + confirm ); + if (t != null) { + KJASSecurityManager.confirmRequests.put(id, confirm); + try { + t.interrupt(); + } catch (SecurityException se) {} + } + } else + if (cmd_code_value == ShowConsole) + { + Main.console.setVisible(true); + } + else + { + throw new IllegalArgumentException( "Unknown command code" ); + } + } + + /************************************************************** + ***** Methods for talking to the applet server ************** + **************************************************************/ + + /** + * sends get url request + */ + public void sendGetURLDataCmd( String jobid, String url ) + { + Main.debug( "sendGetURLCmd(" + jobid + ") url = " + url ); + //length = length of args plus 1 for code, 2 for seps and 1 for end + byte [] url_bytes = url.getBytes(); + int length = jobid.length() + url_bytes.length + 4; + byte [] bytes = new byte[ length + 8 ]; + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) GetURLDataCode; + bytes[index++] = sep; + + tmp_bytes = jobid.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( url_bytes, 0, bytes, index, url_bytes.length ); + index += url_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + + /** + * sends command for get url request (stop/hold/resume) or put (stop) + */ + public void sendDataCmd( String id, int cmd ) + { + Main.debug( "sendDataCmd(" + id + ") command = " + cmd ); + byte [] cmd_bytes = String.valueOf( cmd ).getBytes(); + int length = id.length() + cmd_bytes.length + 4; + byte [] bytes = new byte[ length + 8 ]; + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) DataCommand; + bytes[index++] = sep; + + tmp_bytes = id.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( cmd_bytes, 0, bytes, index, cmd_bytes.length ); + index += cmd_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + /** + * sends put url request + */ + public void sendPutURLDataCmd( String jobid, String url ) + { + Main.debug( "sendPutURLCmd(" + jobid + ") url = " + url ); + //length = length of args plus 1 for code, 2 for seps and 1 for end + byte [] url_bytes = url.getBytes(); + int length = jobid.length() + url_bytes.length + 4; + byte [] bytes = new byte[ length + 8 ]; + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) PutURLDataCode; + bytes[index++] = sep; + + tmp_bytes = jobid.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( url_bytes, 0, bytes, index, url_bytes.length ); + index += url_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + /** + * sends put data + */ + public void sendPutData( String jobid, byte [] b, int off, int len ) + { + Main.debug( "sendPutData(" + jobid + ") len = " + len ); + //length = length of args plus 1 for code, 2 for seps and 1 for end + int length = jobid.length() + len + 4; + byte [] bytes = new byte[ length + 8 ]; + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) PutDataCode; + bytes[index++] = sep; + + tmp_bytes = jobid.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( b, off, bytes, index, len ); + index += len; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + /** + * sends notification about the state of the applet. + * @see org.kde.kjas.server.KJASAppletStub for valid states + */ + public void sendAppletStateNotification( String contextID, String appletID, int state ) + { + Main.debug( "sendAppletStateNotification, contextID = " + contextID + ", appletID = " + + appletID + ", state=" + state ); + + byte [] state_bytes = String.valueOf( state ).getBytes(); + + int length = contextID.length() + appletID.length() + state_bytes.length + 5; + byte [] bytes = new byte[ length + 8 ]; //for length of message + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) AppletStateNotificationCode; + bytes[index++] = sep; + + tmp_bytes = contextID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + tmp_bytes = appletID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( state_bytes, 0, bytes, index, state_bytes.length ); + index += state_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + + /** + * sends notification about applet failure. + * This can happen in any state. + * @param contextID context ID of the applet's context + * @param appletID ID of the applet + * @param errorMessage any message + */ + public void sendAppletFailed ( String contextID, String appletID, String errorMessage) + { + Main.debug( "sendAppletFailed, contextID = " + contextID + ", appletID = " + + appletID + ", errorMessage=" + errorMessage ); + byte [] msg_bytes = errorMessage.getBytes(); + int length = contextID.length() + appletID.length() + msg_bytes.length + 5; + byte [] bytes = new byte[ length + 8 ]; //for length of message + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) AppletFailedCode; + bytes[index++] = sep; + + tmp_bytes = contextID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + tmp_bytes = appletID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( msg_bytes, 0, bytes, index, msg_bytes.length ); + index += msg_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + + public void sendShowDocumentCmd( String loaderKey, String url ) + { + Main.debug( "sendShowDocumentCmd from context#" + loaderKey + " url = " + url ); + + //length = length of args + 2 for seps + 1 for end + 1 for code + byte [] url_bytes = url.getBytes(); + byte [] key_bytes = loaderKey.getBytes(); + int length = key_bytes.length + url_bytes.length + 4; + byte [] bytes = new byte[ length + 8 ]; //8 for the length of this message + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) ShowDocumentCode; + bytes[index++] = sep; + + System.arraycopy( key_bytes, 0, bytes, index, key_bytes.length ); + index += key_bytes.length; + bytes[index++] = sep; + + System.arraycopy( url_bytes, 0, bytes, index, url_bytes.length ); + index += url_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + + public void sendShowDocumentCmd( String contextID, String url, String frame) + { + Main.debug( "sendShowDocumentCmd from context#" + contextID + + " url = " + url + ", frame = " + frame ); + + //length = length of args plus code, 3 seps, end + byte [] url_bytes = url.getBytes(); + byte [] frame_bytes = frame.getBytes(); + int length = contextID.length() + url_bytes.length + frame_bytes.length + 5; + byte [] bytes = new byte[ length + 8 ]; //for length of message + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) ShowURLInFrameCode; + bytes[index++] = sep; + + tmp_bytes = contextID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( url_bytes, 0, bytes, index, url_bytes.length ); + index += url_bytes.length; + bytes[index++] = sep; + + System.arraycopy( frame_bytes, 0, bytes, index, frame_bytes.length ); + index += frame_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + + public void sendShowStatusCmd( String contextID, String msg ) + { + Main.debug( "sendShowStatusCmd, contextID = " + contextID + " msg = " + msg ); + + byte [] msg_bytes = msg.getBytes(); + int length = contextID.length() + msg_bytes.length + 4; + byte [] bytes = new byte[ length + 8 ]; //for length of message + int index = 0; + + byte [] tmp_bytes = getPaddedLengthBytes( length ); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) ShowStatusCode; + bytes[index++] = sep; + + tmp_bytes = contextID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( msg_bytes, 0, bytes, index, msg_bytes.length ); + index += msg_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + + public void sendResizeAppletCmd( String contextID, String appletID, + int width, int height ) + { + Main.debug( "sendResizeAppletCmd, contextID = " + contextID + ", appletID = " + + appletID + ", width = " + width + ", height = " + height ); + + byte [] width_bytes = String.valueOf( width ).getBytes(); + byte [] height_bytes = String.valueOf( height ).getBytes(); + + //length = length of args plus code, 4 seps, end + int length = contextID.length() + appletID.length() + width_bytes.length + + height_bytes.length + 6; + byte [] bytes = new byte[ length + 8 ]; //for length of message + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) ResizeAppletCode; + bytes[index++] = sep; + + tmp_bytes = contextID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + tmp_bytes = appletID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( width_bytes, 0, bytes, index, width_bytes.length ); + index += width_bytes.length; + bytes[index++] = sep; + + System.arraycopy( height_bytes, 0, bytes, index, height_bytes.length ); + index += height_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + public void sendJavaScriptEventCmd( String contextID, String appletID, int objid, String event, int [] types, String [] args ) + { + Main.debug( "sendJavaScriptEventCmd, contextID = " + contextID + " event = " + event ); + String objstr = new String("" + objid); + int length = contextID.length() + appletID.length() + event.length() + objstr.length() + 6; + byte [][][] arglist = null; + if (types != null) { + arglist = new byte[args.length][2][]; + for (int i = 0; i < types.length; i++) { + arglist[i][0] = (new String("" + types[i])).getBytes(); + arglist[i][1] = args[i].getBytes(); + length += 2 + arglist[i][0].length + arglist[i][1].length; + } + } + byte [] bytes = new byte[ length + 8 ]; //for length of message + int index = 0; + + byte [] tmp_bytes = getPaddedLengthBytes( length ); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) JavaScriptEvent; + bytes[index++] = sep; + + tmp_bytes = contextID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + tmp_bytes = appletID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + tmp_bytes = objstr.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + tmp_bytes = event.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + if (types != null) + for (int i = 0; i < types.length; i++) { + System.arraycopy( arglist[i][0], 0, bytes, index, arglist[i][0].length ); + index += arglist[i][0].length; + bytes[index++] = sep; + System.arraycopy( arglist[i][1], 0, bytes, index, arglist[i][1].length ); + index += arglist[i][1].length; + bytes[index++] = sep; + } + + signals.write( bytes, 0, bytes.length ); + } + public void sendMemberValue( String contextID, int cmd, int ticketnr, int type, int rid, String value ) + { + Main.debug( "sendMemberValue, contextID = " + contextID + " value = " + value + " type=" + type + " rid=" + rid ); + + String strticket = String.valueOf( ticketnr ); + String strtype = String.valueOf( type ); + String strobj = String.valueOf( rid ); + byte [] value_bytes = value.getBytes(); + int length = contextID.length() + value_bytes.length + strtype.length() + strobj.length() + strticket.length() + 7; + byte [] bytes = new byte[ length + 8 ]; //for length of message + int index = 0; + + byte [] tmp_bytes = getPaddedLengthBytes( length ); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) cmd; + bytes[index++] = sep; + + tmp_bytes = contextID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + tmp_bytes = strticket.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + tmp_bytes = strtype.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + tmp_bytes = strobj.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( value_bytes, 0, bytes, index, value_bytes.length ); + index += value_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + + private void sendAudioClipCommand(String contextId, String url, int cmd) { + byte [] url_bytes = url.getBytes(); + int length = contextId.length() + url_bytes.length + 4; + byte [] bytes = new byte[ length + 8 ]; + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) cmd; + bytes[index++] = sep; + + tmp_bytes = contextId.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( url_bytes, 0, bytes, index, url_bytes.length ); + index += url_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + + public void sendAudioClipPlayCommand(String contextId, String url) { + sendAudioClipCommand(contextId, url, AudioClipPlayCode); + } + public void sendAudioClipLoopCommand(String contextId, String url) { + sendAudioClipCommand(contextId, url, AudioClipLoopCode); + } + public void sendAudioClipStopCommand(String contextId, String url) { + sendAudioClipCommand(contextId, url, AudioClipStopCode); + } + + public void sendPutMember( String contextID, int ticketnr, boolean success ) + { + Main.debug("sendPutMember, contextID = " + contextID + " success = " + success); + + byte [] ticket_bytes = String.valueOf( ticketnr ).getBytes(); + byte [] ret_bytes = String.valueOf( success ? "1" : "0" ).getBytes(); + int length = contextID.length() + ret_bytes.length + ticket_bytes.length + 5; + byte [] bytes = new byte[ length + 8 ]; //for length of message + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) PutMember; + bytes[index++] = sep; + + tmp_bytes = contextID.getBytes(); + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = sep; + + System.arraycopy( ticket_bytes, 0, bytes, index, ticket_bytes.length ); + index += ticket_bytes.length; + bytes[index++] = sep; + + System.arraycopy( ret_bytes, 0, bytes, index, ret_bytes.length ); + index += ret_bytes.length; + bytes[index++] = sep; + + signals.write( bytes, 0, bytes.length ); + } + public void sendSecurityConfirm( String [] certs, int certsnr, String perm, String id ) + { + Main.debug("sendSecurityConfirm, ID = " + id + " certsnr = " + certsnr); + + byte [] id_bytes = id.getBytes(); + byte [] perm_bytes = perm.getBytes(); + byte [] certsnr_bytes = String.valueOf( certsnr ).getBytes(); + int length = perm_bytes.length + id_bytes.length + certsnr_bytes.length + 5; + for (int i = 0; i < certsnr; i++) + length += certs[i].length() + 1; + byte [] bytes = new byte[ length + 8 ]; //for length of message + byte [] tmp_bytes = getPaddedLengthBytes( length ); + int index = 0; + + System.arraycopy( tmp_bytes, 0, bytes, index, tmp_bytes.length ); + index += tmp_bytes.length; + bytes[index++] = (byte) SecurityConfirmCode; + bytes[index++] = sep; + + System.arraycopy( id_bytes, 0, bytes, index, id_bytes.length ); + index += id_bytes.length; + bytes[index++] = sep; + + System.arraycopy( perm_bytes, 0, bytes, index, perm_bytes.length ); + index += perm_bytes.length; + bytes[index++] = sep; + + System.arraycopy( certsnr_bytes, 0, bytes, index, certsnr_bytes.length ); + index += certsnr_bytes.length; + bytes[index++] = sep; + + for (int i = 0; i < certsnr; i++) { + byte [] cert_bytes = certs[i].getBytes(); + System.arraycopy( cert_bytes, 0, bytes, index, cert_bytes.length ); + index += cert_bytes.length; + bytes[index++] = sep; + } + + signals.write( bytes, 0, bytes.length ); + } + /************************************************************** + ***** Utility functions for parsing commands **************** + **************************************************************/ + private String getArg( byte[] command ) + { + int begin = cmd_index; + while( 0 != ((int) command[cmd_index++]) ); + + if( cmd_index > (begin + 1) ) + { + String rval = new String( command, begin, (cmd_index - begin - 1) ); + return rval; + } + else + return null; + } + + private byte[] getPaddedLengthBytes( int length ) + { + byte[] length_bytes = String.valueOf( length ).getBytes(); + if( length_bytes.length > 8 ) + throw new IllegalArgumentException( "can't create string number of length = 8" ); + byte [] bytes = { (byte) ' ', (byte) ' ', (byte) ' ', (byte) ' ', + (byte) ' ', (byte) ' ', (byte) ' ', (byte) ' '}; + System.arraycopy( length_bytes, 0, bytes, 0, length_bytes.length ); + return bytes; + } + private int readPaddedLength( int string_size ) + throws IOException + { + //read in 8 bytes for command length- length will be sent as a padded string + byte[] length = new byte[string_size]; + commands.read( length, 0, string_size ); + + String length_str = new String( length ); + return Integer.parseInt( length_str.trim() ); + } + +} diff --git a/tdehtml/java/org/kde/kjas/server/KJASSecurityManager.java b/tdehtml/java/org/kde/kjas/server/KJASSecurityManager.java new file mode 100644 index 000000000..0525bba0c --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASSecurityManager.java @@ -0,0 +1,243 @@ +package org.kde.kjas.server; + +import java.security.*; +import java.security.cert.*; +import java.net.*; +import java.util.*; + + +public class KJASSecurityManager extends SecurityManager +{ + static Hashtable confirmRequests = new Hashtable(); + static int confirmId = 0; + Hashtable grantedPermissions = new Hashtable(); + HashSet grantAllPermissions = new HashSet(); + HashSet rejectAllPermissions = new HashSet(); + + private static final char [] base64table = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + static String encode64( byte [] data) + { + StringBuffer buf = new StringBuffer( 4*((data.length + 2)/3) ); + int i = 0, b1, b2, b3; + while (i < data.length - 2) { + b1 = data[i++]; + b2 = data[i++]; + b3 = data[i++]; + buf.append( base64table[(b1 >>> 2) & 0x3F] ); + buf.append( base64table[((b1 << 4) & 0x30) | ((b2 >>> 4) & 0xF)] ); + buf.append( base64table[((b2 << 2) & 0x3C) | ((b3 >>> 6) & 0x03)] ); + buf.append( base64table[b3 & 0x3F] ); + } + if ( i < data.length ) { + b1 = data[i++]; + buf.append( base64table[(b1 >>> 2) & 0x3F] ); + if ( i < data.length ) { + b2 = data[i++]; + buf.append( base64table[((b1 << 4) & 0x30) | ((b2 >>> 4) & 0xF)] ); + buf.append( base64table[(b2 << 2) & 0x3C] ); + } else { + buf.append( base64table[(b1 << 4) & 0x30] ); + buf.append( "=" ); + } + buf.append( '=' ); + } + return buf.toString(); + } + public KJASSecurityManager() + { + } + /** + * checks for an applets permission to access certain resources + * currently, only a check for SocketPermission is done, that the + * applet cannot connect to any other but the host, where it comes from. + * Anything else seems to be handled automagically + */ + public void checkPermission(Permission perm) throws SecurityException, NullPointerException { + // ClassLoader cl = Thread.currentThread().getContextClassLoader(); + try { + super.checkPermission(perm); + } catch (SecurityException se) { + // Don't annoy users with these + if (/*perm instanceof java.lang.RuntimePermission || */ + perm instanceof java.awt.AWTPermission) + throw se; + + // Collect certificates + HashSet signers = new HashSet(); + Class [] cls = getClassContext(); + for (int i = 1; i < cls.length; i++) { + Object[] objs = cls[i].getSigners(); + if (objs != null && objs.length > 0) { + for (int j = 0; j < objs.length; j++) + if (objs[j] instanceof X509Certificate) + signers.add( ((X509Certificate) objs[j]) ); + } + } + Main.debug("Certificates " + signers.size() + " for " + perm); + + // Check granted/denied permission + if ( grantAllPermissions.contains(signers) ) + return; + if ( rejectAllPermissions.contains(signers) ) + throw se; + Permissions permissions = (Permissions) grantedPermissions.get(signers); + if (permissions != null && permissions.implies(perm)) + return; + + // Ok, ask user what to do + String [] certs = new String[signers.size()]; + int certsnr = 0; + for (Iterator i = signers.iterator(); i.hasNext(); ) { + try { + certs[certsnr] = encode64( ((X509Certificate) i.next()).getEncoded() ); + certsnr++; + } catch (CertificateEncodingException cee) {} + } + if (certsnr == 0) + throw se; + String id = "" + confirmId++; + confirmRequests.put(id, Thread.currentThread()); + Main.protocol.sendSecurityConfirm(certs, certsnr, perm.toString(), id); + boolean granted = false; + try { + Thread.sleep(300000); + } catch (InterruptedException ie) { + if (((String) confirmRequests.get(id)).equals("yes")) { + granted = true; + permissions = (Permissions) grantedPermissions.get(signers); + if (permissions == null) { + permissions = new Permissions(); + grantedPermissions.put(signers, permissions); + } + permissions.add(perm); + } else if (((String) confirmRequests.get(id)).equals("grant")) { + grantAllPermissions.add( signers ); + granted = true; + } else if (((String) confirmRequests.get(id)).equals("reject")) { + rejectAllPermissions.add( signers ); + } // else "no", "nossl" or "invalid" + } finally { + confirmRequests.remove(id); + } + if (!granted) { + Main.debug("Permission denied" + perm); + throw se; + } + } + } + + // keytool -genkey -keystore mystore -alias myalias + // keytool -export -keystore mystore -alias myalias -file mycert + // keytool -printcert -file mycert + // keytool -import -keystore myotherstore -alias myalias -file mycert + // jarsigner -keystore mystore myjar.jar myalias + // jarsigner -verify -keystore myotherstore myjar.jar + // + // policy file (use policytool and check java.security): + // keystore "file:myotherstore", "JKS" + // grant signedBy "myalias" + // { + // permission java.io.FilePermission "<<ALL FILES>>", "read" + // } + // + // java code: + // KeyStore store = KeyStore.getInstance("JKS", "SUN"); + public void disabled___checkPermission(Permission perm) throws SecurityException, NullPointerException + { + // does not seem to work as expected, Problems with proxy - and it seems that the default + // implementation already does all that well, what I wanted to do here. + // It is likely that this method will hence disappear soon again. + Object context = getSecurityContext(); + Thread thread = Thread.currentThread(); + if (perm instanceof SocketPermission) { + // check if this is a connection back to the originating host + // if not, fall through and call super.checkPermission + // this gives normally access denied + Main.debug("*** checkPermission " + perm + " in context=" + context + " Thread=" + thread); + // use the context class loader to determine if this is one + // of our applets + ClassLoader contextClassLoader = thread.getContextClassLoader(); + Main.debug("* ClassLoader=" + contextClassLoader); + try { + // try to cast ... + KJASAppletClassLoader loader = (KJASAppletClassLoader)contextClassLoader; + // ok. cast succeeded. Now get the codebase of the loader + // because it contains the host name + URL codebase = loader.getCodeBase(); + URL docbase = loader.getDocBase(); + Main.debug("* Class Loader docbase=" + docbase + " codebase=" + codebase); + String hostname = perm.getName(); + // extract the hostname from the permission name + // which is something like "some.host.domain:XX" + // with XX as the port number + int colonIdx = hostname.indexOf(':'); + if (colonIdx > 0) { + // strip of the port + hostname = hostname.substring(0, colonIdx); + } + // Main.info("Checking " + hostname + "<->" + codebase.getHost()); + + if (hostsAreEqual(hostname, codebase.getHost())) { + // ok, host matches + String actions = perm.getActions(); + // just check if listen is specified which we do not want + // to allow + if (actions != null && actions.indexOf("listen") >= 0) { + Main.debug("* Listen is not allowed."); + } else { + // ok, just return and throw _no_ exception + Main.debug("* Hostname equals. Permission granted."); + return; + } + } else { + Main.info("Host mismatch: " + perm + " != " + codebase.getHost()); + } + } catch (ClassCastException e) { + Main.debug("* ClassLoader is not a KJASAppletClassLoader"); + } + Main.debug("* Fall through to super.checkPermission()"); + } + super.checkPermission(perm); + } + + private static final boolean hostsAreEqual(String host1, String host2) { + if (host1 == null || host2 == null) { + return false; + } + if (host1.length() == 0 || host2.length() == 0) { + return false; + } + if (host1.equalsIgnoreCase(host2)) { + return true; + } + + if ( Main.proxyHost != null && Main.proxyPort != 0) { + // if we use a proxy, we certainly cannot use DNS + return false; + } + + InetAddress inet1=null, inet2=null; + try { + inet1 = InetAddress.getByName(host1); + } catch (UnknownHostException e) { + Main.kjas_err("Unknown host:" + host1, e); + return false; + } + try { + inet2 = InetAddress.getByName(host2); + } catch (UnknownHostException e) { + Main.kjas_err("Unknown host:" + host2, e); + return false; + } + if (inet1.equals(inet2)) { + return true; + } + return false; + } +} diff --git a/tdehtml/java/org/kde/kjas/server/KJASSoundPlayer.java b/tdehtml/java/org/kde/kjas/server/KJASSoundPlayer.java new file mode 100644 index 000000000..a37c2bbd4 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASSoundPlayer.java @@ -0,0 +1,36 @@ +package org.kde.kjas.server; + +import java.applet.*; +import java.net.*; + +public class KJASSoundPlayer implements AudioClip +{ + private String file; + private String contextId; + + public KJASSoundPlayer( String _contextId, URL _file ) + { + file = _file.toString(); + contextId = _contextId; + Main.debug("KJASSoundPlayer( URL '" + _file + "')"); + } + + public void loop() + { + Main.debug("KJASSoundPlayer loop() URL='" + file + "'"); + Main.protocol.sendAudioClipLoopCommand(contextId, file); + } + + public void play() + { + Main.debug("KJASSoundPlayer play() URL='" + file + "'"); + Main.protocol.sendAudioClipPlayCommand(contextId, file); + } + + public void stop() + { + Main.debug("KJASSoundPlayer stop() URL='" + file + "'"); + Main.protocol.sendAudioClipStopCommand(contextId, file); + } +} + diff --git a/tdehtml/java/org/kde/kjas/server/KJASSwingConsole.java b/tdehtml/java/org/kde/kjas/server/KJASSwingConsole.java new file mode 100644 index 000000000..fedda6c48 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASSwingConsole.java @@ -0,0 +1,325 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2002 Till + * Copyright (C) 2005 Koos Vriezen <koos ! vriezen () xs4all ! nl> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.kde.kjas.server; + +import java.awt.Toolkit; +import java.awt.Image; +import java.awt.BorderLayout; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.PrintStream; +import java.util.Enumeration; +import java.util.Properties; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JButton; +import javax.swing.JTextArea; +import javax.swing.border.EmptyBorder; + + +public class KJASSwingConsole implements Console { + private JFrame frame = null; + private JPanel jPanel1; + private JScrollPane jScrollPane1; + private JButton clearButton; + private JTextArea textField; + private JButton closeButton; + private JButton copyButton; + final static int NR_BUFFERS = 3; + final static int MAX_BUF_LENGTH = 3000; + private int queue_pos = 0; + private StringBuffer [] output_buffer = new StringBuffer[NR_BUFFERS]; + + private PrintStream real_stderr = new PrintStream(System.err); + + /** Creates new form KJASSwingConsole */ + public KJASSwingConsole() { + PrintStream st = new PrintStream( new KJASConsoleStream(this) ); + System.setOut(st); + System.setErr(st); + } + + private void initComponents() { + frame = new JFrame("Konqueror Java Console"); + jPanel1 = new JPanel(); + clearButton = new JButton(); + closeButton = new JButton(); + copyButton = new JButton(); + jScrollPane1 = new JScrollPane(); + textField = new JTextArea(); + + frame.setFont(new java.awt.Font("Monospaced", 0, 10)); + frame.setName("KJAS Console"); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent evt) { + exitForm(evt); + } + }); + + jPanel1.setLayout(new BorderLayout()); + jPanel1.setBorder(new EmptyBorder(new java.awt.Insets(1, 1, 1, 1))); + clearButton.setText("clear"); + clearButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + clearButtonActionPerformed(evt); + } + }); + + jPanel1.add(clearButton, BorderLayout.WEST); + + closeButton.setText("close"); + closeButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + closeButtonActionPerformed(evt); + } + }); + + jPanel1.add(closeButton, BorderLayout.EAST); + + copyButton.setText("copy"); + copyButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent evt) { + copyButtonActionPerformed(evt); + } + }); + + jPanel1.add(copyButton, BorderLayout.CENTER); + + frame.getContentPane().add(jPanel1, BorderLayout.SOUTH); + + textField.setColumns(40); + textField.setEditable(false); + textField.setRows(10); + textField.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent evt) { + textFieldKeyPressed(evt); + } + }); + + jScrollPane1.setViewportView(textField); + + frame.getContentPane().add(jScrollPane1, BorderLayout.CENTER); + + try { + java.net.URL iconUrl = getClass().getClassLoader().getResource("images/beanicon.png"); + if (iconUrl != null) { + Toolkit tk = Toolkit.getDefaultToolkit(); + Image icon = tk.createImage(iconUrl); + frame.setIconImage(icon); + } + } catch (Throwable e) { + } + frame.pack(); + frame.setSize(500, 300); + } + + private void textFieldKeyPressed(java.awt.event.KeyEvent evt) { + // Add your handling code here: + char key = evt.getKeyChar(); + switch (key) { + case 'h': + showHelp(); + break; + case 'g': + append("Running Garbage Collection ...\n", true); + System.gc(); + case 'm': + append("Total Memory: " + Runtime.getRuntime().totalMemory() + " bytes\n", true); + append("Free Memory : " + Runtime.getRuntime().freeMemory() + " bytes\n", true); + break; + case 'c': + clear(); + break; + case 's': + showSystemProperties(); + break; + case 't': + showThreads(); + break; + case 'x': + KJASAppletClassLoader.removeLoaders(); + append("Emptied Classloader Cache\n", true); + break; + } + } + + private void showHelp() { + append("Java VM: " + System.getProperty("java.vendor") + " " + System.getProperty("java.version") + "\n", true); + String ph = System.getProperty("http.proxyHost"); + if (ph != null) { + append("Proxy: " + ph + ":" + System.getProperty("java.proxyPort") + "\n", true); + } + SecurityManager sec = System.getSecurityManager(); + if (sec == null) { + append("WARNING: Security Manager disabled!\n", true); + } else { + append("SecurityManager=" + sec + "\n", true); + } + appendSeparator(); + append("Konqueror Java Console Help\n", true); + append(" c: clear console\n", true); + append(" g: run garbage collection\n", true); + append(" h: show help\n", true); + append(" m: show memory info\n", true); + append(" s: print system properties\n", true); + append(" t: list threads\n", true); + append(" x: empty classloader cache\n", true); + appendSeparator(); + } + + private void showSystemProperties() { + append("Printing System Properties ...\n", true); + appendSeparator(); + Properties p = System.getProperties(); + for (Enumeration e = p.keys(); e.hasMoreElements();) { + Object key = e.nextElement(); + if ("line.separator".equals(key)) { + String value = (String) p.get(key); + StringBuffer unescaped = new StringBuffer(10); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '\n') unescaped.append("\\n"); + else if (c == '\r') unescaped.append("\\n"); + else unescaped.append(c); + } + append(key + " = " + unescaped + "\n", true); + } else append(key + " = " + p.get(key) + "\n", true); + } + appendSeparator(); + } + + private void showThreads() { + Thread t = Thread.currentThread(); + ThreadGroup g = t.getThreadGroup(); + ThreadGroup parent; + while ((parent = g.getParent()) != null) { + g = parent; + } + g.list(); + } + + private void copyButtonActionPerformed(java.awt.event.ActionEvent evt) { + textField.selectAll(); + textField.copy(); + } + + private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) { + frame.setVisible(false); + } + + private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) { + clear(); + } + + /** Exit the Application */ + private void exitForm(java.awt.event.WindowEvent evt) { + frame.setVisible(false); + } + + public void setVisible(boolean visible) { + if (frame == null && visible) { + initComponents(); + frame.setVisible(visible); + System.out.println( "Java VM version: " + + System.getProperty("java.version") ); + System.out.println( "Java VM vendor: " + + System.getProperty("java.vendor") ); + String ph = System.getProperty("http.proxyHost"); + String pp = System.getProperty("http.proxyPort"); + if (ph != null) { + System.out.println("Proxy: " + ph + ":" + pp); + } + SecurityManager sec = System.getSecurityManager(); + Main.debug("SecurityManager=" + sec); + if (sec == null) { + System.out.println( "WARNING: Security Manager disabled!" ); + textField.setForeground(java.awt.Color.red); + } + showHelp(); + } else if (frame != null) + frame.setVisible(visible); + + if (visible) { + for (int i = 0; i < NR_BUFFERS; i++) + if (output_buffer[(queue_pos + i + 1) % 3] != null) { + textField.append(output_buffer[(queue_pos + i + 1) % 3].toString()); + output_buffer[(queue_pos + i + 1) % 3] = null; + } + } + } + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + new KJASSwingConsole().setVisible(true); + } + + public void clear() { + textField.setText(""); + } + + private void appendSeparator() { + append("----------------------------------------------------\n", true); + } + + public void append(String txt) { + append(txt, false); + } + + public void append(String txt, boolean force) { + if (txt == null) + return; + if (frame == null || !frame.isVisible()) { + if (Main.Debug) + real_stderr.print(txt); + if (output_buffer[queue_pos] != null && + output_buffer[queue_pos].length() > MAX_BUF_LENGTH) { + queue_pos = (++queue_pos) % NR_BUFFERS; + if (output_buffer[queue_pos] != null) { + // starting overwriting old log, clear textField if exists + if (frame != null) + textField.setText(""); + output_buffer[queue_pos] = null; + } + } + if (output_buffer[queue_pos] == null) + output_buffer[queue_pos] = new StringBuffer(txt); + else + output_buffer[queue_pos].append(txt); + return; + } + int length = txt.length(); + synchronized(textField) { + //get the caret position, and then get the new position + int old_pos = textField.getCaretPosition(); + textField.append(txt); + textField.setCaretPosition( old_pos + length ); + } + } +} + diff --git a/tdehtml/java/org/kde/kjas/server/KJASURLStreamHandlerFactory.java b/tdehtml/java/org/kde/kjas/server/KJASURLStreamHandlerFactory.java new file mode 100644 index 000000000..58c5ff518 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/KJASURLStreamHandlerFactory.java @@ -0,0 +1,609 @@ +/* This file is part of the KDE project + * + * Copyright (C) 2003 Koos Vriezen <koos ! vriezen () xs4all ! nl> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package org.kde.kjas.server; + +import java.net.*; +import java.io.*; +import java.util.*; +import java.security.*; +/** + * + */ + +class KIOConnection +{ + final static int NOT_CONNECTED = 0; + final static int CONNECT_WAIT = 1; + final static int CONNECTED = 2; + + final static int DATA = 0; + final static int FINISHED = 1; + final static int ERRORCODE = 2; + final static int CONNECT = 6; + final static int REQUESTDATA = 7; + + final static int STOP = 0; + final static int HOLD = 1; + final static int RESUME = 2; + + protected static int id = 0; + static Hashtable jobs = new Hashtable(); // should be thread safe + + static void setData(String jobid, int code, byte [] data) { + KIOConnection job = (KIOConnection) jobs.get(jobid); + if (job == null || !job.setData(code, data)) + Main.info("KIO KJASHttpURLConnection gone (timedout/closed)"); + else + Thread.yield(); + } + + private class KJASOutputStream extends OutputStream { + KJASOutputStream() { + } + public void write(int b) throws IOException { + byte[] buf = {(byte)b}; + write(buf); + } + public synchronized void write(byte b[], int off, int len) throws IOException { + byte[] buf = new byte[len]; + System.arraycopy(b, off, buf, 0, len); + sendData(buf, false); + } + public void write(byte b[]) throws IOException { + write(b, 0, b.length); + } + public void close() throws IOException { + disconnect(); + } + public void flush() throws IOException { + checkConnected(); + sendData(null, true); + } + } + + private class KJASInputStream extends InputStream { + + KJASInputStream() { + } + public int read() throws IOException { + if (getData(true)) + return 0x00ff & in_buf[in_bufpos++]; + return -1; + } + public int read(byte[] b, int off, int len) throws IOException { + int total = 0; + do { + if (!getData(true)) break; + int nr = in_buf.length - in_bufpos; + if (nr > len) + nr = len; + System.arraycopy(in_buf, in_bufpos, b, off, nr); + len -= nr; + total += nr; + off += nr; + in_bufpos += nr; + } while (len > 0); + return total > 0 ? total : -1; + } + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + public int available() throws IOException { + return inAvailable(); + } + public boolean markSupported() { + return false; + } + public void close() throws IOException { + disconnect(); + } + } + + protected URL url; + protected int connect_status = 0; + protected String jobid = null; // connection id with KIO + protected LinkedList data = new LinkedList(); // not thread safe + protected int errorcode = 0; + protected boolean finished = false; // all data has arived + protected boolean onhold = false; // KIO job is suspended + protected boolean request_data = false; // need data for put job + private KJASOutputStream out = null; + private KJASInputStream in = null; + private byte [] in_buf = null; // current input buffer + private int in_bufpos = 0; // position in buffer + private boolean in_eof = false; // all data is read + private final static int LOW_BUFFER_LIMIT = 5; // put onhold off + private final static int HIGH_BUFFER_LIMIT = 10; // put onhold on + + protected KIOConnection(URL u) { + url = u; + } + protected void checkConnected() throws IOException { + if (connect_status != CONNECTED) + throw new IOException("not connected"); + } + protected boolean haveError() { + return errorcode != 0; + } + synchronized protected boolean setData(int code, byte [] d) { + // is job still there when entering the monitor + if (jobs.get(jobid) == null) + return false; + if (connect_status == CONNECT_WAIT) + connect_status = CONNECTED; + switch (code) { + case FINISHED: + if (d != null && d.length > 0) + data.addLast(d); + finished = true; + onhold = false; + jobs.remove(jobid); + Main.debug ("KIO FINISHED (" + jobid + ") " + data.size()); + break; + case DATA: + if (d.length > 0) + data.addLast(d); + // Main.debug ("KIO DATA (" + jobid + ") " + data.size()); + if (!onhold && data.size() > HIGH_BUFFER_LIMIT) { + Main.protocol.sendDataCmd(jobid, HOLD); + onhold = true; + } + break; + case ERRORCODE: + String codestr = new String(d); + errorcode = Integer.parseInt(codestr); + Main.debug ("KIO ERRORECODE(" + jobid + ") " + errorcode); + break; + case CONNECT: + Main.debug ("KIO CONNECT(" + jobid + ") "); + request_data = true; + errorcode = 0; + break; + case REQUESTDATA: + Main.debug ("KIO REQUESTDATA(" + jobid + ") "); + request_data = true; + break; + } + notifyAll(); + return true; + } + + private synchronized boolean getData(boolean mayblock) throws IOException { + if (haveError()) { + //disconnect(); + in_eof = true; + //throw new IOException("i/o error " + errorcode); + } + if (in_eof) + return false; + checkConnected(); + if (in_buf != null && in_bufpos < in_buf.length) + return true; + int datasize = data.size(); + if (datasize > 0) { + in_buf = (byte []) data.removeFirst(); + in_bufpos = 0; + } + if (onhold && datasize < LOW_BUFFER_LIMIT) { + Main.protocol.sendDataCmd(jobid, RESUME); + onhold = false; + } + if (datasize > 0) + return true; + if (finished) { + in_eof = true; + return false; + } + if (!mayblock) + return false; + try { + wait(); + } catch (InterruptedException ie) { + return false; + } + return getData(false); + } + synchronized private int inAvailable() throws IOException { + if (in_eof) + return 0; + checkConnected(); + if (!getData(false)) + return 0; + int total = in_buf.length - in_bufpos; + ListIterator it = data.listIterator(0); + while (it.hasNext()) + total += ((byte []) it.next()).length; + return total; + } + synchronized private void sendData(byte [] d, boolean force) throws IOException { + Main.debug ("KIO sendData(" + jobid + ") force:" + force + " request_data:" + request_data); + if (d != null) + data.addLast(d); + if (!request_data && !force) return; + if (data.size() == 0) return; + if (force && !request_data) { + try { + wait(10000); + } catch (InterruptedException ie) { + return; + } + if (!request_data) { + Main.debug ("KIO sendData(" + jobid + ") timeout"); + data.clear(); + disconnect(); + throw new IOException("timeout"); + } + } + byte[] buf; + int total = 0; + ListIterator it = data.listIterator(0); + while (it.hasNext()) + total += ((byte []) it.next()).length; + buf = new byte[total]; + int off = 0; + it = data.listIterator(0); + while (it.hasNext()) { + byte [] b = (byte []) it.next(); + System.arraycopy(b, 0, buf, off, b.length); + off += b.length; + } + data.clear(); + request_data = false; + Main.protocol.sendPutData(jobid, buf, 0, total); + } + synchronized void connect(boolean doInput) throws IOException { + if (connect_status == CONNECTED) + return; // javadocs: call is ignored + //(new Exception()).printStackTrace(); + Main.debug ("KIO connect " + url); + errorcode = 0; + finished = in_eof = false; + jobid = String.valueOf(id++); + jobs.put(jobid, this); + if (doInput) + Main.protocol.sendGetURLDataCmd(jobid, url.toExternalForm()); + else + Main.protocol.sendPutURLDataCmd(jobid, url.toExternalForm()); + connect_status = CONNECT_WAIT; + try { + wait(20000); + } catch (InterruptedException ie) { + errorcode = -1; + } + boolean isconnected = (connect_status == CONNECTED); + if (isconnected && !haveError()) { + if (doInput) + in = new KJASInputStream(); + else + out = new KJASOutputStream(); + Main.debug ("KIO connect(" + jobid + ") " + url); + return; + } + connect_status = NOT_CONNECTED; + jobs.remove(jobid); + if (isconnected) { + if (!finished) + Main.protocol.sendDataCmd(jobid, STOP); + Main.debug ("KIO connect error " + url); + throw new ConnectException("connection failed (not found)"); + } + Main.debug ("KIO connect timeout " + url); + throw new IOException("connection failed (timeout)"); + } + synchronized void disconnect() { + if (connect_status == NOT_CONNECTED) + return; + Main.debug ("KIO disconnect " + jobid); + //(new Exception()).printStackTrace(); + if (out != null) { + try { + out.flush(); + } catch (IOException iox) {} + } + connect_status = NOT_CONNECTED; + out = null; + in = null; + if (!finished) { + Main.protocol.sendDataCmd(jobid, STOP); + jobs.remove(jobid); + } + notifyAll(); + } + InputStream getInputStream() throws IOException { + Main.debug ("KIO getInputStream(" + jobid + ") " + url); + return in; + } + OutputStream getOutputStream() throws IOException { + Main.debug ("KIO getOutputStream(" + jobid + ") " + url); + return out; + } +} + +final class KIOHttpConnection extends KIOConnection +{ + final static int HEADERS = 3; + final static int REDIRECT = 4; + final static int MIMETYPE = 5; + + Vector headers = new Vector(); + Hashtable headersmap = new Hashtable(); + String responseMessage = null; + int responseCode = -1; + + KIOHttpConnection(URL u) { + super(u); + } + protected boolean haveError() { + return super.haveError() || + responseCode != 404 && (responseCode < 0 || responseCode >= 400); + } + protected synchronized boolean setData(int code, byte [] d) { + switch (code) { + case HEADERS: + StringTokenizer tokenizer = new StringTokenizer(new String(d), "\n"); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + int pos = token.indexOf(":"); + String [] entry = { + token.substring(0, pos > -1 ? pos : token.length()).toLowerCase(), token.substring(pos > -1 ? pos+1: token.length()).trim() + }; + headers.add(entry); + headersmap.put(entry[0], entry[1]); + // Main.debug ("KIO header " + entry[0] + "=" + entry[1]); + } + responseCode = 0; + if (headersmap.size() > 0) { + String token = ((String []) headers.get(0))[0]; + if (!token.startsWith("http/1.")) break; + int spos = token.indexOf(' '); + if (spos < 0) break; + int epos = token.indexOf(' ', spos + 1); + if (epos < 0) break; + responseCode = Integer.parseInt(token.substring(spos+1, epos)); + responseMessage = token.substring(epos+1); + Main.debug ("KIO responsecode=" + responseCode); + } + break; + } + return super.setData(code, d); + } +} + +final class KIOSimpleConnection extends KIOConnection +{ + KIOSimpleConnection(URL u) { + super(u); + } +} + +final class KJASHttpURLConnection extends HttpURLConnection +{ + private KIOHttpConnection kioconnection; + + KJASHttpURLConnection(URL u) { + super(u); + kioconnection = new KIOHttpConnection(u); + } + public Map getHeaderFields() { + try { + connect(); + } catch (IOException e) { + Main.debug ("Error on implicit connect()"); + } + Main.debug ("KIO getHeaderFields"); + return kioconnection.headersmap; + } + public String getHeaderField(String name) { + try { + connect(); + } catch (IOException e) { + Main.debug ("Error on implicit connect()"); + } + String field = (String) kioconnection.headersmap.get(name); + Main.debug ("KIO getHeaderField:" + name + "=" + field); + //(new Exception()).printStackTrace(); + return field; + } + public String getHeaderField(int n) { + try { + connect(); + } catch (IOException e) { + Main.debug ("Error on implicit connect()"); + } + Main.debug ("KIO getHeaderField(" + n + ") size=" + kioconnection.headersmap.size()); + if (n >= kioconnection.headersmap.size()) + return null; + String [] entry = (String []) kioconnection.headers.get(n); + String line = entry[0]; + if (entry[1].length() > 0) + line += ":" + entry[1]; + Main.debug ("KIO getHeaderField(" + n + ")=#" + line + "#"); + return line; + } + public String getHeaderFieldKey(int n) { + try { + connect(); + } catch (IOException e) { + Main.debug ("Error on implicit connect()"); + } + Main.debug ("KIO getHeaderFieldKey " + n); + if (n >= kioconnection.headersmap.size()) + return null; + return ((String []) kioconnection.headers.get(n))[0]; + } + public int getResponseCode() throws IOException { + Main.debug ("KIO getResponseCode"); + if (kioconnection.responseCode == -1) { + try { + connect(); + } catch (IOException e) { + if (kioconnection.responseCode == -1) + throw e; + } + } + responseMessage = kioconnection.responseMessage; + return kioconnection.responseCode; + } + public boolean usingProxy() { + return false; // FIXME + } + public void connect() throws IOException { + if (connected) + return; + Main.debug ("KIO KJASHttpURLConnection.connect " + url); + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPermission(getPermission()); + kioconnection.connect(doInput); + connected = true; + if (kioconnection.responseCode == 404) + throw new FileNotFoundException(url.toExternalForm()); + } + public void disconnect() { + kioconnection.disconnect(); + connected = false; + } + public InputStream getInputStream() throws IOException { + doInput = true; + doOutput = false; + connect(); + return kioconnection.getInputStream(); + } + public OutputStream getOutputStream() throws IOException { + doInput = false; + doOutput = true; + connect(); + return kioconnection.getOutputStream(); + } + public InputStream getErrorStream() { + Main.debug("KIO KJASHttpURLConnection.getErrorStream" + url); + try { + if (connected && kioconnection.responseCode == 404) + return kioconnection.getInputStream(); + } catch (Exception ex) {} + return null; + } +} + +final class KJASSimpleURLConnection extends URLConnection +{ + private KIOSimpleConnection kioconnection = null; + private int default_port; + + KJASSimpleURLConnection(URL u, int p) { + super(u); + default_port = p; + } + public boolean usingProxy() { + return false; // FIXME + } + public Permission getPermission() throws IOException { + int p = url.getPort(); + if (p < 0) + p = default_port; + return new SocketPermission(url.getHost() + ":" + p, "connect"); + } + public void connect() throws IOException { + if (kioconnection != null) + return; + Main.debug ("KIO KJASSimpleURLConnection.connection " + url); + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPermission(getPermission()); + kioconnection = new KIOSimpleConnection(url); + kioconnection.connect(doInput); + connected = true; + } + public void disconnect() { + if (kioconnection == null) + return; + kioconnection.disconnect(); + kioconnection = null; + connected = false; + } + public InputStream getInputStream() throws IOException { + doInput = true; + doOutput = false; + if (kioconnection == null) + connect(); + return kioconnection.getInputStream(); + } + public OutputStream getOutputStream() throws IOException { + doInput = false; + doOutput = true; + if (kioconnection == null) + connect(); + return kioconnection.getOutputStream(); + } +} + + +final class KJASHttpURLStreamHandler extends URLStreamHandler +{ + KJASHttpURLStreamHandler(int port) { + default_port = port; + } + protected URLConnection openConnection(URL u) throws IOException { + URL url = new URL(u.toExternalForm()); + return new KJASHttpURLConnection(url); + } + protected int getDefaultPort() { + return default_port; + } + private int default_port; +} + +final class KJASSimpleURLStreamHandler extends URLStreamHandler +{ + KJASSimpleURLStreamHandler(int port) { + default_port = port; + } + protected URLConnection openConnection(URL u) throws IOException { + URL url = new URL(u.toExternalForm()); + return new KJASSimpleURLConnection(url, default_port); + } + protected int getDefaultPort() { + return default_port; + } + private int default_port; +} + +public final class KJASURLStreamHandlerFactory + implements URLStreamHandlerFactory +{ + public URLStreamHandler createURLStreamHandler(String protocol) { + if (protocol.equals("jar") || protocol.equals("file")) + return null; + //outputs to early: Main.debug ("createURLStreamHandler " + protocol); + Main.debug ("KIO createURLStreamHandler " + protocol); + if (protocol.equals("http")) + return new KJASHttpURLStreamHandler(80); + else if (protocol.equals("https")) + return new KJASHttpURLStreamHandler(443); + else if (protocol.equals("ftp")) + return new KJASSimpleURLStreamHandler(21); + else if (protocol.equals("smb")) + return new KJASSimpleURLStreamHandler(139); + else if (protocol.equals("fish")) + return new KJASSimpleURLStreamHandler(22); + return null; + } +} diff --git a/tdehtml/java/org/kde/kjas/server/Main.java b/tdehtml/java/org/kde/kjas/server/Main.java new file mode 100644 index 000000000..50ccb14f1 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/Main.java @@ -0,0 +1,178 @@ +package org.kde.kjas.server; + +import java.io.*; +import java.security.*; +import java.net.*; + +/** + * KJAS server recognizes these variablers: + * kjas.debug - makes server actions verbose + * kjas.showConsole - shows Java Console window + * kjas.log - save a transcript of the debug output to /tmp/kjas.log + */ + +public class Main +{ + //We need to save a reference to the original stdout + //for sending messages back + static final KJASProtocolHandler protocol; + static Console console = null; + private static final boolean show_console; + public static final boolean Debug; + public static final boolean log; + static final boolean cacheImages; + static float java_version = (float) 0.0; + static String proxyHost = null; + static int proxyPort = 0; + private static boolean good_jdk = true; + + /************************************************************************** + * Initialization + **************************************************************************/ + static + { + Debug = System.getProperty( "kjas.debug" ) != null; + + show_console = System.getProperty( "kjas.showConsole" ) != null; + + if( System.getProperty( "kjas.useKio" ) != null ) + URL.setURLStreamHandlerFactory( new KJASURLStreamHandlerFactory() ); + + log = System.getProperty( "kjas.log" ) != null; + + cacheImages = System.getProperty( "kjas.noImageCache" ) != null; + + // determine system proxy + proxyHost = System.getProperty( "http.proxyHost" ); + String proxyPortString = System.getProperty( "http.proxyPort" ); + try { + proxyPort = Integer.parseInt(proxyPortString); + } catch (Exception e) { + } + //Main.debug( "JVM version = " + System.getProperty( "java.version" ) ); + String version = System.getProperty("java.version").substring( 0, 3 ); + // Hack for SGI Java2 runtime + if (version == "Jav") { // Skip over JavaVM- (the first 7 chars) + version = System.getProperty("java.version").substring(7,3); + } + //Main.debug( "JVM numerical version = " + version ); + try { + java_version = Float.parseFloat( version ); + if( java_version < 1.2 ) + good_jdk = false; + } catch( NumberFormatException e ) { + good_jdk = false; + } + PrintStream protocol_stdout = System.out; + console = new KJASSwingConsole(); + protocol = new KJASProtocolHandler( System.in, protocol_stdout ); + } + + /************************************************************************** + * Public Utility functions available to the KJAS framework + **************************************************************************/ + public static void debug( String msg ) + { + if( Debug ) + { + System.out.println( "KJAS: " + msg ); + } + } + public static void info (String msg ) { + System.err.println( "KJAS: " + msg ); + } + + public static void kjas_err( String msg, Exception e ) + { + System.err.println( msg ); + System.err.println( "Backtrace: " ); + e.printStackTrace(); + } + + public static void kjas_err( String msg, Throwable t ) + { + System.err.println( msg ); + t.printStackTrace(); + } + private Main() { + } + + /************************************************************************** + * Main- create the command loop + **************************************************************************/ + public static void main( String[] args ) + { + if( !good_jdk ) + { + console.setVisible( true ); + System.err.println( "ERROR: This version of Java is not supported for security reasons." ); + System.err.println( "\t\tPlease use Java version 1.2 or higher." ); + return; + } + + if( show_console ) + console.setVisible( true ); + + // set up https + boolean hasHTTPS = true; + + try { + // https needs a secure socket provider + Provider[] sslProviders = Security.getProviders("SSLContext.SSL"); + + if (sslProviders == null || sslProviders.length == 0) { + // as a fallback, try to dynamically install Sun's jsse + Class provider = Class.forName("com.sun.net.ssl.internal.ssl.Provider"); + + if (provider != null) { + Main.debug("adding Security Provider"); + Provider p = (Provider) provider.newInstance(); + Security.addProvider(p); + } else { + // Try jessie (http://www.nongnu.org/jessie/) as a fallback + // available in the Free World + provider = Class.forName("org.metastatic.jessie.provider.Jessie"); + if (provider != null) { + Main.debug("adding Jessie as Security Provider"); + Provider p = (Provider) provider.newInstance(); + Security.addProvider(p); + } else { + Main.debug("could not get class: com.sun.net.ssl.internal.ssl.Provider"); + hasHTTPS = false; + } + } + } + + if (hasHTTPS) { + // allow user to provide own protocol handler + // -Djava.protocol.handler.pkgs = user.package.name + // getting and setting of properties might generate SecurityExceptions + // so this needs to be in a try block + String handlerPkgs = System.getProperty("java.protocol.handler.pkgs"); + + if (handlerPkgs == null) { + // set default packages for Sun and IBM + handlerPkgs = "com.sun.net.ssl.internal.www.protocol" + + "|com.ibm.net.ssl.www.protocol"; + } else { + // add default packages for Sun and IBM as fallback + handlerPkgs += "|com.sun.net.ssl.internal.www.protocol" + + "|com.ibm.net.ssl.www.protocol"; + } + + System.setProperty("java.protocol.handler.pkgs", handlerPkgs); + } + } catch (Exception e) { + hasHTTPS = false; + } + + if (hasHTTPS == false) { + System.out.println("Unable to load JSSE SSL stream handler, https support not available"); + System.out.println("For more information see http://java.sun.com/products/jsse/"); + } + + //start the command parsing + protocol.commandLoop(); + } + +} diff --git a/tdehtml/java/org/kde/kjas/server/StatusListener.java b/tdehtml/java/org/kde/kjas/server/StatusListener.java new file mode 100644 index 000000000..be17c2b29 --- /dev/null +++ b/tdehtml/java/org/kde/kjas/server/StatusListener.java @@ -0,0 +1,5 @@ +package org.kde.kjas.server; + +public interface StatusListener { + public void showStatus(String message); +}
\ No newline at end of file |