📄 ftp.c
字号:
while (1) { switch (ret_code) { case 220: /* IDEA: Lets add the proxy support here. */ if (!ftp_use_proxy(connection)) { /* No proxy just direct connection. */ err = ftp_send_msg(connection, "USER %s\r\n", username); } else { switch (connection->ftp_proxy->type) { case USERatSITE: err = ftp_send_msg(connection, "USER %s@%s:%d\r\n", username, connection->u.host, connection->u.port); break; case USERatPROXYUSERatSITE: err = ftp_send_msg(connection, "USER %s@%s@%s:%d\r\n", username, connection->ftp_proxy->username, connection->u.host, connection->u.port); break; case USERatSITE_PROXYUSER: err = ftp_send_msg(connection, "USER %s:%d@%s %s\r\n", username, connection->u.host, connection->u.port, connection->ftp_proxy->username); break; case PROXYUSERatSITE: err = ftp_send_msg(connection, "USER %s@%s:%d\r\n", connection->ftp_proxy->username, connection->u.host, connection->u.port); break; default: /* Something else, just send PROXY USER. */ err = ftp_send_msg(connection, "USER %s\r\n", connection->ftp_proxy->username); break; } } if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; break; case 230: /* Fallthrough. */ case 231: /* Fallthrough. */ case 202: logged_in = TRUE; if (!ftp_use_proxy(connection)) return FTPOK; /* Logged in succesfully. */ switch (connection->ftp_proxy->type) { case LOGINthenUSERatSITE: err = ftp_send_msg(connection, "USER %s@%s:%d\r\n", username, connection->u.host, connection->u.port); break; case OPENSITE: err = ftp_send_msg(connection, "OPEN %s:%d\r\n", connection->u.host, connection->u.port); break; case SITESITE: err = ftp_send_msg(connection, "SITE %s:%d\r\n", connection->u.host, connection->u.port); break; case PROXYUSERatSITE: err = ftp_send_msg(connection, "USER %s\r\n", username); break; default: /* TODO What is the default here? */ return FTPOK; break; } if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; break; /* Handle 421 services not available. */ case 421: return FTPSERVCLOSEDATLOGIN; break; /* User name is all right, need password. */ case 331: if (!ftp_use_proxy(connection)) { /* No proxy just direct connection. */ err = ftp_send_msg(connection, "PASS %s\r\n", passwd); } else { switch (connection->ftp_proxy->type) { case USERatSITE: err = ftp_send_msg(connection, "PASS %s\r\n", passwd); break; case USERatPROXYUSERatSITE: err = ftp_send_msg(connection, "PASS %s@%s\r\n", passwd, connection->ftp_proxy->passwd); break; case USERatSITE_PROXYUSER: err = ftp_send_msg(connection, "PASS %s\r\n", passwd); break; case PROXYUSERatSITE: err = ftp_send_msg(connection, "PASS %s\r\n", connection->ftp_proxy->passwd); break; default: /* Something else we dont know about. */ err = ftp_send_msg(connection, "PASS %s\r\n", connection->ftp_proxy->passwd); break; } } if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; break; /* 5xx series of commands indicate error. */ case 530: return FTPLOGREFUSED; break; case 501: /* Fallthrough. */ case 503: /* Fallthrough. */ case 550: return FTPERR; break; default: /* Unknown error code. */ proz_debug(_("Unknown code %d retuned during FTP login"), ret_code); return FTPERR; break; } ret_code = ftp_get_return(connection->serv_ret_lines->line); done_with_response(connection); } if (err != FTPOK) return err; return FTPOK;}/****************************************************************************** ...******************************************************************************/boolean ftp_use_proxy(connection_t * connection){ return (connection->ftp_proxy && connection->ftp_proxy->use_proxy && connection->ftp_proxy->proxy_url.url) ? TRUE : FALSE;}/****************************************************************************** Gets info about the url (connection->u) from the FTP server, and fills in info like whether the server supports resume, the file size etc.******************************************************************************/uerr_t proz_ftp_get_url_info(connection_t * connection){ uerr_t err; char *user, *passwd, *tmp; netrc_entry *netrc_ent; boolean passive_mode; longstring buffer; int size_rt; /* if we have to use a HTTP proxy call the routine which is defined in http.c and just return. */ if (ftp_use_proxy(connection) && connection->ftp_proxy->type == HTTPPROXY) { err = ftp_get_url_info_from_http_proxy(connection); return err; } init_response(connection); if (ftp_use_proxy(connection)) { connection_show_message(connection, _("Connecting to %s"), connection->ftp_proxy->proxy_url.host); /* Connect to the proxy server here. */ err = ftp_connect_to_server(connection, connection->ftp_proxy->proxy_url.host, connection->ftp_proxy->proxy_url.port); if (err != FTPOK) { connection_show_message(connection, _("Error while connecting to %s"), connection->ftp_proxy->proxy_url.host); return err; } connection_show_message(connection, _("Connected to %s"), connection->ftp_proxy->proxy_url.host); } else { connection_show_message(connection, _("Connecting to %s"), connection->u.host); err = ftp_connect_to_server(connection, connection->u.host, connection->u.port); if (err != FTPOK) { connection_show_message(connection, _("Error while connecting to %s"), connection->u.host);; return err; } connection_show_message(connection, _("Connected to %s"), connection->u.host); } done_with_response(connection); user = connection->u.user; passwd = connection->u.passwd; /* Use .netrc if asked to do so. */ if (connection->use_netrc == TRUE) { netrc_ent = search_netrc(libprozrtinfo.netrc_list, connection->u.host); if (netrc_ent != NULL) { user = netrc_ent->account; passwd = netrc_ent->password; } } user = user ? user : libprozrtinfo.ftp_default_user; passwd = passwd ? passwd : libprozrtinfo.ftp_default_passwd; if (strcmp(user, "anonymous") == 0) connection_show_message(connection, _("Logging in as user %s with password %s"), user, passwd); else { int pwd_len = strlen(passwd); char *tmp_pwd = (char *) kmalloc(pwd_len + 1); memset(tmp_pwd, 'x', pwd_len); tmp_pwd[pwd_len] = 0; connection_show_message(connection, _("Logging in as user %s with password %s"), user, tmp_pwd); kfree(tmp_pwd); } init_response(connection); err = ftp_login(connection, user, passwd); if (err != FTPOK) { close_sock(&connection->ctrl_sock); return err; } done_with_response(connection); connection_show_message(connection, _("Logged in successfully")); init_response(connection); err = ftp_binary(connection); if (err != FTPOK) { close_sock(&connection->ctrl_sock); return err; } done_with_response(connection); /* Do we need to CWD? */ if (*connection->u.dir) { init_response(connection); err = ftp_cwd(connection, connection->u.dir); if (err != FTPOK) { connection_show_message(connection, _("CWD failed to change to directory '%s'"), connection->u.dir); close_sock(&connection->ctrl_sock); return err; } else { done_with_response(connection); } } else connection_show_message(connection, _("CWD not needed")); init_response(connection); err = ftp_rest(connection, 0); if (err != FTPOK) { connection->resume_support = FALSE; connection_show_message(connection, _("REST failed")); /* NOTE: removed return err; */ } else { connection->resume_support = TRUE; connection_show_message(connection, _("REST ok")); } done_with_response(connection); /* Lets see whether the URL really is a file. */ init_response(connection); err = ftp_cwd(connection, connection->u.file); if (err == FTPOK) { /* So connection->u.file is a directory and not a file. */ connection->file_type = DIRECTORY; return FTPOK; } else { /* FIXME: The statement below is strictly not true, it could be a symlink but for the moment lets leave this as it is, later we will perform a LIST command and detect whether it is a symlink. */ connection->file_type = REGULAR_FILE; } done_with_response(connection); init_response(connection); err = ftp_size(connection, connection->u.file, &connection->main_file_size); if ((err == FTPOK) || (err == FTPNSFOD) || (err != FTPSIZEFAIL)) { close_sock(&connection->ctrl_sock); return err; } done_with_response(connection); /* The server did not support the SIZE command, so lets try to get the file size through the LIST command. */ err = ftp_setup_data_sock_1(connection, &passive_mode); if (err != FTPOK) { close_sock(&connection->ctrl_sock); return err; } init_response(connection); err = ftp_ascii(connection); if (err != FTPOK) { close_sock(&connection->ctrl_sock); return err; } done_with_response(connection); init_response(connection); err = ftp_list(connection, connection->u.file); if (err != FTPOK) { close_sock(&connection->ctrl_sock); return err; } done_with_response(connection); err = ftp_setup_data_sock_2(connection, &passive_mode); if (err != FTPOK) { close_sock(&connection->ctrl_sock); return err; } /* Now read the data to the buffer. */ /* TODO Create a buffer which dynamically resizes itself as we add data. */ if (krecv(connection->data_sock, buffer, sizeof(buffer), 0, &connection->xfer_timeout) == -1) { connection_show_message(connection, _("Error receiving FTP transfer data: %s"), strerror(errno)); return FTPERR; } proz_debug(_("String received after the LIST command = %s"), buffer); while ((tmp = strrchr(buffer, '\n')) || (tmp = strrchr(buffer, '\r'))) { *tmp = 0; }; close_sock(&connection->data_sock); close_sock(&connection->ctrl_sock); size_rt = size_returner(buffer, strlen(buffer)); if (size_rt == FTPPARSENOTEXIST) { return FTPNSFOD; } else if (size_rt == FTPPARSEFAIL) { connection_show_message(connection, _ ("Unable to parse the line the FTP server returned:please report URL to kalum@delrom.ro ")); } connection->main_file_size = size_rt; return FTPOK;}/****************************************************************************** This will be the first step in setting up a data sock, it will try PASV or PORT.******************************************************************************/uerr_t ftp_setup_data_sock_1(connection_t * connection, boolean * passive_mode){ uerr_t err; /* If enabled lets try PASV. */ if (connection->ftp_use_pasv == TRUE) { init_response(connection); err = ftp_pasv(connection, connection->pasv_addr); /* If the error is due to the server not supporting PASV then set the flag and lets try PORT. */ if ((err == FTPNOPASV) || (err == FTPINVPASV)) { proz_debug(_("Server doesn't seem to support PASV")); *passive_mode = FALSE; } else if (err == FTPOK) /* Server supports PASV. */ { char dhost[256]; unsigned short dport; sprintf(dhost, "%d.%d.%d.%d", connection->pasv_addr[0], connection->pasv_addr[1], connection->pasv_addr[2], connection->pasv_addr[3]); dport = (connection->pasv_addr[4] << 8) + connection->pasv_addr[5]; err = connect_to_server(&connection->data_sock, dhost, dport, &connection->xfer_timeout); if (err != NOCONERROR) return err; /* Everything seems to be ok. */ *passive_mode = TRUE; } else return err; done_with_response(connection); } else *passive_mode = FALSE; /* Ok... Since PASV is not to be used. */ if (*passive_mode == FALSE) { /* Obtain a listen socket. */ err = ftp_get_listen_socket(connection, &connection->listen_sock); if (err != FTPOK) return err; } return FTPOK;}/****************************************************************************** This will be the second step in setting up a data sock, if passive mode is FALSE, it will call accept_connection().******************************************************************************/uerr_t ftp_setup_data_sock_2(connection_t * connection, boolean * passive_mode){ uerr_t err; if (*passive_mode == FALSE) /* We have to accept the connection. */ { err = accept_connection(connection->listen_sock, &connection->data_sock); if (err != ACCEPTOK) return err; } return FTPOK;}/*Loops for connection->attempts */uerr_t ftp_get_url_info_loop(connection_t * connection){ pthread_mutex_lock(&connection->access_mutex); connection->running = TRUE; pthread_mutex_unlock(&connection->access_mutex); assert(connection->attempts >= 0); do { if (connection->attempts > 0 && connection->err != NEWLOCATION) { connection_show_message(connection, _("Retrying attempt %d in %d seconds"), connection->attempts, connection->retry_delay.tv_sec); delay_ms(connection->retry_delay.tv_sec * 1000); } /*Push the handler which will cleanup any sockets that are left open */ pthread_cleanup_push(cleanup_socks, (void *) connection); connection->err = proz_ftp_get_url_info(connection); /*pop the handler */ pthread_cleanup_pop(0); connection->attempts++; switch (connection->err) { case FTPOK: connection_show_message(connection, _("Successfully got info")); pthread_mutex_lock(&connection->access_mutex); connection->running = FALSE; pthread_mutex_unlock(&connection->access_mutex); return connection->err; break; case FTPNSFOD: connection_show_message(connection, _("File not found!")); pthread_mutex_lock(&connection->access_mutex); connection->running = FALSE; pthread_mutex_unlock(&connection->access_mutex); return connection->err; break; default: connection_show_message(connection, proz_strerror(connection->err)); break; } } while ((connection->attempts < connection->max_attempts) || connection->max_attempts == 0); connection_show_message(connection, _ ("I have tried %d attempt(s) and have failed, aborting"), connection->attempts); pthread_mutex_lock(&connection->access_mutex); connection->running = FALSE; pthread_mutex_unlock(&connection->access_mutex); return connection->err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -