📄 ftp.c
字号:
/****************************************************************************** libprozilla - a download accelerator library Copyright (C) 2001 Kalum Somaratna This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA******************************************************************************//* FTP support. *//* $Id: ftp.c,v 1.43 2001/09/23 01:39:15 kalum Exp $ */#include "common.h"#include "prozilla.h"#include "connect.h"#include "misc.h"#include "url.h"#include "netrc.h"#include "debug.h"#include "ftpparse.h"#include "ftp.h"/* #define UNIMPLEMENTED_CMD(a) ((a == 500) || (a == 502) || (a == 504)) */#define BUFFER_SIZE 2048/****************************************************************************** Return the numeric response of the FTP server by reading the first three characters in the buffer.******************************************************************************/static int ftp_get_return(const char *ftp_buffer){ char code[4]; strncpy(code, ftp_buffer, 3); code[3] = '\0'; return atoi(code);}/****************************************************************************** ...******************************************************************************/static uerr_t ftp_get_reply(connection_t * connection){ int cont = 0; int code; response_line *srl; /* FIXME Make the line variable dynamically allocated. */ /* Allocate the space in the buffer for the request. */ char szBuffer[BUFFER_SIZE]; char *strtok_saveptr = (char *) alloca(FTP_BUFFER_SIZE); memset(szBuffer, 0, FTP_BUFFER_SIZE); if (ftp_get_line(connection, szBuffer) != FTPOK) return FTPERR; if (!isdigit(*szBuffer)) return FTPERR; if (*szBuffer == '\0') return FTPERR; code = ftp_get_return(szBuffer); if (szBuffer[3] == '-') cont = 1; else cont = 0; (void) strtok_r(szBuffer, "\r\n", &strtok_saveptr); srl = connection->serv_ret_lines = kmalloc(sizeof(response_line)); srl->line = kstrdup(szBuffer); srl->next = 0; /* Add the first line to the struct. */ while (cont) { if (ftp_get_line(connection, szBuffer) != FTPOK) return FTPERR; /* Server closed the connection. */ if (*szBuffer == '\0') return FTPERR; if ((ftp_get_return(szBuffer) == code) && (szBuffer[3] == ' ')) cont = 0; (void) strtok_r(szBuffer, "\r\n", &strtok_saveptr); proz_debug(_("Message = %s"), szBuffer); srl->next = kmalloc(sizeof(response_line)); srl = srl->next; srl->line = kstrdup(szBuffer); srl->next = 0; } return FTPOK;}/****************************************************************************** ...******************************************************************************/int ftp_check_msg(connection_t * connection, int len){ int ret; if ((ret = krecv(connection->ctrl_sock, connection->szBuffer, len, MSG_PEEK, &connection->ctrl_timeout)) == -1) { proz_debug(_("Error checking for FTP data: %s"), strerror(errno)); return ret; } return ret;}/****************************************************************************** ...******************************************************************************/int ftp_read_msg(connection_t * connection, int len){ int ret; if ((ret = krecv(connection->ctrl_sock, connection->szBuffer, len, 0, &connection->ctrl_timeout)) == -1) { proz_debug(_("Error receiving FTP data: %s"), strerror(errno)); return ret; } return ret;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_send_msg(connection_t * connection, const char *format, ...){ longstring command; va_list args; va_start(args, format);#ifdef HAVE_VSNPRINTF vsnprintf(command, sizeof(command) - 1, format, args); command[sizeof(command) - 1] = '\0';#else vsprintf(command, format, args);#endif va_end(args); proz_debug(_("Sending: %s"), command); if ((ksend(connection->ctrl_sock, command, strlen(command), 0, &connection->ctrl_timeout)) == -1) { proz_debug(_("Error sending FTP data: %s"), strerror(errno)); return WRITEERR; } return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_get_line(connection_t * connection, char *line){ int iLen, iBuffLen = 0, ret = 0; char *szptr = line, ch; connection->szBuffer = &ch; while ((iBuffLen < BUFFER_SIZE) && ((ret = ftp_check_msg(connection, 1)) > 0)) { /* Now get the full string. */ iLen = ftp_read_msg(connection, 1); if (iLen != 1) return FTPERR; iBuffLen += iLen; *szptr = ch; szptr += iLen; if (ch == '\n') break; /* We have a line -> return. */ } /* Check for error returned in ftp_check_msg(). */ if (ret == -1) return FTPERR; /* FIXME Is this correct? Debug! */ *(szptr + 1) = '\0'; proz_debug(_("Received: %s"), line); return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_ascii(connection_t * connection){ uerr_t err; err = ftp_send_msg(connection, "TYPE A\r\n"); if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] != '2') return FTPUNKNOWNTYPE; return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_binary(connection_t * connection){ uerr_t err; err = ftp_send_msg(connection, "TYPE I\r\n"); if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] != '2') return FTPUNKNOWNTYPE; return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_port(connection_t * connection, const char *command){ uerr_t err; err = ftp_send_msg(connection, command); if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] != '2') return FTPPORTERR; return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_list(connection_t * connection, const char *file){ uerr_t err; err = ftp_send_msg(connection, "LIST %s\r\n", file); if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] == '5') return FTPNSFOD; if (connection->serv_ret_lines->line[0] != '1') return FTPERR; return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_retr(connection_t * connection, const char *file){ uerr_t err; err = ftp_send_msg(connection, "RETR %s\r\n", file); if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] == '5') return FTPNSFOD; if (connection->serv_ret_lines->line[0] != '1') return FTPERR; return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_pasv(connection_t * connection, unsigned char *addr){ uerr_t err; unsigned char *p; int i; err = ftp_send_msg(connection, "PASV\r\n"); if (err != FTPOK) return err; err = ftp_get_reply(connection); proz_debug(_("FTP PASV Header = %s"), connection->serv_ret_lines->line); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] != '2') return FTPNOPASV; /* Parse it. */ p = (unsigned char *) connection->serv_ret_lines->line; for (p += 4; *p && !isdigit(*p); p++); if (!*p) return FTPINVPASV; for (i = 0; i < 6; i++) { addr[i] = 0; for (; isdigit(*p); p++) addr[i] = (*p - '0') + 10 * addr[i]; if (*p == ',') p++; else if (i < 5) { return FTPINVPASV; } } return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_rest(connection_t * connection, long bytes){ uerr_t err; err = ftp_send_msg(connection, "REST %ld\r\n", bytes); if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] != '3') return FTPRESTFAIL; return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_cwd(connection_t * connection, const char *dir){ uerr_t err; err = ftp_send_msg(connection, "CWD %s\r\n", dir); if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] == '5') { /* Is it due to the file being not found? */ if (strstr(connection->serv_ret_lines->line, "o such file") || strstr(connection->serv_ret_lines->line, "o Such File") || strstr(connection->serv_ret_lines->line, "ot found") || strstr(connection->serv_ret_lines->line, "ot Found")) return FTPNSFOD; } if (connection->serv_ret_lines->line[0] != '2') return FTPCWDFAIL; return FTPOK;}/****************************************************************************** Returns the current working directory in dir.******************************************************************************/uerr_t ftp_pwd(connection_t * connection, const char *dir){ uerr_t err; char *r, *l; char szBuffer[FTP_BUFFER_SIZE]; err = ftp_send_msg(connection, "PWD\r\n"); if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] == '5') return FTPPWDERR; if (connection->serv_ret_lines->line[0] != '2') return FTPPWDFAIL; if ((r = strrchr(connection->serv_ret_lines->line, '"')) != NULL) { l = strchr(connection->serv_ret_lines->line, '"'); if ((l != NULL) && (l != r)) { *r = '\0'; ++l; strcpy(dir, l); *r = '"'; } } else { if ((r = strchr(connection->serv_ret_lines->line, ' ')) != NULL) { *r = '\0'; strcpy(dir, szBuffer); *r = ' '; } } return FTPOK;}/****************************************************************************** Returns the size of the file in size, on error size will be -1.******************************************************************************/uerr_t ftp_size(connection_t * connection, const char *file, long *size){ uerr_t err; *size = -1; err = ftp_send_msg(connection, "SIZE %s\r\n", file); if (err != FTPOK) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; /* Now lets figure out what happened. */ if (connection->serv_ret_lines->line[0] == '2') { sscanf(connection->serv_ret_lines->line + 3, "%ld", size); return FTPOK; } else if (connection->serv_ret_lines->line[0] == '5') /* An error occured. */ { /* Is it due to the file being not found? */ if (strstr(connection->serv_ret_lines->line, "o such file") || strstr(connection->serv_ret_lines->line, "o Such File") || strstr(connection->serv_ret_lines->line, "ot found") || strstr(connection->serv_ret_lines->line, "ot Found")) return FTPNSFOD; } return FTPSIZEFAIL;}/****************************************************************************** Connect to the given FTP server.******************************************************************************/uerr_t ftp_connect_to_server(connection_t * connection, const char *name, int port){ uerr_t err; err = connect_to_server(&(connection->ctrl_sock), name, port, &connection->conn_timeout); if (err != NOCONERROR) return err; err = ftp_get_reply(connection); if (err != FTPOK) return err; if (connection->serv_ret_lines->line[0] != '2') return FTPCONREFUSED; return FTPOK;}/****************************************************************************** This function will call bind() to return a bound socket then the FTP server will be connected with a port request and asked to connect.******************************************************************************/uerr_t ftp_get_listen_socket(connection_t * connection, int *listen_sock){ /* Get a fixed value. */ char command[MAX_MSG_SIZE]; int sockfd; socklen_t len; struct sockaddr_in TempAddr; char *port, *ipaddr; struct sockaddr_in serv_addr; uerr_t err; if (bind_socket(&sockfd) != BINDOK) return LISTENERR; len = sizeof(serv_addr); if (getsockname(sockfd, (struct sockaddr *) &serv_addr, &len) < 0) { perror("getsockname"); close(sockfd); return CONPORTERR; } /* Get hosts info. */ len = sizeof(TempAddr); if (getsockname(connection->ctrl_sock, (struct sockaddr *) &TempAddr, &len) < 0) { perror("getsockname"); close(sockfd); return CONPORTERR; } ipaddr = (char *) &TempAddr.sin_addr; port = (char *) &serv_addr.sin_port;#define UC(b) (((int)b)&0xff) sprintf(command, "PORT %d,%d,%d,%d,%d,%d\r\n", UC(ipaddr[0]), UC(ipaddr[1]), UC(ipaddr[2]), UC(ipaddr[3]), UC(port[0]), UC(port[1])); err = ftp_port(connection, command); if (err != FTPOK) return err; *listen_sock = sockfd; return FTPOK;}/****************************************************************************** ...******************************************************************************/uerr_t ftp_login(connection_t * connection, const char *username, const char *passwd){ uerr_t err = FTPERR; int ret_code = 220; boolean logged_in = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -