This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Patch: RFC: java.net updates


Tom> Still, for now I would like to move forward.  I still do need
Tom> someone to try a Windows build of the patch to make sure I didn't
Tom> break anything.  Can anybody on this list do that?

I'm checking in the appended without a Windows build.
We can always fix problems later, if they arise.
I suspect at least the strerror code will need to be changed (based on
Tony Kimball's patches).

This patch adds some missing methods to java.net.  It also fixes up
some problems in URLClassLoader (our version had the wrong superclass
and didn't implement some functionality I needed).

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* java/net/JarURLConnection.java (getCertificates): New method
	from Classpath.
	* java/net/URLClassLoader.java (URLClassLoader): Extends
	SecureClassLoader.
	(definePackage): New method from Classpath.
	(getPermissions): Likewise.
	(newInstance): Likewise.
	(findClass): Construct CodeSource for new class (from Classpath).
	* java/net/SocketImpl.java (shutdownInput, shutdownOutput): New
	methods.
	* java/net/URL.java (getUserInfo): New method.
	(set(String,String,int,String,String,String,String,String)): New
	method.
	* java/net/PlainSocketImpl.java (_Jv_SO_KEEPALIVE_): Define.
	(shutdownInput, shutdownOutput): Declare.
	* java/net/PlainDatagramSocketImpl.java (_Jv_SO_KEEPALIVE_):
	Define.
	* java/net/natPlainSocketImpl.cc (setOption): Handle keepalive.
	(getOption): Likewise.
	(shutdownInput): New method.
	(shutdownOutput): Likewise.
	* java/net/natPlainDatagramSocketImpl.cc (setOption): Handle
	keepalive.
	(getOption): Likewise.
	* java/net/SocketOptions.java (SO_KEEPALIVE): New constant.
	* java/net/Socket.java (setKeepAlive): New method.
	(getKeepAlive): Likewise.
	(shutdownInput, shutdownOutput): New methods.

Index: java/net/JarURLConnection.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/JarURLConnection.java,v
retrieving revision 1.6
diff -u -r1.6 JarURLConnection.java
--- java/net/JarURLConnection.java 27 Aug 2002 17:47:26 -0000 1.6
+++ java/net/JarURLConnection.java 30 Aug 2002 18:12:26 -0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2002  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -15,6 +15,7 @@
 import java.util.Map;
 import java.util.Vector;
 import java.util.Hashtable;
+import java.security.cert.Certificate;
 
 /**
  * @author Kresten Krab Thorup <krab@gnu.org>
@@ -316,4 +317,16 @@
     hdrHash.put(key.toLowerCase(), Long.toString(len));
   }
 
+  /**
+   * Returns an array of Certificate objects for the jar file entry specified
+   * by this URL or null if there are none
+   *
+   * @return A Certificate array
+   *
+   * @exception IOException If an error occurs
+   */
+  public Certificate[] getCertificates() throws IOException
+  {
+    return getJarEntry().getCertificates();
+  }
 }
Index: java/net/PlainDatagramSocketImpl.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/PlainDatagramSocketImpl.java,v
retrieving revision 1.10
diff -u -r1.10 PlainDatagramSocketImpl.java
--- java/net/PlainDatagramSocketImpl.java 28 Mar 2002 02:08:36 -0000 1.10
+++ java/net/PlainDatagramSocketImpl.java 30 Aug 2002 18:12:26 -0000
@@ -1,6 +1,6 @@
 // PlainDatagramSocketImpl.java - Implementation of DatagramSocketImpl.
 
-/* Copyright (C) 1999  Free Software Foundation
+/* Copyright (C) 1999, 2002  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -33,7 +33,8 @@
                    _Jv_SO_LINGER_ = SocketOptions.SO_LINGER,
                    _Jv_SO_TIMEOUT_ = SocketOptions.SO_TIMEOUT,
                    _Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,
-                   _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF;
+                   _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF,
+                   _Jv_SO_KEEPALIVE_ = SocketOptions.SO_KEEPALIVE;
 
   int fnum = -1;
 
Index: java/net/PlainSocketImpl.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/PlainSocketImpl.java,v
retrieving revision 1.10
diff -u -r1.10 PlainSocketImpl.java
--- java/net/PlainSocketImpl.java 28 Mar 2002 02:08:36 -0000 1.10
+++ java/net/PlainSocketImpl.java 30 Aug 2002 18:12:26 -0000
@@ -32,7 +32,8 @@
                    _Jv_SO_LINGER_ = SocketOptions.SO_LINGER,
                    _Jv_SO_TIMEOUT_ = SocketOptions.SO_TIMEOUT,
                    _Jv_SO_SNDBUF_ = SocketOptions.SO_SNDBUF,
-                   _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF;
+                   _Jv_SO_RCVBUF_ = SocketOptions.SO_RCVBUF,
+                   _Jv_SO_KEEPALIVE_ = SocketOptions.SO_KEEPALIVE;
 
   /**
    * The OS file handle representing the socket.
@@ -52,6 +53,10 @@
   public native void setOption(int optID, Object value) throws SocketException;
 
   public native Object getOption(int optID) throws SocketException;
+
+  public native void shutdownInput () throws IOException;
+
+  public native void shutdownOutput () throws IOException;
 
   protected native void create (boolean stream)  throws IOException;
 
Index: java/net/Socket.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/Socket.java,v
retrieving revision 1.10
diff -u -r1.10 Socket.java
--- java/net/Socket.java 27 Aug 2002 17:47:27 -0000 1.10
+++ java/net/Socket.java 30 Aug 2002 18:12:26 -0000
@@ -618,6 +618,47 @@
   }
 
   /**
+   * This method sets the value for the socket level socket option
+   * SO_KEEPALIVE.
+   *
+   * @param on True if SO_KEEPALIVE should be enabled
+   *
+   * @exception SocketException If an error occurs or Socket is not connected
+   *
+   * @since Java 1.3
+   */
+  public void setKeepAlive (boolean on) throws SocketException
+  {
+    if (impl == null)
+      throw new SocketException("Not connected");
+
+    impl.setOption(SocketOptions.SO_RCVBUF, new Boolean(on));
+  }
+
+  /**
+   * This method returns the value of the socket level socket option
+   * SO_KEEPALIVE.
+   *
+   * @return The setting
+   *
+   * @exception SocketException If an error occurs or Socket is not connected
+   *
+   * @since Java 1.3
+   */
+  public boolean getKeepAlive () throws SocketException
+  {
+    if (impl == null)
+      throw new SocketException("Not connected");
+
+    Object buf = impl.getOption(SocketOptions.SO_RCVBUF);
+
+    if (buf instanceof Boolean)
+      return(((Boolean)buf).booleanValue());
+    else
+      throw new SocketException("Internal Error: Unexpected type");
+  }
+
+  /**
    * Closes the socket.
    *
    * @exception IOException If an error occurs
@@ -666,5 +707,27 @@
       sm.checkSetFactory();
 
     factory = fac;
+  }
+
+  /**
+   * Closes the input side of the socket stream.
+   *
+   * @exception IOException If an error occurs.
+   */
+  public void shutdownInput() throws IOException 
+  {
+    if (impl != null)
+      impl.shutdownInput();
+  }
+
+  /**
+   * Closes the output side of the socket stream.
+   *
+   * @exception IOException If an error occurs.
+   */
+  public void shutdownOutput() throws IOException
+  {
+    if (impl != null)
+      impl.shutdownOutput();
   }
 }
Index: java/net/SocketImpl.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/SocketImpl.java,v
retrieving revision 1.8
diff -u -r1.8 SocketImpl.java
--- java/net/SocketImpl.java 14 Feb 2002 23:16:06 -0000 1.8
+++ java/net/SocketImpl.java 30 Aug 2002 18:12:27 -0000
@@ -264,4 +264,20 @@
    * @XXX This redeclaration from SocketOptions is a workaround to a gcj bug.
    */
   public abstract Object getOption(int option_id) throws SocketException;
+
+  /**
+   * Shut down the input side of this socket.  Subsequent reads will
+   * return end-of-file.
+   *
+   * @exception IOException if an error occurs
+   */
+  public abstract void shutdownInput () throws IOException;
+
+  /**
+   * Shut down the output side of this socket.  Subsequent writes will
+   * fail with an IOException.
+   *
+   * @exception IOException if an error occurs
+   */
+  public abstract void shutdownOutput () throws IOException;
 }
Index: java/net/SocketOptions.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/SocketOptions.java,v
retrieving revision 1.6
diff -u -r1.6 SocketOptions.java
--- java/net/SocketOptions.java 22 Jan 2002 22:40:23 -0000 1.6
+++ java/net/SocketOptions.java 30 Aug 2002 18:12:27 -0000
@@ -1,5 +1,5 @@
 /* SocketOptions.java -- Implements options for sockets (duh!)
-   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -60,6 +60,11 @@
 /*
  * Static Variables
  */
