diff options
Diffstat (limited to 'ext/ftp/ftp.c')
| -rw-r--r-- | ext/ftp/ftp.c | 1093 |
1 files changed, 559 insertions, 534 deletions
diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index f955ddab3f..502022ad24 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -29,674 +29,699 @@ */ #include "php.h" -#include "php_globals.h" -#include <ftplib.h> +#if HAVE_FTP + +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> #include "ftp.h" -#if HAVE_FTP +/* reads an ftp response, returns true on success, false on error */ +static int ftp_getresp(ftpbuf_t *ftp); -static int le_netbuf; - - -function_entry php3_ftp_functions[] = { - PHP_FE(ftp_connect, NULL) - PHP_FE(ftp_login, NULL) - PHP_FE(ftp_pwd, NULL) - PHP_FE(ftp_cdup, NULL) - PHP_FE(ftp_chdir, NULL) - PHP_FE(ftp_mkdir, NULL) - PHP_FE(ftp_rmdir, NULL) - PHP_FE(ftp_nlist, NULL) - PHP_FE(ftp_listraw, NULL) - PHP_FE(ftp_systype, NULL) - PHP_FE(ftp_get, NULL) - PHP_FE(ftp_put, NULL) - PHP_FE(ftp_quit, NULL) - {NULL, NULL, NULL} -}; - -php3_module_entry php3_ftp_module_entry = { - "FTP Functions", - php3_ftp_functions, - PHP_MINIT(ftp), - NULL, - NULL, - NULL, - NULL, - STANDARD_MODULE_PROPERTIES -}; - -static void ftp_destructor_netbuf(netbuf *net) -{ - if (net) { - FtpQuit(net); - } -} +/* sets the ftp transfer type */ +static int ftp_type(ftpbuf_t *ftp, ftptype_t type); -PHP_MINIT_FUNCTION(ftp) -{ - le_netbuf = register_list_destructors(ftp_destructor_netbuf, NULL); - REGISTER_MAIN_LONG_CONSTANT("FTP_ASCII", FTPLIB_ASCII, - CONST_PERSISTENT | CONST_CS); - REGISTER_MAIN_LONG_CONSTANT("FTP_BINARY", FTPLIB_BINARY, - CONST_PERSISTENT | CONST_CS); - return SUCCESS; -} +/* opens up a port for ftp transfer */ +static databuf_t* ftp_port(ftpbuf_t *ftp); + +/* accepts the data connection, returns updated data buffer */ +static databuf_t* data_accept(databuf_t *data); + +/* closes the data connection, returns NULL */ +static databuf_t* data_close(databuf_t *data); -/* {{{ proto int ftp_connect(string host) - Open a FTP stream */ -PHP_FUNCTION(ftp_connect) +/* generic file lister */ +static char** ftp_genlist(ftpbuf_t *ftp, + const char *cmd, const char *path); + + +ftpbuf_t* +ftp_open(const char *host, short port) { - pval *arg1; - int id; - netbuf *net; - - /* arg1 - hostname - */ - if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) { - WRONG_PARAM_COUNT; + int fd = -1; + ftpbuf_t *ftp; + struct sockaddr_in addr; + struct hostent *he; + int size; + + + /* set up the address */ + if ((he = gethostbyname(host)) == NULL) { + herror("gethostbyname"); + return NULL; } - convert_to_string(arg1); + memset(&addr, 0, sizeof(addr)); + memcpy(&addr.sin_addr, he->h_addr, he->h_length); + addr.sin_port = port ? port : htons(21); + + + /* alloc the ftp structure */ + ftp = calloc(1, sizeof(*ftp)); + if (ftp == NULL) { + perror("calloc"); + return NULL; + } /* connect */ - if (!FtpConnect(arg1->value.str.val, &net)) { - php_error(E_WARNING, "FtpConnect: %s", FtpLastResponse(net)); - RETURN_FALSE; + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + perror("socket"); + goto bail; } - id = php3_list_insert(net, le_netbuf); - RETURN_LONG(id); -} -/* }}} */ + if (connect(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) { + perror("connect"); + goto bail; + } -/* {{{ proto int ftp_login(int stream, string username, string password) - Logs into the FTP server. */ -PHP_FUNCTION(ftp_login) -{ - pval *arg1, *arg2, *arg3; - int id, type; - netbuf *net; - - /* arg1 - netbuf - * arg2 - username - * arg3 - password - */ - if ( ARG_COUNT(ht) != 3 || - getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE) - { - WRONG_PARAM_COUNT; + size = sizeof(addr); + if (getsockname(fd, (struct sockaddr*) &addr, &size) == -1) { + perror("getsockname"); + goto bail; } - convert_to_long(arg1); - convert_to_string(arg2); - convert_to_string(arg3); + ftp->localaddr = addr.sin_addr; - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; + if ((ftp->fp = fdopen(fd, "r+")) == NULL) { + perror("fdopen"); + goto bail; } - /* log in */ - if (!FtpLogin(arg2->value.str.val, arg3->value.str.val, net)) { - php_error(E_WARNING, "FtpLogin: %s", FtpLastResponse(net)); - RETURN_FALSE; + if (!ftp_getresp(ftp) || ftp->resp != 220) { + goto bail; } - RETURN_TRUE; + return ftp; + +bail: + if (ftp->fp) + fclose(ftp->fp); + else if (fd != -1) + close(fd); + free(ftp); + return NULL; } -/* }}} */ -/* {{{ proto string ftp_pwd(int stream) - Returns the present working directory. */ -PHP_FUNCTION(ftp_pwd) + +ftpbuf_t* +ftp_close(ftpbuf_t *ftp) { - pval *arg1; - int id, type; - netbuf *net; - char buf[512]; - - /* arg1 - netbuf - */ - if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) { - WRONG_PARAM_COUNT; - } + if (ftp == NULL) + return NULL; + if (ftp->fp) + fclose(ftp->fp); + ftp_gc(ftp); + free(ftp); + return NULL; +} - convert_to_long(arg1); - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; - } +void +ftp_gc(ftpbuf_t *ftp) +{ + if (ftp == NULL) + return; - if (!FtpPwd(buf, sizeof(buf), net)) { - php_error(E_WARNING, "FtpPwd: %s", FtpLastResponse(net)); - RETURN_FALSE; - } + free(ftp->pwd); + ftp->pwd = NULL; + free(ftp->syst); + ftp->syst = NULL; +} - RETURN_STRING(buf, 1); + +int +ftp_quit(ftpbuf_t *ftp) +{ + if (ftp == NULL) + return 0; + + fprintf(ftp->fp, "QUIT\r\n"); + if (!ftp_getresp(ftp) || ftp->resp != 221) + return 0; + + free(ftp->pwd); + ftp->pwd = NULL; + + return 1; } -/* }}} */ -/* {{{ proto int ftp_cdup(int stream) - Changes to the parent directory */ -PHP_FUNCTION(ftp_cdup) + +int +ftp_login(ftpbuf_t *ftp, const char *user, const char *pass) { - pval *arg1; - int id, type; - netbuf *net; - - /* arg1 - netbuf - */ - if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) { - WRONG_PARAM_COUNT; - } + if (ftp == NULL) + return 0; + + fprintf(ftp->fp, "USER %s\r\n", user); + if (!ftp_getresp(ftp)) + return 0; + if (ftp->resp == 230) + return 1; + if (ftp->resp != 331) + return 0; + fprintf(ftp->fp, "PASS %s\r\n", pass); + if (!ftp_getresp(ftp)) + return 0; + return (ftp->resp == 230); +} - convert_to_long(arg1); - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; - } +int +ftp_reinit(ftpbuf_t *ftp) +{ + if (ftp == NULL) + return 0; - if (!FtpCDUp(net)) { - php_error(E_WARNING, "FtpCdup: %s", FtpLastResponse(net)); - RETURN_FALSE; - } + ftp_gc(ftp); + + fprintf(ftp->fp, "REIN\r\n"); + if (!ftp_getresp(ftp) || ftp->resp != 220) + return 0; - RETURN_TRUE; + return 1; } -/* }}} */ -/* {{{ proto int ftp_chdir(int stream, string directory) - Changes directories */ -PHP_FUNCTION(ftp_chdir) + +const char* +ftp_syst(ftpbuf_t *ftp) { - pval *arg1, *arg2; - int id, type; - netbuf *net; - - /* arg1 - netbuf - * arg2 - directory - */ - if ( ARG_COUNT(ht) != 2 || - getParameters(ht, 2, &arg1, &arg2) == FAILURE) - { - WRONG_PARAM_COUNT; - } + char *syst, *end; - convert_to_long(arg1); - convert_to_string(arg2); + if (ftp == NULL) + return NULL; - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; - } + /* default to cached value */ + if (ftp->syst) + return ftp->syst; - /* change directories */ - if (!FtpChdir(arg2->value.str.val, net)) { - php_error(E_WARNING, "FtpChdir: %s", FtpLastResponse(net)); - RETURN_FALSE; - } + fprintf(ftp->fp, "SYST\r\n"); + if (!ftp_getresp(ftp) || ftp->resp != 215) + return NULL; + + syst = ftp->inbuf; + if ((end = strchr(syst, ' '))) + *end = 0; + ftp->syst = strdup(syst); + if (end) + *end = ' '; - RETURN_TRUE; + return ftp->syst; } -/* }}} */ -/* {{{ proto int ftp_mkdir(int stream, string directory) - Creates a directory */ -PHP_FUNCTION(ftp_mkdir) + +const char* +ftp_pwd(ftpbuf_t *ftp) { - pval *arg1, *arg2; - int id, type; - netbuf *net; - - /* arg1 - netbuf - * arg2 - directory - */ - if ( ARG_COUNT(ht) != 2 || - getParameters(ht, 2, &arg1, &arg2) == FAILURE) - { - WRONG_PARAM_COUNT; - } + char *pwd, *end; - convert_to_long(arg1); - convert_to_string(arg2); + if (ftp == NULL) + return NULL; - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; - } + /* default to cached value */ + if (ftp->pwd) + return ftp->pwd; - /* change directories */ - if (!FtpMkdir(arg2->value.str.val, net)) { - php_error(E_WARNING, "FtpMkdir: %s", FtpLastResponse(net)); - RETURN_FALSE; - } + fprintf(ftp->fp, "PWD\r\n"); + if (!ftp_getresp(ftp) || ftp->resp != 257) + return NULL; + + /* copy out the pwd from response */ + if ((pwd = strchr(ftp->inbuf, '"')) == NULL) + return NULL; + end = strrchr(++pwd, '"'); + *end = 0; + ftp->pwd = strdup(pwd); + *end = '"'; - RETURN_TRUE; + return ftp->pwd; } -/* }}} */ -/* {{{ proto int ftp_rmdir(int stream, string directory) - Removes a directory */ -PHP_FUNCTION(ftp_rmdir) + +int +ftp_chdir(ftpbuf_t *ftp, const char *dir) { - pval *arg1, *arg2; - int id, type; - netbuf *net; - - /* arg1 - netbuf - * arg2 - directory - */ - if ( ARG_COUNT(ht) != 2 || - getParameters(ht, 2, &arg1, &arg2) == FAILURE) - { - WRONG_PARAM_COUNT; - } + if (ftp == NULL) + return 0; - convert_to_long(arg1); - convert_to_string(arg2); + free(ftp->pwd); + ftp->pwd = NULL; - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; - } + fprintf(ftp->fp, "CWD %s\r\n", dir); + if (!ftp_getresp(ftp) || ftp->resp != 250) + return 0; + + return 1; +} - /* change directories */ - if (!FtpRmdir(arg2->value.str.val, net)) { - php_error(E_WARNING, "FtpRmdir: %s", FtpLastResponse(net)); - RETURN_FALSE; - } - RETURN_TRUE; +int +ftp_cdup(ftpbuf_t *ftp) +{ + if (ftp == NULL) + return 0; + + free(ftp->pwd); + ftp->pwd = NULL; + + fprintf(ftp->fp, "CDUP\r\n"); + if (!ftp_getresp(ftp) || ftp->resp != 250) + return 0; + + return 1; } -/* }}} */ -/* {{{ proto array ftp_nlist(int stream, string directory) - Returns an array of filenames in the given directory */ -PHP_FUNCTION(ftp_nlist) + +char* +ftp_mkdir(ftpbuf_t *ftp, const char *dir) { - pval *arg1, *arg2; - int id, type; - netbuf *net; - FILE *outfp; - char *entry = NULL; - char *ptr; - long size; - char ch; + char *mkd, *end; + if (ftp == NULL) + return NULL; - /* arg1 - netbuf - * arg2 - directory - */ - if ( ARG_COUNT(ht) != 2 || - getParameters(ht, 2, &arg1, &arg2) == FAILURE) - { - WRONG_PARAM_COUNT; - } + fprintf(ftp->fp, "MKD %s\r\n", dir); + if (!ftp_getresp(ftp) || ftp->resp != 257) + return NULL; - convert_to_long(arg1); - convert_to_string(arg2); + /* copy out the dir from response */ + if ((mkd = strchr(ftp->inbuf, '"')) == NULL) + return NULL; + end = strrchr(++mkd, '"'); + *end = 0; + mkd = strdup(mkd); + *end = '"'; - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; - } + return mkd; +} - /* set up a temporary output file */ - if ((outfp = tmpfile()) == NULL) { - php_error(E_WARNING, "error opening tmpfile"); - RETURN_FALSE; - } - /* list to the temporary file */ - if (!FtpNlst(outfp, arg2->value.str.val, net) || ferror(outfp)) { - fclose(outfp); - RETURN_FALSE; - } +int +ftp_rmdir(ftpbuf_t *ftp, const char *dir) +{ + if (ftp == NULL) + return 0; - array_init(return_value); - rewind(outfp); + fprintf(ftp->fp, "RMD %s\r\n", dir); + if (!ftp_getresp(ftp) || ftp->resp != 250) + return 0; - /* Pluck out each file name and save to the return array. */ - do { - /* scan for end of line */ - size = 1; - while ((ch = getc(outfp)) != '\n') { - if (ch == EOF) { - size = -1; - break; - } - size++; - } + return 1; +} - if (size > 0) { - /* seek back to the start of file name and copy - * to a buffer. add the buffer to the array. - */ - fseek(outfp, -size, SEEK_CUR); - entry = emalloc(size); - ptr = entry; - while (--size) - *ptr++ = getc(outfp); - *ptr = 0; - add_next_index_string(return_value, entry, 0); - } +char** +ftp_nlist(ftpbuf_t *ftp, const char *path) +{ + return ftp_genlist(ftp, "NLST", path); +} + - /* eat the \n */ - (void) getc(outfp); - } while (size != -1); - fclose(outfp); +char** +ftp_list(ftpbuf_t *ftp, const char *path) +{ + return ftp_genlist(ftp, "LIST", path); } -/* }}} */ -/* {{{ proto array ftp_listraw(int stream, string directory) - Returns a detailed listing of a directory as an array of output lines */ -PHP_FUNCTION(ftp_listraw) + +int +ftp_getresp(ftpbuf_t *ftp) { - pval *arg1, *arg2; - int id, type; - netbuf *net; - FILE *outfp; - char *entry = NULL; + char tag[4]; + int ch; + char *buf; char *ptr; - long size; - char ch; + if (ftp == NULL) + return 0; + buf = ftp->inbuf; + ftp->resp = 0; - /* arg1 - netbuf - * arg2 - directory - */ - if ( ARG_COUNT(ht) != 2 || - getParameters(ht, 2, &arg1, &arg2) == FAILURE) - { - WRONG_PARAM_COUNT; - } + do { + if (!fread(tag, 4, 1, ftp->fp)) + return 0; + + if (tag[3] == '-') { + while ((ch = getc(ftp->fp)) != '\n') + if (ch == EOF) { + return 0; + } + } + else if (tag[3] == ' ') { + ptr = fgets(buf, FTP_BUFSIZE, ftp->fp); + if (!ptr || !(ptr = strchr(buf, '\n'))) + return 0; + if (ptr > buf && ptr[-1] == '\r') + ptr--; + *ptr = 0; + } + else { + return 0; + } + } while (tag[3] == '-'); - convert_to_long(arg1); - convert_to_string(arg2); - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; - } + /* translate the tag */ + if (!isdigit(tag[0]) || !isdigit(tag[1]) || !isdigit(tag[2])) + return 0; - /* set up a temporary output file */ - if ((outfp = tmpfile()) == NULL) { - php_error(E_WARNING, "error opening tmpfile"); - RETURN_FALSE; - } + ftp->resp = 100 * (tag[0] - '0') + + 10 * (tag[1] - '0') + + (tag[2] - '0'); + return 1; +} - /* list to the temporary file */ - if (!FtpDir(outfp, arg2->value.str.val, net) || ferror(outfp)) { - fclose(outfp); - RETURN_FALSE; - } - array_init(return_value); - rewind(outfp); +int +ftp_type(ftpbuf_t *ftp, ftptype_t type) +{ + char typechar; - /* Pluck out each file name and save to the return array. */ - do { - /* scan for end of line */ - size = 1; - while ((ch = getc(outfp)) != '\n') { - if (ch == EOF) { - size = -1; - break; - } - size++; - } + if (ftp == NULL) + return 0; - if (size > 0) { - /* seek back to the start of file name and copy - * to a buffer. add the buffer to the array. - */ - fseek(outfp, -size, SEEK_CUR); - entry = emalloc(size); - ptr = entry; - while (--size) - *ptr++ = getc(outfp); - *ptr = 0; + if (type == ftp->type) + return 1; - add_next_index_string(return_value, entry, 0); - } + if (type == FTPTYPE_ASCII) + typechar = 'A'; + else if (type == FTPTYPE_IMAGE) + typechar = 'I'; + else + return 0; + + fprintf(ftp->fp, "TYPE %c\r\n", typechar); + if (!ftp_getresp(ftp) || ftp->resp != 200) + return 0; - /* eat the \n */ - (void) getc(outfp); - } while (size != -1); - fclose(outfp); + ftp->type = type; + + return 1; } -/* }}} */ -/* {{{ proto string ftp_systype(int stream) - Returns the system type identifier */ -PHP_FUNCTION(ftp_systype) + +int +ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path, ftptype_t type) { - pval *arg1; - int id, type; - netbuf *net; - char buf[64]; + databuf_t *data = NULL; + int ch, lastch; + if (ftp == NULL) + return 0; - /* arg1 - netbuf - * arg2 - directory - */ - if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) { - WRONG_PARAM_COUNT; - } + if (!ftp_type(ftp, type)) + goto bail; - convert_to_long(arg1); + if ((data = ftp_port(ftp)) == NULL) + goto bail; - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; - } + fprintf(ftp->fp, "RETR %s\r\n", path); + if (!ftp_getresp(ftp) || ftp->resp != 150) + goto bail; - if (!FtpSysType(buf, sizeof(buf), net)) { - php_error(E_WARNING, "FtpSysType: %s", FtpLastResponse(net)); - RETURN_FALSE; + if ((data = data_accept(data)) == NULL) + goto bail; + + lastch = 0; + while ((ch = getc(data->fp)) != EOF) { + if (type == FTPTYPE_ASCII) { + if (lastch == '\r' && ch != '\n') + putc('\r', outfp); + if (ch != '\r') + putc(ch, outfp); + lastch = ch; + } + else { + putc(ch, outfp); + } } + if (type == FTPTYPE_ASCII && lastch == '\r') + putc('\r', outfp); + + if (ferror(data->fp) || ferror(outfp)) + goto bail; + + data = data_close(data); - RETURN_STRING(buf, 1); + if (!ftp_getresp(ftp) || ftp->resp != 226) + goto bail; + + return 1; +bail: + data_close(data); + return 0; } -/* }}} */ -/* {{{ proto int ftp_get(int stream, string local_file, string remote_file, int mode) - Retrieves a file from the FTP server. */ -PHP_FUNCTION(ftp_get) + +int +ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, ftptype_t type) { - pval *arg1, *arg2, *arg3, *arg4; - int id, type; - netbuf *net; - FILE *outfp, *tmpfp; - char *entry = NULL; - char *ptr; - long size; - char ch; - - - /* arg1 - netbuf - * arg2 - destination (local) file - * arg3 - source (remote) file - * arg4 - transfer mode - */ - if ( ARG_COUNT(ht) != 4 || - getParameters(ht, 4, &arg1, &arg2, &arg3, &arg4) == FAILURE) - { - WRONG_PARAM_COUNT; - } + databuf_t *data = NULL; + int ch; - convert_to_long(arg1); - convert_to_string(arg2); - convert_to_string(arg3); - convert_to_long(arg4); + if (ftp == NULL) + return 0; - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; - } + if (!ftp_type(ftp, type)) + goto bail; + + if ((data = ftp_port(ftp)) == NULL) + goto bail; - if ( arg4->value.lval != FTPLIB_ASCII && - arg4->value.lval != FTPLIB_BINARY) - { - php_error(E_WARNING, "arg4 must be FTP_ASCII or FTP_BINARY"); - RETURN_FALSE; + fprintf(ftp->fp, "STOR %s\r\n", path); + if (!ftp_getresp(ftp) || ftp->resp != 150) + goto bail; + + if ((data = data_accept(data)) == NULL) + goto bail; + + while ((ch = getc(infp)) != EOF) { + if (type == FTPTYPE_ASCII && ch == '\n') + putc('\r', data->fp); + putc(ch, data->fp); } + if (ferror(data->fp) || ferror(infp)) + goto bail; + + data = data_close(data); + + if (!ftp_getresp(ftp) || ftp->resp != 226) + goto bail; + + return 1; +bail: + data_close(data); + return 0; +} + - /* get to temporary file, so if there is an error, no existing - * file gets clobbered - */ - if ((tmpfp = tmpfile()) == NULL) { - php_error(E_WARNING, "error opening tmpfile"); - RETURN_FALSE; +databuf_t* +ftp_port(ftpbuf_t *ftp) +{ + int fd = -1; + databuf_t *data; + struct sockaddr_in addr; + int size; + union { + unsigned long l[1]; + unsigned short s[2]; + unsigned char c[4]; + } ipbox; + + /* alloc the data structure */ + data = calloc(1, sizeof(*data)); + if (data == NULL) { + perror("calloc"); + return NULL; } + data->listener = -1; + data->type = ftp->type; - if ( !FtpGet(tmpfp, arg3->value.str.val, arg4->value.lval, net) || - ferror(tmpfp)) - { - fclose(tmpfp); - php_error(E_WARNING, "FtpGet: %s", FtpLastResponse(net)); - RETURN_FALSE; + /* bind/listen */ + if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + perror("socket"); + goto bail; } - rewind(tmpfp); + /* bind to a local address */ + memset(&addr, 0, sizeof(addr)); + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = 0; - if ((outfp = fopen(arg2->value.str.val, "w")) == NULL) { - fclose(tmpfp); - php_error(E_WARNING, "error opening %s", arg2->value.str.val); - RETURN_FALSE; + if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) { + perror("bind"); + goto bail; } - while ((ch = getc(tmpfp)) != EOF) - putc(ch, outfp); + size = sizeof(addr); + if (getsockname(fd, (struct sockaddr*) &addr, &size) == -1) { + perror("getsockname"); + goto bail; + } - if (ferror(tmpfp) || ferror(outfp)) { - fclose(tmpfp); - fclose(outfp); - php_error(E_WARNING, "error writing %s", arg2->value.str.val); - RETURN_FALSE; + if (listen(fd, 5) == -1) { + perror("listen"); + goto bail; } - fclose(tmpfp); - fclose(outfp); + data->listener = fd; + + /* send the PORT */ + ipbox.l[0] = ftp->localaddr.s_addr; + fprintf(ftp->fp, "PORT %u,%u,%u,%u,", + ipbox.c[0], ipbox.c[1], ipbox.c[2], ipbox.c[3]); + ipbox.s[0] = addr.sin_port; + fprintf(ftp->fp, "%u,%u\r\n", + ipbox.c[0], ipbox.c[1]); + + if (!ftp_getresp(ftp) || ftp->resp != 200) + goto bail; + + return data; - RETURN_TRUE; +bail: + if (fd != -1) + close(fd); + free(data); + return NULL; } -/* }}} */ -/* {{{ proto int ftp_put(int stream, string remote_file, string local_file, int mode) - Stores a file on the FTP server */ -PHP_FUNCTION(ftp_put) + +databuf_t* +data_accept(databuf_t *data) { - pval *arg1, *arg2, *arg3, *arg4; - int id, type; - netbuf *net; - FILE *infp; - char *entry = NULL; - char *ptr; - long size; - char ch; - - - /* arg1 - netbuf - * arg2 - destination (remote) file - * arg3 - source (local) file - * arg4 - transfer mode - */ - if ( ARG_COUNT(ht) != 4 || - getParameters(ht, 4, &arg1, &arg2, &arg3, &arg4) == FAILURE) - { - WRONG_PARAM_COUNT; - } + struct sockaddr_in addr; + int size; + int fd; - convert_to_long(arg1); - convert_to_string(arg2); - convert_to_string(arg3); - convert_to_long(arg4); + size = sizeof(addr); + fd = accept(data->listener, (struct sockaddr*) &addr, &size); + close(data->listener); + data->listener = -1; - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; + if (fd == -1) { + free(data); + return NULL; } - if ( arg4->value.lval != FTPLIB_ASCII && - arg4->value.lval != FTPLIB_BINARY) - { - php_error(E_WARNING, "arg4 must be FTP_ASCII or FTP_BINARY"); - RETURN_FALSE; + if ((data->fp = fdopen(fd, "r+")) == NULL) { + close(fd); + free(data); + return NULL; } - if ((infp = fopen(arg3->value.str.val, "r")) == NULL) { - php_error(E_WARNING, "error opening %s", arg3->value.str.val); - RETURN_FALSE; - } - if ( !FtpPut(infp, arg2->value.str.val, arg4->value.lval, net) || - ferror(infp)) - { - fclose(infp); - php_error(E_WARNING, "FtpPut: %s", FtpLastResponse(net)); - RETURN_FALSE; - } - fclose(infp); + return data; +} + - RETURN_TRUE; +databuf_t* +data_close(databuf_t *data) +{ + if (data == NULL) + return NULL; + if (data->listener != -1) + close(data->listener); + if (data->fp) + fclose(data->fp); + free(data); + return NULL; } -/* }}} */ -/* {{{ proto int ftp_quit(int stream) - Closes the FTP stream */ -PHP_FUNCTION(ftp_quit) + +char** +ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path) { - pval *arg1; - int id, type; - netbuf *net; - - /* arg1 - netbuf - */ - if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) { - WRONG_PARAM_COUNT; + FILE *tmpfp = NULL; + databuf_t *data = NULL; + int ch, lastch; + int size; + int lines; + char **ret = NULL; + char **entry; + char *text; + + + if ((tmpfp = tmpfile()) == NULL) + return NULL; + + if (!ftp_type(ftp, FTPTYPE_ASCII)) + goto bail; + + if ((data = ftp_port(ftp)) == NULL) + goto bail; + + if (path) + fprintf(ftp->fp, "%s %s\r\n", cmd, path); + else + fprintf(ftp->fp, "%s\r\n", cmd); + if (!ftp_getresp(ftp) || ftp->resp != 150) + goto bail; + + /* pull data buffer into tmpfile */ + if ((data = data_accept(data)) == NULL) + goto bail; + + size = 0; + lines = 0; + lastch = 0; + while ((ch = getc(data->fp)) != EOF) { + if (ch == '\n' && lastch == '\r') + lines++; + else + size++; + putc(ch, tmpfp); + lastch = ch; + } + data = data_close(data); + + if (ferror(tmpfp)) + goto bail; + + rewind(tmpfp); + + ret = malloc((lines + 1) * sizeof(char**) + size * sizeof(char*)); + if (ret == NULL) { + perror("malloc"); + goto bail; } - convert_to_long(arg1); - id = arg1->value.lval; - net = php3_list_find(id, &type); - if (!net || type != le_netbuf) { - php_error(E_WARNING, "Unable to find netbuf %d", id); - RETURN_FALSE; + entry = ret; + text = (char*) (ret + lines + 1); + *entry = text; + lastch = 0; + while ((ch = getc(tmpfp)) != EOF) { + if (ch == '\n' && lastch == '\r') { + *(text - 1) = 0; + *++entry = text; + } + else { + *text++ = ch; + } + lastch = ch; } + *entry = NULL; - php3_list_delete(id); + if (ferror(tmpfp)) + goto bail; - RETURN_TRUE; + fclose(tmpfp); + + if (!ftp_getresp(ftp) || ftp->resp != 226) { + free(ret); + return NULL; + } + + return ret; +bail: + data_close(data); + fclose(tmpfp); + free(ret); + return NULL; } -/* }}} */ #endif /* HAVE_FTP */ |
