Index: lib/curl_ldap.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/curl_ldap.h,v
retrieving revision 1.1
diff -u -r1.1 curl_ldap.h
--- lib/curl_ldap.h	11 Aug 2007 20:57:54 -0000	1.1
+++ lib/curl_ldap.h	10 Oct 2007 14:13:32 -0000
@@ -24,6 +24,12 @@
  * $Id: curl_ldap.h,v 1.1 2007-08-11 20:57:54 bagder Exp $
  ***************************************************************************/
 #ifndef CURL_DISABLE_LDAP
+extern struct Curl_handler Curl_handler_ldap;
+
+#ifdef HAVE_LDAP_SSL
+extern struct Curl_handler Curl_handler_ldaps;
+#endif
+
 CURLcode Curl_ldap(struct connectdata *conn, bool *done);
 #endif
 #endif /* __CURL_LDAP_H */
Index: lib/dict.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/dict.c,v
retrieving revision 1.50
diff -u -r1.50 dict.c
--- lib/dict.c	26 Aug 2007 05:53:26 -0000	1.50
+++ lib/dict.c	10 Oct 2007 18:04:39 -0000
@@ -82,6 +82,27 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
+
+/*
+ * DICT protocol handler.
+ */
+
+struct Curl_handler Curl_handler_dict = {
+  "DICT",                               /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_dict,                            /* curl_do */
+  NULL,                                 /* curl_done */
+  NULL,                                 /* curl_do_more */
+  NULL,                                 /* curl_connect */
+  NULL,                                 /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_DICT,                            /* defport */
+  PROT_DICT                             /* protocol */
+};
+
 static char *unescape_word(struct SessionHandle *data, const char *inp)
 {
   char *newp;
Index: lib/dict.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/dict.h,v
retrieving revision 1.12
diff -u -r1.12 dict.h
--- lib/dict.h	9 Feb 2005 13:06:40 -0000	1.12
+++ lib/dict.h	10 Oct 2007 14:04:18 -0000
@@ -24,6 +24,8 @@
  * $Id: dict.h,v 1.12 2005-02-09 13:06:40 bagder Exp $
  ***************************************************************************/
 #ifndef CURL_DISABLE_DICT
+extern struct Curl_handler Curl_handler_dict;
+
 CURLcode Curl_dict(struct connectdata *conn, bool *done);
 CURLcode Curl_dict_done(struct connectdata *conn);
 #endif
Index: lib/file.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/file.c,v
retrieving revision 1.93
diff -u -r1.93 file.c
--- lib/file.c	27 Sep 2007 01:45:23 -0000	1.93
+++ lib/file.c	10 Oct 2007 18:04:44 -0000
@@ -89,6 +89,27 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
+
+/*
+ * FILE scheme handler.
+ */
+
+struct Curl_handler Curl_handler_file = {
+  "FILE",                               /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_file,                            /* curl_do */
+  Curl_file_done,                       /* curl_done */
+  NULL,                                 /* curl_do_more */
+  NULL,                                 /* curl_connect */
+  NULL,                                 /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  0,                                    /* defport */
+  PROT_FILE                             /* protocol */
+};
+
 /*
  * Curl_file_connect() gets called from Curl_protocol_connect() to allow us to
  * do protocol-specific actions at connect-time.  We emulate a
Index: lib/file.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/file.h,v
retrieving revision 1.14
diff -u -r1.14 file.h
--- lib/file.h	16 Jan 2007 22:22:23 -0000	1.14
+++ lib/file.h	10 Oct 2007 14:12:57 -0000
@@ -24,6 +24,8 @@
  * $Id: file.h,v 1.14 2007-01-16 22:22:23 bagder Exp $
  ***************************************************************************/
 #ifndef CURL_DISABLE_FILE
+extern struct Curl_handler Curl_handler_file;
+
 CURLcode Curl_file(struct connectdata *, bool *done);
 CURLcode Curl_file_done(struct connectdata *, CURLcode, bool premature);
 CURLcode Curl_file_connect(struct connectdata *);
Index: lib/ftp.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/ftp.c,v
retrieving revision 1.443
diff -u -r1.443 ftp.c
--- lib/ftp.c	2 Oct 2007 19:19:47 -0000	1.443
+++ lib/ftp.c	10 Oct 2007 18:05:01 -0000
@@ -142,6 +142,95 @@
 
 
 /*
+ * FTP protocol handler.
+ */
+
+struct Curl_handler Curl_handler_ftp = {
+  "FTP",                                /* scheme */
+  Curl_ftp_setup_connection,            /* curl_setup_connection */
+  Curl_ftp,                             /* curl_do */
+  Curl_ftp_done,                        /* curl_done */
+  Curl_ftp_nextconnect,                 /* curl_do_more */
+  Curl_ftp_connect,                     /* curl_connect */
+  Curl_ftp_multi_statemach,             /* curl_connecting */
+  Curl_ftp_doing,                       /* curl_doing */
+  Curl_ftp_getsock,                     /* curl_proto_getsock */
+  Curl_ftp_getsock,                     /* curl_doing_getsock */
+  Curl_ftp_disconnect,                  /* curl_disconnect */
+  PORT_FTP,                             /* defport */
+  PROT_FTP                              /* protocol */
+};
+
+
+#ifdef USE_SSL
+/*
+ * FTPS protocol handler.
+ */
+
+struct Curl_handler Curl_handler_ftps = {
+  "FTPS",                               /* scheme */
+  Curl_ftps_setup_connection,           /* curl_setup_connection */
+  Curl_ftp,                             /* curl_do */
+  Curl_ftp_done,                        /* curl_done */
+  Curl_ftp_nextconnect,                 /* curl_do_more */
+  Curl_ftp_connect,                     /* curl_connect */
+  Curl_ftp_multi_statemach,             /* curl_connecting */
+  Curl_ftp_doing,                       /* curl_doing */
+  Curl_ftp_getsock,                     /* curl_proto_getsock */
+  Curl_ftp_getsock,                     /* curl_doing_getsock */
+  Curl_ftp_disconnect,                  /* curl_disconnect */
+  PORT_FTPS,                            /* defport */
+  PROT_FTP | PROT_FTPS | PROT_SSL       /* protocol */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed FTP protocol handler.
+ */
+
+struct Curl_handler Curl_handler_ftp_proxy = {
+  "FTP",                                /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_http,                            /* curl_do */
+  Curl_http_done,                       /* curl_done */
+  NULL,                                 /* curl_do_more */
+  NULL,                                 /* curl_connect */
+  NULL,                                 /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_FTP,                             /* defport */
+  PROT_HTTP                             /* protocol */
+};
+
+
+# ifdef USE_SSL
+/*
+ * HTTP-proxyed FTPS protocol handler.
+ */
+
+struct Curl_handler Curl_handler_ftps_proxy = {
+  "FTPS",                               /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_http,                            /* curl_do */
+  Curl_http_done,                       /* curl_done */
+  NULL,                                 /* curl_do_more */
+  NULL,                                 /* curl_connect */
+  NULL,                                 /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_FTPS,                            /* defport */
+  PROT_HTTP                             /* protocol */
+};
+# endif
+#endif
+
+
+/*
  * NOTE: back in the old days, we added code in the FTP code that made NOBODY
  * requests on files respond with headers passed to the client/stdout that
  * looked like HTTP ones.
@@ -3996,4 +4085,64 @@
   return result;
 }
 
+CURLcode Curl_ftp_setup_connection(struct connectdata * conn)
+{
+  struct SessionHandle *data = conn->data;
+  char * type;
+  char command;
+
+  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+    /* Unless we have asked to tunnel ftp operations through the proxy, we
+       switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+  if (conn->handler == &Curl_handler_ftp)
+    conn->handler = &Curl_handler_ftp_proxy;
+  else
+    conn->handler = &Curl_handler_ftps_proxy;
+#else
+    failf(data, "FTP over http proxy requires HTTP support built-in!");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+  }
+
+  data->reqdata.path++;   /* don't include the initial slash */
+
+  /* FTP URLs support an extension like ";type=<typecode>" that
+   * we'll try to get now! */
+  type = strstr(data->reqdata.path, ";type=");
+
+  if (!type)
+    type = strstr(conn->host.rawalloc, ";type=");
+
+  if (type) {
+    *type = 0;                     /* it was in the middle of the hostname */
+    command = (char) toupper((int) type[6]);
+
+    switch (command) {
+    case 'A': /* ASCII mode */
+      data->set.prefer_ascii = TRUE;
+      break;
+
+    case 'D': /* directory mode */
+      data->set.ftp_list_only = TRUE;
+      break;
+
+    case 'I': /* binary mode */
+    default:
+      /* switch off ASCII */
+      data->set.prefer_ascii = FALSE;
+      break;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_ftps_setup_connection(struct connectdata * conn)
+{
+  struct SessionHandle *data = conn->data;
+
+  conn->ssl[SECONDARYSOCKET].use = data->set.ftp_ssl != CURLUSESSL_CONTROL;
+  return Curl_ftp_setup_connection(conn);
+}
 #endif /* CURL_DISABLE_FTP */
Index: lib/ftp.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/ftp.h,v
retrieving revision 1.25
diff -u -r1.25 ftp.h
--- lib/ftp.h	27 Jan 2007 03:43:06 -0000	1.25
+++ lib/ftp.h	10 Oct 2007 16:31:21 -0000
@@ -24,6 +24,20 @@
  ***************************************************************************/
 
 #ifndef CURL_DISABLE_FTP
+extern struct Curl_handler Curl_handler_ftp;
+
+#ifdef USE_SSL
+extern struct Curl_handler Curl_handler_ftps;
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+extern struct Curl_handler Curl_handler_ftp_proxy;
+
+# ifdef USE_SSL
+extern struct Curl_handler Curl_handler_ftps_proxy;
+# endif
+#endif
+
 CURLcode Curl_ftp(struct connectdata *conn, bool *done);
 CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode, bool premature);
 CURLcode Curl_ftp_connect(struct connectdata *conn, bool *done);
@@ -39,5 +53,7 @@
                      int numsocks);
 CURLcode Curl_ftp_doing(struct connectdata *conn,
                         bool *dophase_done);
+CURLcode Curl_ftp_setup_connection(struct connectdata * conn);
+CURLcode Curl_ftps_setup_connection(struct connectdata * conn);
 #endif /* CURL_DISABLE_FTP */
 #endif /* __FTP_H */
Index: lib/http.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/http.c,v
retrieving revision 1.338
diff -u -r1.338 http.c
--- lib/http.c	7 Oct 2007 08:28:04 -0000	1.338
+++ lib/http.c	10 Oct 2007 18:05:13 -0000
@@ -104,6 +104,48 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
+
+/*
+ * HTTP handler interface.
+ */
+struct Curl_handler Curl_handler_http = {
+  "HTTP",                               /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_http,                            /* curl_do */
+  Curl_http_done,                       /* curl_done */
+  NULL,                                 /* curl_do_more */
+  Curl_http_connect,                    /* curl_connect */
+  NULL,                                 /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_HTTP,                            /* defport */
+  PROT_HTTP,                            /* protocol */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTPS handler interface.
+ */
+struct Curl_handler Curl_handler_https = {
+  "HTTPS",                              /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_http,                            /* curl_do */
+  Curl_http_done,                       /* curl_done */
+  NULL,                                 /* curl_do_more */
+  Curl_http_connect,                    /* curl_connect */
+  Curl_https_connecting,                /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  Curl_https_getsock,                   /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_HTTPS,                           /* defport */
+  PROT_HTTP | PROT_HTTPS | PROT_SSL     /* protocol */
+};
+#endif
+
+
 /*
  * checkheaders() checks the linked list of custom HTTP headers for a
  * particular header (prefix).
Index: lib/http.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/http.h,v
retrieving revision 1.35
diff -u -r1.35 http.h
--- lib/http.h	27 Aug 2007 06:31:28 -0000	1.35
+++ lib/http.h	10 Oct 2007 13:15:05 -0000
@@ -24,6 +24,13 @@
  * $Id: http.h,v 1.35 2007-08-27 06:31:28 danf Exp $
  ***************************************************************************/
 #ifndef CURL_DISABLE_HTTP
+
+extern struct Curl_handler Curl_handler_http;
+
+#ifdef USE_SSL
+extern struct Curl_handler Curl_handler_https;
+#endif
+
 bool Curl_compareheader(const char *headerline,  /* line to check */
                         const char *header,   /* header keyword _with_ colon */
                         const char *content); /* content string to find */
Index: lib/ldap.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/ldap.c,v
retrieving revision 1.86
diff -u -r1.86 ldap.c
--- lib/ldap.c	9 Oct 2007 23:51:55 -0000	1.86
+++ lib/ldap.c	10 Oct 2007 18:05:21 -0000
@@ -118,6 +118,49 @@
 #endif
 
 
+/*
+ * LDAP protocol handler.
+ */
+
+struct Curl_handler Curl_handler_ldap = {
+  "LDAP",                               /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_ldap,                            /* curl_do */
+  NULL,                                 /* curl_done */
+  NULL,                                 /* curl_do_more */
+  NULL,                                 /* curl_connect */
+  NULL,                                 /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_LDAP,                            /* defport */
+  PROT_LDAP                             /* protocol */
+};
+
+#ifdef HAVE_LDAP_SSL
+/*
+ * LDAPS protocol handler.
+ */
+
+struct Curl_handler Curl_handler_ldaps = {
+  "LDAPS",                              /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_ldap,                            /* curl_do */
+  NULL,                                 /* curl_done */
+  NULL,                                 /* curl_do_more */
+  NULL,                                 /* curl_connect */
+  NULL,                                 /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_LDAPS,                           /* defport */
+  PROT_LDAP | PROT_SSL                  /* protocol */
+};
+#endif
+
+
 CURLcode Curl_ldap(struct connectdata *conn, bool *done)
 {
   CURLcode status = CURLE_OK;
Index: lib/ssh.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/ssh.c,v
retrieving revision 1.77
diff -u -r1.77 ssh.c
--- lib/ssh.c	3 Oct 2007 08:07:50 -0000	1.77
+++ lib/ssh.c	10 Oct 2007 18:05:38 -0000
@@ -134,6 +134,49 @@
 
 static int get_pathname(const char **cpp, char **path);
 
+
+/*
+ * SCP protocol handler.
+ */
+
+struct Curl_handler Curl_handler_scp = {
+  "SCP",                                /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_scp_do,                          /* curl_do */
+  Curl_scp_done,                        /* curl_done */
+  NULL,                                 /* curl_do_more */
+  Curl_ssh_connect,                     /* curl_connect */
+  Curl_ssh_multi_statemach,             /* curl_connecting */
+  Curl_scp_doing,                       /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_SSH,                             /* defport */
+  PROT_SCP                              /* protocol */
+};
+
+
+/*
+ * SFTP protocol handler.
+ */
+
+struct Curl_handler Curl_handler_sftp = {
+  "SFTP",                               /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_sftp_do,                         /* curl_do */
+  Curl_sftp_done,                       /* curl_done */
+  NULL,                                 /* curl_do_more */
+  Curl_ssh_connect,                     /* curl_connect */
+  Curl_ssh_multi_statemach,             /* curl_connecting */
+  Curl_sftp_doing,                      /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_SSH,                             /* defport */
+  PROT_SFTP                             /* protocol */
+};
+
+
 static void
 kbd_callback(const char *name, int name_len, const char *instruction,
              int instruction_len, int num_prompts,
Index: lib/ssh.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/ssh.h,v
retrieving revision 1.8
diff -u -r1.8 ssh.h
--- lib/ssh.h	3 Aug 2007 08:14:51 -0000	1.8
+++ lib/ssh.h	10 Oct 2007 14:30:20 -0000
@@ -25,6 +25,8 @@
  ***************************************************************************/
 
 #ifdef USE_LIBSSH2
+extern struct Curl_handler Curl_handler_scp;
+extern struct Curl_handler Curl_handler_sftp;
 
 CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done);
 CURLcode Curl_ssh_multi_statemach(struct connectdata *conn, bool *done);
Index: lib/telnet.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/telnet.c,v
retrieving revision 1.91
diff -u -r1.91 telnet.c
--- lib/telnet.c	30 Aug 2007 20:34:58 -0000	1.91
+++ lib/telnet.c	10 Oct 2007 18:05:47 -0000
@@ -170,6 +170,28 @@
   TelnetReceive telrcv_state;
 };
 
+
+/*
+ * TELNET protocol handler.
+ */
+
+struct Curl_handler Curl_handler_telnet = {
+  "TELNET",                             /* scheme */
+  NULL,                                 /* curl_setup_connection */
+  Curl_telnet,                          /* curl_do */
+  Curl_telnet_done,                     /* curl_done */
+  NULL,                                 /* curl_do_more */
+  NULL,                                 /* curl_connect */
+  NULL,                                 /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_TELNET,                          /* defport */
+  PROT_TELNET                           /* protocol */
+};
+
+
 #ifdef USE_WINSOCK
 static CURLcode
 check_wsock2 ( struct SessionHandle *data )
Index: lib/telnet.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/telnet.h,v
retrieving revision 1.14
diff -u -r1.14 telnet.h
--- lib/telnet.h	16 Jan 2007 22:22:24 -0000	1.14
+++ lib/telnet.h	10 Oct 2007 14:00:26 -0000
@@ -24,6 +24,8 @@
  * $Id: telnet.h,v 1.14 2007-01-16 22:22:24 bagder Exp $
  ***************************************************************************/
 #ifndef CURL_DISABLE_TELNET
+extern struct Curl_handler Curl_handler_telnet;
+
 CURLcode Curl_telnet(struct connectdata *conn, bool *done);
 CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode, bool premature);
 #endif
Index: lib/tftp.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/tftp.c,v
retrieving revision 1.52
diff -u -r1.52 tftp.c
--- lib/tftp.c	4 Oct 2007 10:01:41 -0000	1.52
+++ lib/tftp.c	10 Oct 2007 18:05:52 -0000
@@ -152,6 +152,28 @@
 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ;
 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ;
 
+
+/*
+ * TFTP protocol handler.
+ */
+
+struct Curl_handler Curl_handler_tftp = {
+  "TFTP",                               /* scheme */
+  Curl_tftp_setup_connection,           /* curl_setup_connection */
+  Curl_tftp,                            /* curl_do */
+  Curl_tftp_done,                       /* curl_done */
+  NULL,                                 /* curl_do_more */
+  Curl_tftp_connect,                    /* curl_connect */
+  NULL,                                 /* curl_connecting */
+  NULL,                                 /* curl_doing */
+  NULL,                                 /* curl_proto_getsock */
+  NULL,                                 /* curl_doing_getsock */
+  NULL,                                 /* curl_disconnect */
+  PORT_TFTP,                            /* defport */
+  PROT_TFTP                             /* protocol */
+};
+
+
 /**********************************************************
  *
  * tftp_set_timeouts -
@@ -836,4 +858,41 @@
     code = CURLE_OK;
   return code;
 }
+
+CURLcode Curl_tftp_setup_connection(struct connectdata * conn)
+{
+  struct SessionHandle *data = conn->data;
+  char * type;
+  char command;
+
+  conn->socktype = SOCK_DGRAM;   /* UDP datagram based */
+
+  /* TFTP URLs support an extension like ";mode=<typecode>" that
+   * we'll try to get now! */
+  type = strstr(data->reqdata.path, ";mode=");
+
+  if (!type)
+    type = strstr(conn->host.rawalloc, ";mode=");
+
+  if (type) {
+    *type = 0;                   /* it was in the middle of the hostname */
+    command = (char) toupper((int) type[6]);
+
+    switch (command) {
+    case 'A': /* ASCII mode */
+    case 'N': /* NETASCII mode */
+      data->set.prefer_ascii = TRUE;
+      break;
+
+    case 'O': /* octet mode */
+    case 'I': /* binary mode */
+    default:
+      /* switch off ASCII */
+      data->set.prefer_ascii = FALSE;
+      break;
+    }
+  }
+
+  return CURLE_OK;
+}
 #endif
Index: lib/tftp.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/tftp.h,v
retrieving revision 1.2
diff -u -r1.2 tftp.h
--- lib/tftp.h	16 Jan 2007 22:22:24 -0000	1.2
+++ lib/tftp.h	10 Oct 2007 15:27:45 -0000
@@ -24,8 +24,11 @@
  * $Id: tftp.h,v 1.2 2007-01-16 22:22:24 bagder Exp $
  ***************************************************************************/
 #ifndef CURL_DISABLE_TFTP
+extern struct Curl_handler Curl_handler_tftp;
+
 CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done);
 CURLcode Curl_tftp(struct connectdata *conn, bool *done);
 CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode, bool premature);
