// FTP Client for Google Go language. // Author: smallfish package ftp import ( "fmt" "os" "net" "strconv" "strings" ) type FTP struct { host string port int user string passwd string pasv int cmd string Code int Message string Debug bool stream []byte conn net.Conn Error os.Error } func (ftp *FTP) debugInfo(s string) { if ftp.Debug { fmt.Println(s) } } func (ftp *FTP) Connect(host string, port int) { addr := fmt.Sprintf("%s:%d", host, port) ftp.conn, ftp.Error = net.Dial("tcp", addr) ftp.Response() ftp.host = host ftp.port = port } func (ftp *FTP) Login(user, passwd string) { ftp.Request("USER " + user) ftp.Request("PASS " + passwd) ftp.user = user ftp.passwd = passwd } func (ftp *FTP) Response() (code int, message string) { ret := make([]byte, 1024) n, _ := ftp.conn.Read(ret) msg := string(ret[:n]) code, _ = strconv.Atoi(msg[:3]) message = msg[4 : len(msg)-2] ftp.debugInfo("<*cmd*> " + ftp.cmd) ftp.debugInfo(fmt.Sprintf("<*code*> %d", code)) ftp.debugInfo("<*message*> " + message) return } func (ftp *FTP) Request(cmd string) { ftp.conn.Write([]byte(cmd + "\r\n")) ftp.cmd = cmd ftp.Code, ftp.Message = ftp.Response() if cmd == "PASV" { start, end := strings.Index(ftp.Message, "("), strings.Index(ftp.Message, ")") s := strings.Split(ftp.Message[start:end], ",", -1) l1, _ := strconv.Atoi(s[len(s)-2]) l2, _ := strconv.Atoi(s[len(s)-1]) ftp.pasv = l1*256 + l2 } if (cmd != "PASV") && (ftp.pasv > 0) { ftp.Message = newRequest(ftp.host, ftp.pasv, ftp.stream) ftp.debugInfo("<*response*> " + ftp.Message) ftp.pasv = 0 ftp.stream = nil ftp.Code, _ = ftp.Response() } } func (ftp *FTP) Pasv() { ftp.Request("PASV") } func (ftp *FTP) Pwd() { ftp.Request("PWD") } func (ftp *FTP) Cwd(path string) { ftp.Request("CWD " + path) } func (ftp *FTP) Mkd(path string) { ftp.Request("MKD " + path) } func (ftp *FTP) Size(path string) (size int) { ftp.Request("SIZE " + path) size, _ = strconv.Atoi(ftp.Message) return } func (ftp *FTP) List() { ftp.Pasv() ftp.Request("LIST") } func (ftp *FTP) Stor(file string, data []byte) { ftp.Pasv() if data != nil { ftp.stream = data } ftp.Request("STOR " + file) } func (ftp *FTP) Quit() { ftp.Request("QUIT") ftp.conn.Close() } // new connect to FTP pasv port, return data func newRequest(host string, port int, b []byte) string { conn, _ := net.Dial("tcp", fmt.Sprintf("%s:%d", host, port)) defer conn.Close() if b != nil { conn.Write(b) return "OK" } ret := make([]byte, 4096) n, _ := conn.Read(ret) return string(ret[:n]) } //go/8663