Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Written by kenkeiras
- * This program is free software. It comes without any warranty, to
- * the extent permitted by applicable law. You can redistribute it
- * and/or modify it under the terms of the Do What The Fuck You Want
- * To Public License, Version 2, as published by Sam Hocevar. See
- * http://sam.zoy.org/wtfpl/COPYING for more details.
- */
- package main
- import(
- "fmt" /* Entrada / Salida */
- "net" /* Sockets */
- "os" /* Archivos, errores ... */
- "strings" /* Manejo de strings */
- "strconv" /* Conversiones de strings */
- )
- const BUFF_LEN = 1024
- /* Lee una linea de un socket */
- func readline (sock *net.TCPConn) (s string){
- s = ""
- readData := make([]byte, 1) /* Un buffer de un byte */
- for {
- _, e := sock.Read(readData) /* Se lee un byte */
- /* Si algo falla... */
- if (e != nil){
- fmt.Fprintf(os.Stderr, "Error: %v\n", e)
- os.Exit(2)
- }
- /* Si no se acabo una línea, añadir el byte */
- if (readData[0] != '\n'){
- s = s + string(readData)
- } else {
- /* Sino, salir */
- break
- }
- }
- /* Se devuelve el string */
- return
- }
- /* Lee el banner del Servidor y devuelve el primer comando */
- func show_banner(sock *net.TCPConn) string{
- line := ""
- for{
- line = readline(sock) /* Se lee una línea de socket */
- if (line[ : 3 ] == "220"){ /* Si no dice nada importante */
- fmt.Println(line) /* Se muestra y se sigue esperando */
- } else { /* Sino se sale */
- break
- }
- }
- return line /* Es necesario devolver la última línea, porque
- no se sabe cuanto va a durar la "charla" */
- }
- func getaddr(line string) *net.TCPAddr{
- /* Se elimina el texto que no importa */
- base := line [ strings.Index(line, "(") + 1 :
- strings.Index(line, ")")]
- /* Se divide el texto con las ',' */
- s := strings.Split(base, ",", 10)
- /* Se ensambla la IP */
- ip := s[0] + "." + s[1] + "." + s[2] + "." + s[3]
- /* Y los puertos */
- p1, _ := strconv.Atoi(s[4])
- p2, _ := strconv.Atoi(s[5])
- port := strconv.Itoa((p1 * 256) + p2)
- /* Por último se crea la variable de dirección */
- addr, e := net.ResolveTCPAddr(ip + ":" + string(port) )
- if (e != nil){
- fmt.Fprintf(os.Stderr, "Error: %v\n", e)
- os.Exit(1)
- }
- /* Y se devuelve esa variable */
- return addr
- }
- /* Se pide una conexión en pasivo */
- func get_passive(sock *net.TCPConn){
- sock.Write([]byte("PASV\r\n"))
- }
- /* Se setea la conexíon a binario */
- func set_binary(sock *net.TCPConn){
- sock.Write([]byte("TYPE I\r\n"))
- }
- /* Descarga el archivo */
- func download_file(sock *net.TCPConn,
- file string ,
- addr *net.TCPAddr,
- quit chan int){
- /* Obtiene el nombre del archivo */
- fname := file[ strings.LastIndex(file, "/") + 1 : ]
- /* Lo pide al servidor */
- sock.Write([]byte("RETR " + file + "\r\n"))
- /* Se conecta a el */
- nsock, e := net.DialTCP("tcp", nil, addr)
- if (e != nil){
- fmt.Fprintf(os.Stderr, "Error conectando: %v\n", e)
- os.Exit(1)
- }
- /* Crea el archivo nuevo */
- f, e := os.Open(fname, os.O_WRONLY| os.O_RDONLY | os.O_CREAT,
- 0666)
- if (e != nil){
- fmt.Fprintf(os.Stderr, "Error creando archivo: %v\n", e)
- os.Exit(1)
- }
- /* Y lo descarga */
- buff := make([]byte, BUFF_LEN)
- fmt.Print("Descargando... ")
- for {
- /* Lee unos cuantos bytes */
- len, e := nsock.Read(buff)
- /* Si se acabó el archivo */
- if (e == os.EOF){
- break
- }
- if (e != nil){
- fmt.Fprintf(os.Stderr, "Error: %v\n", e)
- break
- }
- if (len < 1){
- break
- }
- f.Write(buff[ : len ])
- }
- fmt.Println("completado!")
- /* Solo queda cerrar el archivo y el socket de la descarga */
- f.Close()
- nsock.Close()
- /* Y avisar del final del subproceso */
- quit <- 1
- }
- func main(){
- user := "anonymous" /* Usuario */
- passwd := "" /* Contraseña */
- filepath := "" /* Archivo a descargar */
- host := "localhost" /* Servidor */
- port := "21" /* Puerto */
- quit := make(chan int) /* Canal para avisar de fin de subproceso */
- /* Si no se especifico el archivo*/
- if (len(os.Args[:]) != 2){
- fmt.Println("Uso:", os.Args[0],
- "[<usuario>[:<contraseña>]@]<host>[:<puerto>]/archivo")
- os.Exit(0)
- }
- /* Se interpreta el argumento */
- comp := strings.Split(os.Args[1], "@", 2)
- uri := ""
- if (len(comp) == 2){ /* Si se especifica user:pass */
- up := strings.Split(comp[0], ":", 2)
- user = up[0]
- if (len(up) > 1){
- passwd = up[1]
- }
- uri = comp[1]
- } else {
- uri = comp[0]
- }
- comp = strings.Split(uri, "/", 2)
- if (len(comp) == 2){
- hp := strings.Split(comp[0], ":", 3)
- host = hp[0]
- if (len(hp) > 1){
- port = hp[1]
- }
- filepath = comp[1]
- } else {
- fmt.Fprintf(os.Stderr, "No se ha especificado el archivo\n")
- os.Exit(4)
- }
- /* Se resuelve la dirección */
- addr, e := net.ResolveTCPAddr(host + ":" + port)
- if (e != nil){
- fmt.Fprintf(os.Stderr, "Error: %v\n", e)
- os.Exit(1)
- }
- fmt.Printf("Conectando a %s... ", addr)
- /* Se establece la conexión */
- sock, e := net.DialTCP("tcp", nil, addr)
- if (e != nil){
- fmt.Fprintf(os.Stderr, "Error conectando: %v\n", e)
- os.Exit(1)
- }
- fmt.Println("Hecho")
- /* Envía el user y el pass */
- sock.Write([]byte("USER " + user + "\r\n"))
- sock.Write([]byte("PASS " + passwd + "\r\n"))
- /* Muestra el banner */
- line := show_banner(sock)
- for{
- /* ¿EOF? */
- if (line == ""){
- break
- }
- /* Login correcto, se pasa a binario y se pide
- un canal pasivo */
- if (line[ 0 : 3 ] == "230"){
- set_binary(sock)
- get_passive(sock)
- /* Cuando hay un canal pasivo abierto, se obtiene su
- dirección y se descarga el archivo */
- } else if (line [ : 3 ] == "227"){
- naddr := getaddr(line)
- go download_file(sock, filepath, naddr, quit)
- /* Error al descargar :( */
- } else if (line [ : 3] == "550") {
- fmt.Fprintf(os.Stderr, "Error al descargar el archivo\n")
- os.Exit(5)
- /* Cerrando conexión */
- } else if (line [ : 3] == "226") {
- break
- }
- /* Se muestra lo que dice el servidor */
- fmt.Println(line)
- /* Y se obtiene la próxima línea */
- line = readline(sock)
- }
- /* Se espera por el subproceso */
- <-quit
- /* Se cierra el socket */
- sock.Close()
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement