Example #1
0
int ftp_transfer(UrlResource *rsrc, libnet_callback notify)
{
	Url 	*u		= NULL;
	FILE 	*out		= NULL;
	char 	*line		= NULL;
	int 	sock		= -1;
	int 	data_sock	= -1;
	int	passive		= 1;
	int	retval		= 0;
    int msg_code    = 0;

	u = rsrc->url;

	/* first of all, if this is proxied, just pass it off to the
	   http module, since that's how we support proxying. */

	rsrc->proxy = get_proxy("FTP_PROXY");

	if ( rsrc->proxy )
	{
		return http_transfer(rsrc, notify);
	}

	ftp_set_defaults(rsrc, u);

	sock = util_tcp_connect(u->host, u->port);
	if (sock < 0)
	{
        if (rsrc->running)
        {
		    notify(NET_MSG_DOWNLOAD_FINISH, (UINT32)-NET_ERR_CONNECT_FAILED);
        }
        //S_CLOSE(sock);
		return 0;
	}

	if ( !(line = get_line(rsrc, sock)) )
	{
        if (rsrc->running)
        {
            notify(NET_MSG_DOWNLOAD_FINISH, (UINT32)-NET_ERR_FTP_SERVER_ERROR);
        }
        S_CLOSE(sock);
		return 0;
	}

	if ( !check_numeric("220", line) )
	{
		safe_free(line);
        S_CLOSE(sock);
		LIBNET_DEBUG("bad server greeting");        
        if (rsrc->running)
        {
            notify(NET_MSG_DOWNLOAD_FINISH, (UINT32)-NET_ERR_FTP_SERVER_ERROR);
        }
		return 0;
	}
	safe_free(line);


	send_control(sock, "USER ", u->username, "\r\n", NULL);

	if ( !(line = get_line(rsrc, sock)) )
	{
        msg_code = -NET_ERR_LOGIN_FAILED;
        goto cleanup;
	}

	/* do the password dance */
	if ( !check_numeric("230", line) )
	{
		if ( !check_numeric("331", line))
		{
			safe_free(line);
			LIBNET_DEBUG("bad/unexpected response: %s", line);
            msg_code = -NET_ERR_LOGIN_FAILED;
            goto cleanup;
		}
		else
		{
			safe_free(line);

			send_control(sock, "PASS ", u->password, "\r\n", NULL);

			if ( !((line = get_line(rsrc, sock)) &&
					check_numeric("230", line)) )
			{
				safe_free(line);
				LIBNET_DEBUG("login failed");
				msg_code = -NET_ERR_LOGIN_FAILED;
                goto cleanup;
			}
			//safe_free(line);
		}
	}

    safe_free(line);

	/* set binmode */
	send_control(sock, "TYPE I\r\n", NULL);

	if ( !(line = get_line(rsrc, sock)) )
	{      
        msg_code = -NET_ERR_FTP_SERVER_ERROR;
        goto cleanup;
	}
	safe_free(line);
#if 1 // user can't change ftp path to "/" if server don't support it
	if ( u->path && (STRCMP(u->path, "/") != 0))
	{
		/* CWD using relative path */
		char *relative_path = u->path[0] == '/' ? &u->path[1] : &u->path[0];
		send_control(sock, "CWD ", relative_path, "\r\n", NULL);

		if ( !((line = get_line(rsrc, sock)) &&
				check_numeric("250", line)) )
		{
			safe_free(line);
            msg_code = -NET_ERR_OPERATION_NOT_PERMIT;
            goto cleanup;
		}
		safe_free(line);
	}
#endif
	/* finally, the good stuff */

	/* get a socket for reading. try passive first. */

	if ( ! (rsrc->options & OPT_ACTIVE) )
	{
		if ( (data_sock = get_passive_sock(rsrc, sock)) < 0 )
		{          
          msg_code = -NET_ERR_CONNECT_FAILED;
          goto cleanup;
		}
	}


	if ( data_sock < 0 )
	{
		if ( (data_sock = get_sock(rsrc, sock)) < 1 )
		{          
          msg_code = -NET_ERR_CONNECT_FAILED;
          goto cleanup;
		}
		else
			passive = 0;
	}

	if (u->file)
	{
		send_control(sock, "SIZE ", u->file, "\r\n", NULL);
		line = get_line(rsrc, sock);
		if (line && check_numeric("213", line))
		{
			rsrc->outfile_size = ATOI(line + 4);
		}
		else if (line && check_numeric("550", line))
		{
			safe_free(line);
			msg_code = -NET_ERR_FILE_NOT_FOUND;
            goto cleanup;
		}
		else
		{
			rsrc->outfile_size = 0;
		}
		if (line) FREE(line);
	}

	/* handle resume */
	if ( rsrc->outfile_offset && (rsrc->options & OPT_RESUME) )
	{
		char numstring[32]; /* ugly hack */

		sprintf(numstring, "%ld", (long int )rsrc->outfile_offset);
		send_control(sock, "REST ", numstring, "\r\n", NULL);

		if ( !((line = get_line(rsrc, sock)) &&
				check_numeric("350", line)) )
		{
			safe_free(line);
			LIBNET_DEBUG("server does not support FTP resume, try again without -r");
			msg_code = -NET_ERR_OPERATION_NOT_PERMIT;
            goto cleanup;
		}
		safe_free(line);
	}

	if (u->file)
		send_control(sock, "RETR ", u->file, "\r\n", NULL);
	else
		send_control(sock, "NLST\r\n", NULL);

	if ( !((line = get_line(rsrc, sock)) &&
			(check_numeric("150", line) || check_numeric("125", line))) )
	{
		safe_free(line);
        msg_code = -NET_ERR_OPERATION_NOT_PERMIT;
        goto cleanup;
	}

    LIBNET_DEBUG("ftp reply(RETR): %s\n", line);
	if ( !passive )
		data_sock = S_ACCEPT(data_sock, NULL, NULL);

	/*        rsrc->outfile_size = guess_file_size(line); */

	safe_free(line);

	if (rsrc->outfile)
	{
		if (get_file_size(rsrc->outfile) > 0)
			out = fopen(rsrc->outfile, "rb+");
		else
			out = fopen(rsrc->outfile, "wb");

		if ( !out )
		{
			//report(ERR, "opening %s: %s", rsrc->outfile,
			//	   strerror(errno));
            msg_code = -NET_ERR_FILE_SAVE_ERROR;
            goto cleanup;
		}
	}

	retval = dump_data(rsrc, data_sock, out, notify);

    if (rsrc->running)
    {
    	line = get_line(rsrc, sock); /* 226 Transfer complete */
        LIBNET_DEBUG("ftp(done): %s\n", line);
    	safe_free(line);
    }

cleanup:
    
	send_control(sock, "QUIT\r\n", NULL);
	line = get_line(rsrc, sock); /* 221 Goodbye */    
    LIBNET_DEBUG("ftp(QUIT): %s\n", line);
	safe_free(line);
    
	if (out)
		fclose(out);

    if (data_sock >= 0)
    {
        S_CLOSE(data_sock);
    }
    
	if (sock >= 0)
    {
        S_CLOSE(sock);
	}
	
#ifndef WIN32
	if (rsrc->outfile)
		fs_sync(rsrc->outfile);
#endif

    if (msg_code < 0 && rsrc->running)
    { 
		notify(NET_MSG_DOWNLOAD_FINISH, (UINT32)msg_code);
    }
	return retval;
}
Example #2
0
int ftp_transfer(UrlResource *rsrc)
{
    Url  *u         = NULL;
    char *line      = NULL;
    int   sock      = 0;
    int   data_sock = 0;
    int   passive   = 1;
    int   retval    = 0;
    
    u = rsrc->url;

    /*
     * first of all, if this is proxied, just pass it off to the
     * http module, since that's how we support proxying.
     */

    rsrc->proxy = get_proxy("FTP_PROXY");

    if (rsrc->proxy && (rsrc->proxy[0] != '\0')) {
        return http_transfer(rsrc);
    }

    ftp_set_defaults(rsrc, u);

    if (!(sock = tcp_connect(rsrc->op, u->host, u->port)))
        return FALSE;

    if (!(line = get_line(rsrc, sock)))
        return FALSE;

    if (!check_numeric("220", line)) {
        ui_error(rsrc->op, "bad ftp server greeting: %s", line);
        nvfree(line);
        return FALSE;
    }
    
    send_control(sock, "USER ", u->username, "\r\n", NULL);

    if (!(line = get_line(rsrc, sock))) return FALSE;
    
    /* do the password dance */
    if (!check_numeric("230", line)) {
        if (!check_numeric("331", line)) {
            ui_error(rsrc->op, "bad/unexpected response: %s", line);
            nvfree(line);
            return FALSE;
        } else {
            nvfree(line);

            send_control(sock, "PASS ", u->password, "\r\n", NULL);
                        
            if (!((line = get_line(rsrc, sock)) &&
                  check_numeric("230", line)) ) {
                nvfree(line);
                ui_error(rsrc->op, "login failed");
                return FALSE;
            }
            nvfree(line);
        }
    }
        
    /* set binmode */
    send_control(sock, "TYPE I\r\n", NULL);

    if (!(line = get_line(rsrc, sock))) return 0;
    nvfree(line);

    if (u->path) {
        send_control(sock, "CWD ", u->path, "\r\n", NULL);
        
        if (!((line = get_line(rsrc, sock)) &&
              check_numeric("250", line))) {
            nvfree(line);
            close_quit(sock);
            return 0;
        }
        nvfree(line);
    }
        
    /* finally, the good stuff */
    
    /* get a socket for reading. try passive first. */
        
    if ((data_sock = get_passive_sock(rsrc, sock)) == -1) {
        return FALSE;
    }
    
    if (!data_sock) {
        if ((data_sock = get_sock(rsrc, sock)) < 1)
            return 0;
        else
            passive = 0;
    }

    if (u->file) {
        send_control(sock, "SIZE ", u->file, "\r\n", NULL);
        line = get_line(rsrc, sock);
        if (line && check_numeric("213", line)) {
            rsrc->outfile_size = atoi(line + 3);
        } else {
            rsrc->outfile_size = 0;
        }
    }
    
    if (u->file)
        send_control(sock, "RETR ", u->file, "\r\n", NULL);
    else
        send_control(sock, "NLST\r\n", NULL);

    if (!((line = get_line(rsrc, sock)) &&
          (check_numeric("150", line) || check_numeric("125", line)))) {
        nvfree(line);
        close_quit(sock);
        return 0;
    }

    if (!passive) 
        data_sock = accept(data_sock, NULL, NULL);

    nvfree(line);

    retval = dump_data(rsrc, data_sock);
    
    line = get_line(rsrc, sock); /* 226 Transfer complete */
    nvfree(line);
    send_control(sock, "QUIT\r\n", NULL);
    line = get_line(rsrc, sock); /* 221 Goodbye */
    nvfree(line);
    
    close(sock);
    close(data_sock);
    return retval;

} /* ftp_transfer() */