+
+/**
+ * Option id for the SO_KEEPALIVE value
+ */
+static final int SO_KEEPALIVE = 0x8;
 
 /**
   * Option id for the SO_LINGER value
Index: java/net/URL.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/URL.java,v
retrieving revision 1.10
diff -u -r1.10 URL.java
--- java/net/URL.java 23 Feb 2002 00:15:48 -0000 1.10
+++ java/net/URL.java 30 Aug 2002 18:12:27 -0000
@@ -175,7 +175,8 @@
       this.handler = setURLStreamHandler(protocol);
 
     if (this.handler == null)
-      throw new MalformedURLException("Protocol handler not found: " + protocol);
+      throw new MalformedURLException("Protocol handler not found: "
+				      + protocol);
 
     // JDK 1.2 doc for parseURL specifically states that any '#' ref
     // is to be excluded by passing the 'limit' as the indexOf the '#'
@@ -245,6 +246,12 @@
     return ref;
   }
 
+  public String getUserInfo ()
+  {
+    int at = host.indexOf('@');
+    return at < 0 ? null : host.substring(0, at);
+  }
+
   public int hashCode()
   {
     // JCL book says this is computed using (only) the hashcodes of the 
@@ -295,6 +302,30 @@
     this.port = port;
     this.host = host;
     this.file = file;
+    this.ref = ref;
+    hashCode = hashCode();			// Used for serialization.
+  }
+
+  /** @since 1.3 */
+  protected void set(String protocol, String host, int port,
+		     String authority, String userInfo,
+		     String path, String query, String ref)
+  {
+    // TBD: Theoretically, a poorly written StreamHandler could pass an
+    // invalid protocol.  It will cause the handler to be set to null
+    // thus overriding a valid handler.  Callers of this method should
+    // be aware of this.
+    this.handler = setURLStreamHandler(protocol);
+    this.protocol = protocol;
+    if (userInfo == null)
+      this.host = host;
+    else
+      this.host = userInfo + "@" + host;
+    this.port = port;
+    if (query == null)
+      this.file = path;
+    else
+      this.file = path + "?" + query;
     this.ref = ref;
     hashCode = hashCode();			// Used for serialization.
   }
Index: java/net/URLClassLoader.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/URLClassLoader.java,v
retrieving revision 1.6
diff -u -r1.6 URLClassLoader.java
--- java/net/URLClassLoader.java 27 Aug 2002 17:47:27 -0000 1.6
+++ java/net/URLClassLoader.java 30 Aug 2002 18:12:27 -0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2002  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -12,11 +12,15 @@
 import java.util.jar.*;
 import java.util.Enumeration;
 import java.util.Vector;
+import java.security.CodeSource;
+import java.security.SecureClassLoader;
+import java.security.PermissionCollection;
+import java.security.cert.Certificate;
 
 /**
  * @since 1.2
  */
-public class URLClassLoader extends ClassLoader 
+public class URLClassLoader extends SecureClassLoader
 {
   // The URLStreamHandlerFactory
   URLStreamHandlerFactory factory = null;
@@ -228,12 +232,12 @@
 
     try 
       {
-	URL u = getResource (name.replace ('.', '/') + ".class");
+	URL url = getResource (name.replace ('.', '/') + ".class");
 
-	if (u == null)
+	if (url == null)
 	  throw new ClassNotFoundException (name);
 
-	URLConnection connection = u.openConnection ();
+	URLConnection connection = url.openConnection ();
 	InputStream is = connection.getInputStream ();
 
 	int len = connection.getContentLength ();
@@ -250,12 +254,171 @@
 	    off += c;
 	  }
 
-	return defineClass (name, data, 0, len);
+	// Now construct the CodeSource (if loaded from a jar file)
+	CodeSource source = null;
+	if (url.getProtocol().equals("jar"))
+	  {
+	    Certificate[] certificates =
+	      ((JarURLConnection) connection).getCertificates();
+	    String u = url.toExternalForm ();
+	    u = u.substring (4); //skip "jar:"
+	    int i = u.indexOf ('!');
+	    if (i >= 0)
+	      u = u.substring (0, i);
+	    url = new URL("jar", "", u);
+
+	    source = new CodeSource(url, certificates);
+	  }
+	else if (url.getProtocol().equals("file"))
+	  {
+	    try
+	      {
+		String u = url.toExternalForm();
+		// Skip "file:" and then get canonical directory name.
+		File f = new File(u.substring(5));
+		f = f.getCanonicalFile();
+		url = new URL("file", "", f.getParent());
+		source = new CodeSource (url, null);
+	      }
+	    catch (IOException ignore)
+	      {
+	      }
+	  }
+
+	return defineClass (name, data, 0, len, source);
       } 
     catch (java.io.IOException x)
       {
 	throw new ClassNotFoundException(name);
       }
   }
-}
 
+  /** 
+   * Defines a Package based on the given name and the supplied manifest
+   * information. The manifest indicates the tile, version and
+   * vendor information of the specification and implementation and wheter the
+   * package is sealed. If the Manifest indicates that the package is sealed
+   * then the Package will be sealed with respect to the supplied URL.
+   *
+   * @exception IllegalArgumentException If this package name already exists
+   * in this class loader
+   * @param name The name of the package
+   * @param manifest The manifest describing the specification,
+   * implementation and sealing details of the package
+   * @param url the code source url to seal the package
+   * @return the defined Package
+   */
+  protected Package definePackage(String name, Manifest manifest, URL url) 
+    throws IllegalArgumentException
+  {
+    Attributes attr = manifest.getMainAttributes();
+    String specTitle =
+      attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 
+    String specVersion =
+      attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 
+    String specVendor =
+      attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 
+    String implTitle =
+      attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 
+    String implVersion =
+      attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 
+    String implVendor =
+      attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
+
+    // Look if the Manifest indicates that this package is sealed
+    // XXX - most likely not completely correct!
+    // Shouldn't we also check the sealed attribute of the complete jar?
+    // http://java.sun.com/products/jdk/1.3/docs/guide/extensions/spec.html#bundled
+    // But how do we get that jar manifest here?
+    String sealed = attr.getValue(Attributes.Name.SEALED);
+    if ("false".equals(sealed))
+      {
+	// Make sure that the URL is null so the package is not
+	// sealed.
+	url = null;
+      }
+
+    return definePackage(name, specTitle, specVersion, specVendor,
+			 implTitle, implVersion, implVendor, url);
+  }
+
+  /**
+   * Returns the permissions needed to access a particular code source.
+   * These permissions includes those returned by
+   * <CODE>SecureClassLoader.getPermissions</CODE> and the actual permissions
+   * to access the objects referenced by the URL of the code source.
+   * The extra permissions added depend on the protocol and file portion of
+   * the URL in the code source. If the URL has the "file" protocol ends with
+   * a / character then it must be a directory and a file Permission to read
+   * everthing in that directory and all subdirectories is added. If the URL
+   * had the "file" protocol and doesn't end with a / character then it must
+   * be a normal file and a file permission to read that file is added. If the
+   * URL has any other protocol then a socket permission to connect and accept
+   * connections from the host portion of the URL is added.
+   * @param source The codesource that needs the permissions to be accessed
+   * @return the collection of permissions needed to access the code resource
+   * @see SecureClassLoader.getPermissions()
+   */
+  protected PermissionCollection getPermissions(CodeSource source)
+  {
+    // XXX - This implementation does exactly as the Javadoc describes.
+    // But maybe we should/could use URLConnection.getPermissions()?
+
+    // First get the permissions that would normally be granted
+    PermissionCollection permissions = super.getPermissions(source);
+        
+    // Now add the any extra permissions depending on the URL location
+    URL url = source.getLocation();
+    String protocol = url.getProtocol();
+    if (protocol.equals("file"))
+      {
+	String file = url.getFile();
+	// If the file end in / it must be an directory
+	if (file.endsWith("/"))
+	  {
+	    // Grant permission to read everything in that directory and
+	    // all subdirectories
+	    permissions.add(new FilePermission(file + "-", "read"));
+	  }
+	else
+	  {
+	    // It is a 'normal' file
+	    // Grant permission to access that file
+	    permissions.add(new FilePermission(file, "read"));
+	  }
+      }
+    else
+      {
+	// Grant permission to connect to and accept connections from host
+	  String host = url.getHost();
+	  permissions.add(new SocketPermission(host, "connect,accept"));
+      }
+
+    return permissions;
+  }
+
+  /**
+   * Creates a new instance of a URLClassLoader that gets classes from the
+   * supplied URLs. This class loader will have as parent the standard
+   * system class loader.
+   * @param urls the initial URLs used to resolve classes and resources
+   */
+  public static URLClassLoader newInstance(URL urls[]) throws
+    SecurityException
+  {
+    return new URLClassLoader(urls);
+  }
+
+  /**
+   * Creates a new instance of a URLClassLoader that gets classes from the
+   * supplied URLs and with the supplied loader as parent class loader.
+   * @param urls the initial URLs used to resolve classes and resources
+   * @param parent the parent class loader
+   */
+  public static URLClassLoader newInstance(URL urls[],
+					   ClassLoader parent)
+    throws SecurityException
+  {
+    return new URLClassLoader(urls, parent);
+  }
+}
Index: java/net/natPlainDatagramSocketImpl.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/natPlainDatagramSocketImpl.cc,v
retrieving revision 1.40
diff -u -r1.40 natPlainDatagramSocketImpl.cc
--- java/net/natPlainDatagramSocketImpl.cc 27 Aug 2002 16:08:30 -0000 1.40
+++ java/net/natPlainDatagramSocketImpl.cc 30 Aug 2002 18:12:27 -0000
@@ -524,6 +524,10 @@
         throw new java::net::SocketException (
           JvNewStringUTF ("SO_LINGER not valid for UDP"));
         return;