+CURLcode Curl_tftp_setup_connection(struct connectdata * conn);
 #endif
 #endif
Index: lib/url.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/url.c,v
retrieving revision 1.651
diff -u -r1.651 url.c
--- lib/url.c	5 Oct 2007 14:37:33 -0000	1.651
+++ lib/url.c	10 Oct 2007 16:32:15 -0000
@@ -178,6 +178,7 @@
 
 #define ZERO_NULL 0
 
+
 #ifndef USE_ARES
 /* not for ares builds */
 
@@ -188,6 +189,62 @@
 extern sigjmp_buf curl_jmpenv;
 #endif
 
+
+/*
+ * Protocol table.
+ */
+
+static struct Curl_handler * protocols[] = {
+
+#ifndef CURL_DISABLE_HTTP
+  &Curl_handler_http,
+#endif
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+  &Curl_handler_https,
+#endif
+
+#ifndef CURL_DISABLE_FTP
+  &Curl_handler_ftp,
+#endif
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+  &Curl_handler_ftps,
+#endif
+
+#ifndef CURL_DISABLE_TELNET
+  &Curl_handler_telnet,
+#endif
+
+#ifndef CURL_DISABLE_DICT
+  &Curl_handler_dict,
+#endif
+
+#ifndef CURL_DISABLE_LDAP
+  &Curl_handler_ldap,
+#endif
+
+#if defined(HAVE_LDAP_SSL) && !defined(CURL_DISABLE_SSL)
+  &Curl_handler_ldaps,
+#endif
+
+#ifndef CURL_DISABLE_FILE
+  &Curl_handler_file,
+#endif
+
+#ifndef CURL_DISABLE_TFTP
+  &Curl_handler_tftp,
+#endif
+
+#ifdef USE_LIBSSH2
+  &Curl_handler_scp,
+  &Curl_handler_sftp,
+#endif
+
+  (struct Curl_handler *) NULL
+};
+
+
 #ifdef SIGALRM
 static
 RETSIGTYPE alarmfunc(int sig)
