Browse Source

Added feature discovery as per RFC 2389.

Julien Laffaye 12 years ago
parent
commit
f23c3ddfab
1 changed files with 52 additions and 4 deletions
  1. 52 4
      ftp.go

+ 52 - 4
ftp.go

@@ -23,8 +23,9 @@ const (
 
 // ServerConn represents the connection to a remote FTP server.
 type ServerConn struct {
-	conn *textproto.Conn
-	host string
+	conn     *textproto.Conn
+	host     string
+	features map[string]string
 }
 
 // Entry describes a file and is returned by List().
@@ -34,7 +35,7 @@ type Entry struct {
 	Size uint64
 }
 
-// 
+// response represent a data-connection
 type response struct {
 	conn net.Conn
 	c    *ServerConn
@@ -51,7 +52,11 @@ func Connect(addr string) (*ServerConn, error) {
 	}
 
 	a := strings.SplitN(addr, ":", 2)
-	c := &ServerConn{conn, a[0]}
+	c := &ServerConn{
+		conn:     conn,
+		host:     a[0],
+		features: make(map[string]string),
+	}
 
 	_, _, err = c.conn.ReadCodeLine(StatusReady)
 	if err != nil {
@@ -59,6 +64,12 @@ func Connect(addr string) (*ServerConn, error) {
 		return nil, err
 	}
 
+	err = c.feat()
+	if err != nil {
+		c.Quit()
+		return nil, err
+	}
+
 	return c, nil
 }
 
@@ -86,6 +97,43 @@ func (c *ServerConn) Login(user, password string) error {
 	return nil
 }
 
+// feat issues a FEAT FTP command to list the additional commands supported by
+// the remote FTP server.
+// FEAT is described in RFC 2389
+func (c *ServerConn) feat() error {
+	code, message, err := c.cmd(-1, "FEAT")
+	if err != nil {
+		return err
+	}
+
+	if code != StatusSystem {
+		// The server does not support the FEAT command. This is not an
+		// error: we consider that they are no additional features.
+		return nil
+	}
+
+	lines := strings.Split(message, "\n")
+	for _, line := range lines {
+		if !strings.HasPrefix(line, " ") {
+			continue
+		}
+
+		line = strings.Trim(line, " ")
+		featureElements := strings.SplitN(line, " ", 2)
+
+		command := featureElements[0]
+
+		var commandDesc string
+		if len(featureElements) == 2 {
+			commandDesc = featureElements[1]
+		}
+
+		c.features[command] = commandDesc
+	}
+
+	return nil
+}
+
 // epsv issues an "EPSV" command to get a port number for a data connection.
 func (c *ServerConn) epsv() (port int, err error) {
 	_, line, err := c.cmd(StatusExtendedPassiveMode, "EPSV")