--- src/client.c.org	Tue Nov 30 13:49:23 2004
+++ src/client.c	Wed Dec  1 12:42:01 2004
@@ -144,6 +144,7 @@
 
 static size_t try_read_from_server PROTO ((char *, size_t));
 
+static void proxy_connect PROTO ((cvsroot_t *, int));
 static void auth_server PROTO ((cvsroot_t *, struct buffer *, struct buffer *,
 				int, int, struct hostent *));
 
@@ -3762,7 +3763,7 @@
     int port_number;
     struct sockaddr_in client_sai;
     struct hostent *hostinfo;
-    struct buffer *to_server, *from_server;
+    struct buffer *local_to_server, *local_from_server;
 
     sock = socket (AF_INET, SOCK_STREAM, 0);
     if (sock == -1)
@@ -3770,7 +3771,17 @@
 	error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
     }
     port_number = get_cvs_port_number (root);
+
+    /* if we have a proxy connect to that instead */
+    if(root->proxy)
+    {
+      hostinfo = init_sockaddr (&client_sai, root->proxy, root->proxy_port);
+    }
+    else
+    {
     hostinfo = init_sockaddr (&client_sai, root->hostname, port_number);
+    }
+    
     if (trace)
     {
 	fprintf (stderr, " -> Connecting to %s(%s):%d\n",
@@ -3780,29 +3791,41 @@
     if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai))
 	< 0)
 	error (1, 0, "connect to %s(%s):%d failed: %s",
-	       root->hostname,
+	       root->proxy ? root->proxy : root->hostname,
 	       inet_ntoa (client_sai.sin_addr),
-	       port_number, SOCK_STRERROR (SOCK_ERRNO));
+	       root->proxy ? root->proxy_port : port_number,
+	       SOCK_STRERROR (SOCK_ERRNO));
 
-    make_bufs_from_fds (sock, sock, 0, &to_server, &from_server, 1);
+    make_bufs_from_fds (sock, sock, 0, &local_to_server, &local_from_server, 1);
 
-    auth_server (root, to_server, from_server, verify_only, do_gssapi, hostinfo);
+    if(root->proxy)
+    {
+      // REALLY ugly hack to allow proxy_connect() to use send_to_server().
+      // The proper fix would be to remove the global to_server & from_server
+      // variables, and instead let send_to_server() etc. take the target
+      // server struct as a paramter.
+      to_server = local_to_server;
+      from_server = local_from_server;
+      proxy_connect (root, port_number);
+   }
+
+    auth_server (root, local_to_server, local_from_server, verify_only, do_gssapi, hostinfo);
 
     if (verify_only)
     {
 	int status;
 
-	status = buf_shutdown (to_server);
+	status = buf_shutdown (local_to_server);
 	if (status != 0)
 	    error (0, status, "shutting down buffer to server");
-	buf_free (to_server);
-	to_server = NULL;
+	buf_free (local_to_server);
+	local_to_server = NULL;
 
-	status = buf_shutdown (from_server);
+	status = buf_shutdown (local_from_server);
 	if (status != 0)
 	    error (0, status, "shutting down buffer from server");
-	buf_free (from_server);
-	from_server = NULL;
+	buf_free (local_from_server);
+	local_from_server = NULL;
 
 	/* Don't need to set server_started = 0 since we don't set it to 1
 	 * until returning from this call.
@@ -3810,11 +3833,53 @@
     }
     else
     {
-	*to_server_p = to_server;
-	*from_server_p = from_server;
+	*to_server_p = local_to_server;
+	*from_server_p = local_from_server;
     }
 
     return;
+}
+
+
+
+static void
+proxy_connect (root, port_number)
+    cvsroot_t *root;
+    int port_number;
+{
+#define CONNECT_STRING "CONNECT %s:%d HTTP/1.0\r\n\r\n"
+    /* Send a "CONNECT" command to proxy: */
+    char* read_buf;
+    int codenum, count;
+    
+    /* 4 characters for port covered by the length of %s & %d */
+    char* write_buf = xmalloc (strlen (CONNECT_STRING) + strlen (root->hostname
+) + 20 + 1);
+    int len = sprintf (write_buf, CONNECT_STRING, root->hostname, port_number);
+
+    send_to_server (write_buf, len);
+    
+    /* Wait for HTTP status code, bail out if you don't get back a 2xx code.*/
+    count = read_line (&read_buf);
+    sscanf (read_buf, "%s %d", write_buf, &codenum);
+    
+    if ((codenum / 100) != 2)
+       error (1, 0, "proxy server %s:%d does not support http tunnelling",
+              root->proxy, root->proxy_port);
+    free (read_buf);
+    free (write_buf);
+    
+    /* Skip through remaining part of MIME header, recv_line
+       consumes the trailing \n */
+    while(read_line (&read_buf) > 0)
+    {
+       if (read_buf[0] == '\r' || read_buf[0] == 0)
+       {
+           free (read_buf);
+           break;
+       }
+       free (read_buf);
+    }
 }
 
 
--- src/client.h.org	Wed Dec  1 07:36:43 2004
+++ src/client.h	Wed Dec  1 07:38:06 2004
@@ -69,6 +69,9 @@
 #   ifndef CVS_AUTH_PORT
 #     define CVS_AUTH_PORT 2401
 #   endif /* CVS_AUTH_PORT */
+#   ifndef CVS_PROXY_PORT
+#     define CVS_PROXY_PORT 80
+#   endif /* CVS_PROXY_PORT */
 # endif /* (AUTH_CLIENT_SUPPORT) || defined (HAVE_GSSAPI) */
 
 # if HAVE_KERBEROS
--- src/root.c.org	Wed Dec  1 07:38:19 2004
+++ src/root.c	Wed Dec  1 07:48:43 2004
@@ -303,6 +303,8 @@
     newroot->proxy_port = 0;
     newroot->isremote = 0;
 #endif /* CLIENT_SUPPORT */
+    newroot->proxy = NULL;
+    newroot->proxy_port = CVS_PROXY_PORT;
 
     return newroot;
 }
@@ -332,6 +334,8 @@
     if (root->proxy_hostname != NULL)
 	free (root->proxy_hostname);
 #endif /* CLIENT_SUPPORT */
+    if (root->proxy != NULL)
+	free (root->proxy);
     free (root);
 }
 
@@ -375,6 +379,7 @@
 #ifdef CLIENT_SUPPORT
     int check_hostname, no_port, no_password;
 #endif /* CLIENT_SUPPORT */
+    const char *env_var;
 
     /* allocate some space */
     newroot = new_cvsroot_t();
@@ -555,6 +560,29 @@
 	/* restore the '/' */
 	cvsroot_copy = firstslash;
 	*cvsroot_copy = '/';
+
+       
+       /* Determine proxy */
+       env_var = getenv("CVS_PROXY");
+       if (!env_var)
+           env_var = getenv("HTTP_PROXY");
+       /* Check if a proxy was specified, and if it is a HTTP proxy */
+       if (env_var && !memcmp(env_var, "http://", 7))
+       {
+           char *port_str;
+           
+           /* Try to parse the proxy data */
+           env_var += 7;
+           /* TODO - parse username/password data, too */
+           port_str = strchr(env_var, ':');
+           if (port_str)
+           {
+               *port_str++ = 0;
+               newroot->proxy_port = atoi(port_str);
+           }
+           newroot->proxy = xstrdup(env_var);
+       }
+
 #endif /* CLIENT_SUPPORT */
     }
 
--- src/root.h.org	Wed Dec  1 07:48:49 2004
+++ src/root.h	Wed Dec  1 12:26:12 2004
@@ -39,4 +39,5 @@
     int proxy_port;		/* The port of the proxy or zero, as above. */
     unsigned char isremote;	/* Nonzero if we are doing remote access. */
 #endif /* CLIENT_SUPPORT */
+    char *proxy;	
 } cvsroot_t;