@@ -1999,9 +2056,9 @@
     Curl_ntlm_cleanup(conn);
   }
 
-  if(conn->curl_disconnect)
+  if(conn->handler->curl_disconnect)
     /* This is set if protocol-specific cleanups should be made */
-    conn->curl_disconnect(conn);
+    conn->handler->curl_disconnect(conn);
 
   if(-1 != conn->connectindex) {
     /* unlink ourselves! */
@@ -2519,8 +2576,8 @@
                           curl_socket_t *socks,
                           int numsocks)
 {
-  if(conn->curl_proto_getsock)
-    return conn->curl_proto_getsock(conn, socks, numsocks);
+  if(conn->handler->curl_proto_getsock)
+    return conn->handler->curl_proto_getsock(conn, socks, numsocks);
   return GETSOCK_BLANK;
 }
 
@@ -2528,8 +2585,8 @@
                        curl_socket_t *socks,
                        int numsocks)
 {
-  if(conn && conn->curl_doing_getsock)
-    return conn->curl_doing_getsock(conn, socks, numsocks);
+  if(conn && conn->handler->curl_doing_getsock)
+    return conn->handler->curl_doing_getsock(conn, socks, numsocks);
   return GETSOCK_BLANK;
 }
 
@@ -2544,9 +2601,9 @@
 {
   CURLcode result=CURLE_OK;
 
-  if(conn && conn->curl_connecting) {
+  if(conn && conn->handler->curl_connecting) {
     *done = FALSE;
-    result = conn->curl_connecting(conn, done);
+    result = conn->handler->curl_connecting(conn, done);
   }
   else
     *done = TRUE;
@@ -2563,9 +2620,9 @@
 {
   CURLcode result=CURLE_OK;
 
-  if(conn && conn->curl_doing) {
+  if(conn && conn->handler->curl_doing) {
     *done = FALSE;
-    result = conn->curl_doing(conn, done);
+    result = conn->handler->curl_doing(conn, done);
   }
   else
     *done = TRUE;
@@ -2593,7 +2650,7 @@
 
        Unless this protocol doesn't have any protocol-connect callback, as
        then we know we're done. */
-    if(!conn->curl_connecting)
+    if(!conn->handler->curl_connecting)
       *protocol_done = TRUE;
 
     return CURLE_OK;
@@ -2608,7 +2665,7 @@
   }
 
   if(!conn->bits.protoconnstart) {
-    if(conn->curl_connect) {
+    if(conn->handler->curl_connect) {
       /* is there a protocol-specific connect() procedure? */
 
       /* Set start time here for timeout purposes in the connect procedure, it
@@ -2616,7 +2673,7 @@
       conn->now = Curl_tvnow();
 
       /* Call the protocol-specific connect function */
-      result = conn->curl_connect(conn, protocol_done);
+      result = conn->handler->curl_connect(conn, protocol_done);
     }
     else
       *protocol_done = TRUE;
@@ -2943,285 +3000,38 @@
 static CURLcode setup_connection_internals(struct SessionHandle *data,
                                            struct connectdata *conn)
 {
-  conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
-
-  if (strequal(conn->protostr, "HTTP")) {
-#ifndef CURL_DISABLE_HTTP
-    conn->port = PORT_HTTP;
-    conn->remote_port = PORT_HTTP;
-    conn->protocol |= PROT_HTTP;
-    conn->curl_do = Curl_http;
-    conn->curl_do_more = (Curl_do_more_func)ZERO_NULL;
-    conn->curl_done = Curl_http_done;
-    conn->curl_connect = Curl_http_connect;
-#else
-    failf(data, LIBCURL_NAME
-          " was built with HTTP disabled, http: not supported!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
+  struct Curl_handler * * pp;
+  struct Curl_handler * p;
+  CURLcode result;
 
-  else if (strequal(conn->protostr, "HTTPS")) {
-#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+  conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
 
-    conn->port = PORT_HTTPS;
-    conn->remote_port = PORT_HTTPS;
-    conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
-
-    conn->curl_do = Curl_http;
-    conn->curl_do_more = (Curl_do_more_func)ZERO_NULL;
-    conn->curl_done = Curl_http_done;
-    conn->curl_connect = Curl_http_connect;
-    conn->curl_connecting = Curl_https_connecting;
-    conn->curl_proto_getsock = Curl_https_getsock;
-
-#else /* USE_SSL */
-    failf(data, LIBCURL_NAME
-          " was built with SSL disabled, https: not supported!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif /* !USE_SSL */
-  }
+  /* Scan protocol handler table. */
 
-  else if(strequal(conn->protostr, "FTP") ||
-          strequal(conn->protostr, "FTPS")) {
+  for (pp = protocols; p = *pp; pp++)
+    if (strequal(p->scheme, conn->protostr)) {
+      /* Protocol found in table. Perform setup complement if some. */
+      conn->handler = p;
 
-#ifndef CURL_DISABLE_FTP
-    char *type;
-    int port = PORT_FTP;
+      if (p->curl_setup_connection) {
+        result = (*p->curl_setup_connection)(conn);
 
-    if(strequal(conn->protostr, "FTPS")) {
-#ifdef USE_SSL
-      conn->protocol |= PROT_FTPS|PROT_SSL;
-      /* send data securely unless specifically requested otherwise */
-      conn->ssl[SECONDARYSOCKET].use = data->set.ftp_ssl != CURLUSESSL_CONTROL;
-      port = PORT_FTPS;
-#else
-      failf(data, LIBCURL_NAME
-            " was built with SSL disabled, ftps: not supported!");
-      return CURLE_UNSUPPORTED_PROTOCOL;
-#endif /* !USE_SSL */
-    }
+        if (result != CURLE_OK)
+          return result;
 
-    conn->port = port;
-    conn->remote_port = (unsigned short)port;
-    conn->protocol |= PROT_FTP;
-
-    if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
-      /* Unless we have asked to tunnel ftp operations through the proxy, we
-         switch and use HTTP operations only */
-#ifndef CURL_DISABLE_HTTP
-      conn->curl_do = Curl_http;
-      conn->curl_done = Curl_http_done;
-      conn->protocol = PROT_HTTP; /* switch to HTTP */
-#else
-      failf(data, "FTP over http proxy requires HTTP support built-in!");
-      return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-    }
-    else {
-      conn->curl_do = Curl_ftp;
-      conn->curl_do_more = Curl_ftp_nextconnect;
-      conn->curl_done = Curl_ftp_done;
-      conn->curl_connect = Curl_ftp_connect;
-      conn->curl_connecting = Curl_ftp_multi_statemach;
-      conn->curl_doing = Curl_ftp_doing;
-      conn->curl_proto_getsock = Curl_ftp_getsock;
-      conn->curl_doing_getsock = Curl_ftp_getsock;
-      conn->curl_disconnect = Curl_ftp_disconnect;
-    }
-
-    data->reqdata.path++; /* don't include the initial slash */
-
-    /* FTP URLs support an extension like ";type=<typecode>" that
-     * we'll try to get now! */
-    type=strstr(data->reqdata.path, ";type=");
-    if(!type) {
-      type=strstr(conn->host.rawalloc, ";type=");
-    }
-    if(type) {
-      char command;
-      *type=0;                     /* it was in the middle of the hostname */
-      command = (char)toupper((int)type[6]);
-      switch(command) {
-      case 'A': /* ASCII mode */
-        data->set.prefer_ascii = TRUE;
-        break;
-      case 'D': /* directory mode */
-        data->set.ftp_list_only = TRUE;
-        break;
-      case 'I': /* binary mode */
-      default:
-        /* switch off ASCII */
-        data->set.prefer_ascii = FALSE;
-        break;
+        p = conn->handler;              /* May have changed. */
       }
-    }
-#else /* CURL_DISABLE_FTP */
-    failf(data, LIBCURL_NAME
-          " was built with FTP disabled, ftp/ftps: not supported!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
-  else if(strequal(conn->protostr, "TELNET")) {
-#ifndef CURL_DISABLE_TELNET
-    /* telnet testing factory */
-    conn->protocol |= PROT_TELNET;
-
-    conn->port = PORT_TELNET;
-    conn->remote_port = PORT_TELNET;
-    conn->curl_do = Curl_telnet;
-    conn->curl_done = Curl_telnet_done;
-#else
-    failf(data, LIBCURL_NAME
-          " was built with TELNET disabled!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
-  else if (strequal(conn->protostr, "DICT")) {
-#ifndef CURL_DISABLE_DICT
-    conn->protocol |= PROT_DICT;
-    conn->port = PORT_DICT;
-    conn->remote_port = PORT_DICT;
-    conn->curl_do = Curl_dict;
-    /* no DICT-specific done */
-    conn->curl_done = (Curl_done_func)ZERO_NULL;
-#else
-    failf(data, LIBCURL_NAME
-          " was built with DICT disabled!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
-  else if (strequal(conn->protostr, "LDAP")) {
-#ifndef CURL_DISABLE_LDAP
-    conn->protocol |= PROT_LDAP;
-    conn->port = PORT_LDAP;
-    conn->remote_port = PORT_LDAP;
-    conn->curl_do = Curl_ldap;
-    /* no LDAP-specific done */
-    conn->curl_done = (Curl_done_func)ZERO_NULL;
-#else
-    failf(data, LIBCURL_NAME
-          " was built with LDAP disabled!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
-#ifdef HAVE_LDAP_SSL
-  else if (strequal(conn->protostr, "LDAPS")) {
-#ifndef CURL_DISABLE_LDAP
-    conn->protocol |= PROT_LDAP|PROT_SSL;
-    conn->port = PORT_LDAPS;
-    conn->remote_port = PORT_LDAPS;
-    conn->curl_do = Curl_ldap;
-    /* no LDAP-specific done */
-    conn->curl_done = (Curl_done_func)ZERO_NULL;
-#else
-    failf(data, LIBCURL_NAME
-          " was built with LDAP disabled!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-#endif /* CURL_LDAP_USE_SSL */
-
-  else if (strequal(conn->protostr, "FILE")) {
-#ifndef CURL_DISABLE_FILE
-    conn->protocol |= PROT_FILE;
-
-    conn->curl_do = Curl_file;
-    conn->curl_done = Curl_file_done;
-#else
-    failf(data, LIBCURL_NAME
-          " was built with FILE disabled!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
 
-  else if (strequal(conn->protostr, "TFTP")) {
-#ifndef CURL_DISABLE_TFTP
-    char *type;
-    conn->socktype = SOCK_DGRAM; /* UDP datagram based */
-    conn->protocol |= PROT_TFTP;
-    conn->port = PORT_TFTP;
-    conn->remote_port = PORT_TFTP;
-    conn->curl_connect = Curl_tftp_connect;
-    conn->curl_do = Curl_tftp;
-    conn->curl_done = Curl_tftp_done;
-    /* TFTP URLs support an extension like ";mode=<typecode>" that
-     * we'll try to get now! */
-    type=strstr(data->reqdata.path, ";mode=");
-    if(!type) {
-      type=strstr(conn->host.rawalloc, ";mode=");
-    }
-    if(type) {
-      char command;
-      *type=0;                     /* it was in the middle of the hostname */
-      command = (char)toupper((int)type[6]);
-      switch(command) {
-      case 'A': /* ASCII mode */
-      case 'N': /* NETASCII mode */
-        data->set.prefer_ascii = TRUE;
-        break;
-      case 'O': /* octet mode */
-      case 'I': /* binary mode */
-      default:
-        /* switch off ASCII */
-        data->set.prefer_ascii = FALSE;
-        break;
-      }
+      conn->port = p->defport;
+      conn->remote_port = p->defport;
+      conn->protocol |= p->protocol;
+      return CURLE_OK;
     }
-#else
-    failf(data, LIBCURL_NAME
-          " was built with TFTP disabled!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
-  else if (strequal(conn->protostr, "SCP")) {
-#ifdef USE_LIBSSH2
-    conn->port = PORT_SSH;
-    conn->remote_port = PORT_SSH;
-    conn->protocol = PROT_SCP;
-    conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */
-    conn->curl_do = Curl_scp_do;
-    conn->curl_done = Curl_scp_done;
-    conn->curl_connecting = Curl_ssh_multi_statemach;
-    conn->curl_doing = Curl_scp_doing;
-    conn->curl_do_more = (Curl_do_more_func)ZERO_NULL;
-#else
-    failf(data, LIBCURL_NAME
-          " was built without LIBSSH2, scp: not supported!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
-  else if (strequal(conn->protostr, "SFTP")) {
-#ifdef USE_LIBSSH2
-    conn->port = PORT_SSH;
-    conn->remote_port = PORT_SSH;
-    conn->protocol = PROT_SFTP;
-    conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */
-    conn->curl_do = Curl_sftp_do;
-    conn->curl_done = Curl_sftp_done;
-    conn->curl_connecting = Curl_ssh_multi_statemach;
-    conn->curl_doing = Curl_sftp_doing;
-    conn->curl_do_more = (Curl_do_more_func)ZERO_NULL;
-#else
-    failf(data, LIBCURL_NAME
-          " was built without LIBSSH2, scp: not supported!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
 
-  else {
-    /* We fell through all checks and thus we don't support the specified
-       protocol */
-    failf(data, "Unsupported protocol: %s", conn->protostr);
-    return CURLE_UNSUPPORTED_PROTOCOL;
-  }
-  return CURLE_OK;
+  /* Protocol not found in table. */
+  failf(data, "Protocol %s not supported or disabled in " LIBCURL_NAME,
+        conn->protostr);
+  return CURLE_UNSUPPORTED_PROTOCOL;
 }
 
 /****************************************************************
@@ -4495,8 +4305,8 @@
   }
 
   /* this calls the protocol-specific function pointer previously set */
-  if(conn->curl_done)
-    result = conn->curl_done(conn, status, premature);
+  if(conn->handler->curl_done)
+    result = conn->handler->curl_done(conn, status, premature);
   else
     result = CURLE_OK;
 
@@ -4548,9 +4358,9 @@
   conn->bits.done = FALSE; /* Curl_done() is not called yet */
   conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
 
-  if(conn->curl_do) {
+  if(conn->handler->curl_do) {
     /* generic protocol-specific function pointer set in curl_connect() */
-    result = conn->curl_do(conn, done);
+    result = conn->handler->curl_do(conn, done);
 
     /* This was formerly done in transfer.c, but we better do it here */
 
@@ -4599,7 +4409,7 @@
           }
 
           /* ... finally back to actually retry the DO phase */
-          result = conn->curl_do(conn, done);
+          result = conn->handler->curl_do(conn, done);
         }
       }
     }
@@ -4611,8 +4421,8 @@
 {
   CURLcode result=CURLE_OK;
 
-  if(conn->curl_do_more)
-    result = conn->curl_do_more(conn);
+  if(conn->handler->curl_do_more)
+    result = conn->handler->curl_do_more(conn);
 
   return result;
 }
Index: lib/urldata.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/urldata.h,v
retrieving revision 1.350
diff -u -r1.350 urldata.h
--- lib/urldata.h	4 Oct 2007 10:01:41 -0000	1.350
+++ lib/urldata.h	10 Oct 2007 18:04:22 -0000
@@ -810,6 +810,59 @@
 };
 
 /*
+ * Specific protocol handler.
+ */
+
+struct Curl_handler {
+  char * scheme;        /* URL scheme name. */
+
+  /* Complement to setup_connection_internals(). */
+  CURLcode (*curl_setup_connection)(struct connectdata *);
+
+  /* These two functions MUST be set to be protocol dependent */
+  CURLcode (*curl_do)(struct connectdata *, bool *done);
+  Curl_done_func curl_done;
+
+  /* If the curl_do() function is better made in two halves, this
+   * curl_do_more() function will be called afterwards, if set. For example
+   * for doing the FTP stuff after the PASV/PORT command.
+   */
+  Curl_do_more_func curl_do_more;
+
+  /* This function *MAY* be set to a protocol-dependent function that is run
+   * after the connect() and everything is done, as a step in the connection.
+   * The 'done' pointer points to a bool that should be set to TRUE if the
+   * function completes before return. If it doesn't complete, the caller
+   * should call the curl_connecting() function until it is.
+   */
+  CURLcode (*curl_connect)(struct connectdata *, bool *done);
+
+  /* See above. Currently only used for FTP. */
+  CURLcode (*curl_connecting)(struct connectdata *, bool *done);
+  CURLcode (*curl_doing)(struct connectdata *, bool *done);
+
+  /* Called from the multi interface during the PROTOCONNECT phase, and it
+     should then return a proper fd set */
+  int (*curl_proto_getsock)(struct connectdata *conn,
+                            curl_socket_t *socks,
+                            int numsocks);
+
+  /* Called from the multi interface during the DOING phase, and it should
+     then return a proper fd set */
+  int (*curl_doing_getsock)(struct connectdata *conn,
+                            curl_socket_t *socks,
+                            int numsocks);
+
+  /* This function *MAY* be set to a protocol-dependent function that is run
+   * by the curl_disconnect(), as a step in the disconnection.
+   */
+  CURLcode (*curl_disconnect)(struct connectdata *);
+
+  long defport;       /* Default port. */
+  long protocol; /* PROT_* flags concerning the protocol set */
+};
+
+/*
  * The connectdata struct contains all fields and variables that should be
  * unique for an entire connection.
  */
@@ -894,50 +947,7 @@
 
   struct ConnectBits bits;    /* various state-flags for this connection */
 
-  /* These two functions MUST be set by the curl_connect() function to be
-     be protocol dependent */
-  CURLcode (*curl_do)(struct connectdata *, bool *done);
-  Curl_done_func curl_done;
-
-  /* If the curl_do() function is better made in two halves, this
-   * curl_do_more() function will be called afterwards, if set. For example
-   * for doing the FTP stuff after the PASV/PORT command.
-   */
-  Curl_do_more_func curl_do_more;
-
-  /* This function *MAY* be set to a protocol-dependent function that is run
-   * after the connect() and everything is done, as a step in the connection.
-   * The 'done' pointer points to a bool that should be set to TRUE if the
-   * function completes before return. If it doesn't complete, the caller
-   * should call the curl_connecting() function until it is.
-   */
-  CURLcode (*curl_connect)(struct connectdata *, bool *done);
-
-  /* See above. Currently only used for FTP. */
-  CURLcode (*curl_connecting)(struct connectdata *, bool *done);
-  CURLcode (*curl_doing)(struct connectdata *, bool *done);
-
-  /* Called from the multi interface during the PROTOCONNECT phase, and it
-     should then return a proper fd set */
-  int (*curl_proto_getsock)(struct connectdata *conn,
-                            curl_socket_t *socks,
-                            int numsocks);
-
-  /* Called from the multi interface during the DOING phase, and it should
-     then return a proper fd set */
-  int (*curl_doing_getsock)(struct connectdata *conn,
-                            curl_socket_t *socks,
-                            int numsocks);
-
-  /* This function *MAY* be set to a protocol-dependent function that is run
-   * by the curl_disconnect(), as a step in the disconnection.
-   */
-  CURLcode (*curl_disconnect)(struct connectdata *);
-
-  /* This function *MAY* be set to a protocol-dependent function that is run
-   * in the curl_close() function if protocol-specific cleanups are required.
-   */
-  CURLcode (*curl_close)(struct connectdata *);
+  struct Curl_handler * handler;    /* This connection's protocol handler. */
 
   /**** curl_get() phase fields */
 
