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; }
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() */