+      case _Jv_SO_KEEPALIVE_ :
+        throw new java::net::SocketException (
+          JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
+        return;
       case _Jv_SO_SNDBUF_ :
       case _Jv_SO_RCVBUF_ :
 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
@@ -613,11 +617,14 @@
         throw new java::net::SocketException (
           JvNewStringUTF ("TCP_NODELAY not valid for UDP"));
         break;
-
       case _Jv_SO_LINGER_ :
         throw new java::net::SocketException (
           JvNewStringUTF ("SO_LINGER not valid for UDP"));
         break;    
+      case _Jv_SO_KEEPALIVE_ :
+        throw new java::net::SocketException (
+          JvNewStringUTF ("SO_KEEPALIVE not valid for UDP"));
+        break;
       case _Jv_SO_RCVBUF_ :
       case _Jv_SO_SNDBUF_ :
 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
Index: java/net/natPlainSocketImpl.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/net/natPlainSocketImpl.cc,v
retrieving revision 1.43
diff -u -r1.43 natPlainSocketImpl.cc
--- java/net/natPlainSocketImpl.cc 27 Aug 2002 16:08:31 -0000 1.43
+++ java/net/natPlainSocketImpl.cc 30 Aug 2002 18:12:28 -0000
@@ -222,6 +222,20 @@
     JvNewStringLatin1 ("SocketImpl.close: unimplemented"));
 }
 
+void
+java::net::PlainSocketImpl::shutdownInput (void)
+{
+  throw new SocketException (
+    JvNewStringLatin1 ("SocketImpl.shutdownInput: unimplemented"));
+}
+
+void
+java::net::PlainSocketImpl::shutdownOutput (void)
+{
+  throw new SocketException (
+    JvNewStringLatin1 ("SocketImpl.shutdownOutput: unimplemented"));
+}
+
 #else /* DISABLE_JAVA_NET */
 
 union SockAddr
@@ -722,12 +736,18 @@
 #ifdef TCP_NODELAY
         if (::setsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
 	    val_len) != 0)
-	  goto error;    
+	  goto error;
 #else
         throw new java::lang::InternalError (
           JvNewStringUTF ("TCP_NODELAY not supported"));
 #endif /* TCP_NODELAY */
         return;
+
+      case _Jv_SO_KEEPALIVE_ :
+        if (::setsockopt (fnum, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+	    val_len) != 0)
+	  goto error;
+
       case _Jv_SO_LINGER_ :
 #ifdef SO_LINGER
         struct linger l_val;
@@ -816,6 +836,14 @@
           JvNewStringUTF ("SO_LINGER not supported"));
 #endif
         break;    
+
+      case _Jv_SO_KEEPALIVE_ :
+        if (::getsockopt (fnum, SOL_SOCKET, SO_KEEPALIVE, (char *) &val,
+	    &val_len) != 0)
+          goto error;
+        else
+	  return new java::lang::Boolean (val != 0);
+
       case _Jv_SO_RCVBUF_ :
       case _Jv_SO_SNDBUF_ :
 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
@@ -874,6 +902,20 @@
  error:
   char* strerr = strerror (errno);
   throw new java::net::SocketException (JvNewStringUTF (strerr));
+}
+
+void
+java::net::PlainSocketImpl::shutdownInput (void)
+{
+  if (::shutdown (fnum, 0))
+    throw new SocketException (JvNewStringUTF (strerror (errno)));
+}
+
+void
+java::net::PlainSocketImpl::shutdownOutput (void)
+{
+  if (::shutdown (fnum, 1))
+    throw new SocketException (JvNewStringUTF (strerror (errno)));
 }
 
 #endif /* DISABLE_JAVA_NET */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]