]> granicus.if.org Git - php/commitdiff
Replaced ftplib because of incompatible license.
authorAndrew Skalski <askalski@php.net>
Mon, 20 Sep 1999 14:10:25 +0000 (14:10 +0000)
committerAndrew Skalski <askalski@php.net>
Mon, 20 Sep 1999 14:10:25 +0000 (14:10 +0000)
ext/ftp/Makefile.am
ext/ftp/ftp.c
ext/ftp/ftp.h
ext/ftp/ftplib.c [deleted file]
ext/ftp/ftplib.h [deleted file]
ext/ftp/php_ftp.c [new file with mode: 0644]
ext/ftp/php_ftp.h [new file with mode: 0644]

index f609671ac4734ccb9c9ea0b8cfa499cd44afa114..ea032672b0cae6167dd9afa038b939f74fcc50d5 100644 (file)
@@ -2,4 +2,4 @@
 
 INCLUDES=@INCLUDES@ -I@top_srcdir@ -I@top_srcdir@/libzend
 noinst_LIBRARIES=libphpext_ftp.a
-libphpext_ftp_a_SOURCES=ftp.c ftplib.c
+libphpext_ftp_a_SOURCES=php_ftp.c ftp.c
index f955ddab3f4b198f516f754089e48670132d9e8a..502022ad24aab0159e7576d3c1ff42df21503663 100644 (file)
  */
 
 #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 */
index 1a71ba70a123f7c9ae19341aa5d918239ce19abd..f9a2cf549c9bedb9a1758798200ce987a3d14754 100644 (file)
-/* $Id$ */
+/*
+   +----------------------------------------------------------------------+
+   | PHP HTML Embedded Scripting Language Version 3.0                     |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-1999 PHP Development Team (See Credits file)      |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or modify |
+   | it under the terms of one of the following licenses:                 |
+   |                                                                      |
+   |  A) 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.                                               |
+   |                                                                      |
+   |  B) the PHP License as published by the PHP Development Team and     |
+   |     included in the distribution in the file: LICENSE                |
+   |                                                                      |
+   | 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 both licenses referred to here.   |
+   | If you did not, or have any questions about PHP licensing, please    |
+   | contact core@php.net.                                                |
+   +----------------------------------------------------------------------+
+   | Authors:                                                             |
+   |          Andrew Skalski      <askalski@chek.com>                     |
+   +----------------------------------------------------------------------+
+ */
 
-#ifndef        _INCLUDED_FTP_H
-#define        _INCLUDED_FTP_H
+#ifndef        _FTP_H
+#define        _FTP_H
 
-#if COMPILE_DL
-#undef HAVE_FTP
-#define HAVE_FTP 1
-#endif
+#include <stdio.h>
+#include <netinet/in.h>
+
+
+#define        FTP_BUFSIZE     4096
+
+typedef enum ftptype {
+       FTPTYPE_ASCII,
+       FTPTYPE_IMAGE,
+} ftptype_t;
+
+typedef struct ftpbuf
+{
+       FILE            *fp;                    /* control connection */
+       struct in_addr  localaddr;              /* local inet address */
+       int             resp;                   /* last response code */
+       char            inbuf[FTP_BUFSIZE];     /* last response text */
+       char            *pwd;                   /* cached pwd */
+       char            *syst;                  /* cached system type */
+       ftptype_t       type;                   /* current transfer type */
+} ftpbuf_t;
+
+typedef struct databuf
+{
+       int             listener;               /* listener socket */
+       FILE            *fp;                    /* data connection */
+       ftptype_t       type;                   /* transfer type */
+} databuf_t;
+
+
+/* open a FTP connection, returns ftpbuf (NULL on error)
+ * port is the ftp port in network byte order, or 0 for the default
+ */
+ftpbuf_t*      ftp_open(const char *host, short port);
+
+/* quits from the ftp session (it still needs to be closed)
+ * return true on success, false on error
+ */
+int            ftp_quit(ftpbuf_t *ftp);
+
+/* frees up any cached data held in the ftp buffer */
+void           ftp_gc(ftpbuf_t *ftp);
+
+/* close the FTP connection and return NULL */
+ftpbuf_t*      ftp_close(ftpbuf_t *ftp);
+
+/* logs into the FTP server, returns true on success, false on error */
+int            ftp_login(ftpbuf_t *ftp, const char *user, const char *pass);
+
+/* reinitializes the connection, returns true on success, false on error */
+int            ftp_reinit(ftpbuf_t *ftp);
+
+/* returns the remote system type (NULL on error) */
+const char*    ftp_syst(ftpbuf_t *ftp);
+
+/* returns the present working directory (NULL on error) */
+const char*    ftp_pwd(ftpbuf_t *ftp);
+
+/* changes directories, return true on success, false on error */
+int            ftp_chdir(ftpbuf_t *ftp, const char *dir);
+
+/* changes to parent directory, return true on success, false on error */
+int            ftp_cdup(ftpbuf_t *ftp);
 
-#if HAVE_FTP
+/* creates a directory, return the directory name on success, NULL on error.
+ * the return value must be freed
+ */
+char*          ftp_mkdir(ftpbuf_t *ftp, const char *dir);
 
-extern php3_module_entry php3_ftp_module_entry;
-#define php3_ftp_module_ptr &php3_ftp_module_entry
+/* removes a directory, return true on success, false on error */
+int            ftp_rmdir(ftpbuf_t *ftp, const char *dir);
 
-extern PHP_MINIT_FUNCTION(ftp);
+/* returns a NULL-terminated array of filenames in the given path
+ * or NULL on error.  the return array must be freed (but don't
+ * free the array elements)
+ */
+char**         ftp_nlist(ftpbuf_t *ftp, const char *path);
 
-PHP_FUNCTION(ftp_connect);
-PHP_FUNCTION(ftp_login);
-PHP_FUNCTION(ftp_pwd);
-PHP_FUNCTION(ftp_cdup);
-PHP_FUNCTION(ftp_chdir);
-PHP_FUNCTION(ftp_mkdir);
-PHP_FUNCTION(ftp_rmdir);
-PHP_FUNCTION(ftp_nlist);
-PHP_FUNCTION(ftp_listraw);
-PHP_FUNCTION(ftp_systype);
-PHP_FUNCTION(ftp_get);
-PHP_FUNCTION(ftp_put);
-PHP_FUNCTION(ftp_quit);
+/* returns a NULL-terminated array of lines returned by the ftp
+ * LIST command for the given path or NULL on error.  the return
+ * array must be freed (but don't
+ * free the array elements)
+ */
+char**         ftp_list(ftpbuf_t *ftp, const char *path);
 
-#define phpext_ftp_ptr php3_ftp_module_ptr
+/* retrieves a file and saves its contents to outfp
+ * returns true on success, false on error
+ */
+int            ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path,
+                       ftptype_t type);
 
-#else
-#define php3_ftp_module_ptr NULL
-#endif /* HAVE_FTP */
+/* stores the data from infp as a file on the remote server
+ * returns true on success, false on error
+ */
+int            ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp,
+                       ftptype_t type);
 
 #endif
diff --git a/ext/ftp/ftplib.c b/ext/ftp/ftplib.c
deleted file mode 100644 (file)
index 35a06d6..0000000
+++ /dev/null
@@ -1,1253 +0,0 @@
-/***************************************************************************/
-/*                                                                        */
-/* ftplib.c - callable ftp access routines                                */
-/* Copyright (C) 1996, 1997, 1998 Thomas Pfau, pfau@cnj.digex.net         */
-/*     73 Catherine Street, South Bound Brook, NJ, 08880                  */
-/*                                                                        */
-/* This library is free software; you can redistribute it and/or          */
-/* modify it under the terms of the GNU Library General Public            */
-/* License as published by the Free Software Foundation; either                   */
-/* version 2 of the License, or (at your option) any later version.       */
-/*                                                                        */
-/* This library 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      */
-/* Library General Public License for more details.                       */
-/*                                                                        */
-/* You should have received a copy of the GNU Library General Public      */
-/* License along with this progam; if not, write to the                           */
-/* Free Software Foundation, Inc., 59 Temple Place - Suite 330,                   */
-/* Boston, MA 02111-1307, USA.                                            */
-/*                                                                        */
-/***************************************************************************/
-
-/* Adapted by Andrew Skalski <askalski@chek.com> for use with PHP. */
-
-
-#include "php.h"
-
-#if HAVE_FTP
-
-#if defined(__unix__) || defined(__VMS)
-#include <unistd.h>
-#endif
-#if defined(_WIN32)
-#include <windows.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-#if defined(__unix__)
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#elif defined(VMS)
-#include <types.h>
-#include <socket.h>
-#include <in.h>
-#include <netdb.h>
-#include <inet.h>
-#elif defined(_WIN32)
-#include <winsock.h>
-#endif
-
-#define BUILDING_LIBRARY
-#include "ftplib.h"
-
-#if defined(_WIN32)
-#define SETSOCKOPT_OPTVAL_TYPE (const char *)
-#else
-#define SETSOCKOPT_OPTVAL_TYPE (void *)
-#endif
-
-#define FTPLIB_BUFSIZ 8192
-#define ACCEPT_TIMEOUT 30
-
-#define FTPLIB_CONTROL 0
-#define FTPLIB_READ 1
-#define FTPLIB_WRITE 2
-
-#if !defined FTPLIB_DEFMODE
-#define FTPLIB_DEFMODE FTPLIB_PASSIVE
-#endif
-
-struct NetBuf {
-    char *cput,*cget;
-    int handle;
-    int cavail,cleft;
-    char *buf;
-    int dir;
-    netbuf *ctrl;
-    int cmode;
-    struct timeval idletime;
-    FtpCallback idlecb;
-    void *idlearg;
-    int xfered;
-    int cbbytes;
-    int xfered1;
-    char response[256];
-};
-
-static char *version =
-    "ftplib Release 3.1 6/xx/98, copyright 1996, 1997, 1998 Thomas Pfau";
-
-GLOBALDEF int ftplib_debug = 0;
-
-#if defined(__unix__) || defined(VMS)
-#define net_read read
-#define net_write write
-#define net_close close
-#elif defined(_WIN32)
-#define net_read(x,y,z) recv(x,y,z,0)
-#define net_write(x,y,z) send(x,y,z,0)
-#define net_close closesocket
-#endif
-\f
-#if defined(NEED_MEMCCPY)
-/*
- * VAX C does not supply a memccpy routine so I provide my own
- */
-void *memccpy(void *dest, const void *src, int c, size_t n)
-{
-    int i=0;
-    const unsigned char *ip=src;
-    unsigned char *op=dest;
-
-    while (i < n)
-    {
-       if ((*op++ = *ip++) == c)
-           break;
-       i++;
-    }
-    if (i == n)
-       return NULL;
-    return op;
-}
-#endif
-#if defined(NEED_STRDUP)
-/*
- * strdup - return a malloc'ed copy of a string
- */
-char *strdup(const char *src)
-{
-    int l = strlen(src) + 1;
-    char *dst = malloc(l);
-    if (dst)
-        strcpy(dst,src);
-    return dst;
-}
-#endif
-\f
-/*
- * socket_wait - wait for socket to receive or flush data
- *
- * return 1 if no user callback, otherwise, return value returned by
- * user callback
- */
-static int socket_wait(netbuf *ctl)
-{
-    fd_set fd,*rfd = NULL,*wfd = NULL;
-    struct timeval tv;
-    int rv = 0;
-    if ((ctl->dir == FTPLIB_CONTROL) || (ctl->idlecb == NULL))
-       return 1;
-    if (ctl->dir == FTPLIB_WRITE)
-       wfd = &fd;
-    else
-       rfd = &fd;
-    FD_ZERO(&fd);
-    do
-    {
-       FD_SET(ctl->handle,&fd);
-       tv = ctl->idletime;
-       rv = select(ctl->handle+1, rfd, wfd, NULL, &tv);
-       if (rv == -1)
-       {
-           rv = 0;
-           strncpy(ctl->ctrl->response, strerror(errno),
-                    sizeof(ctl->ctrl->response));
-           break;
-       }
-       else if (rv > 0)
-       {
-           rv = 1;
-           break;
-       }
-    }
-    while ((rv = ctl->idlecb(ctl, ctl->xfered, ctl->idlearg)));
-    return rv;
-}
-\f
-/*
- * read a line of text
- *
- * return -1 on error or bytecount
- */
-static int readline(char *buf,int max,netbuf *ctl)
-{
-    int x,retval = 0;
-    char *end,*bp=buf;
-    int eof = 0;
-
-    if ((ctl->dir != FTPLIB_CONTROL) && (ctl->dir != FTPLIB_READ))
-       return -1;
-    if (max == 0)
-       return 0;
-    do
-    {
-       if (ctl->cavail > 0)
-       {
-           x = (max >= ctl->cavail) ? ctl->cavail : max-1;
-           end = memccpy(bp,ctl->cget,'\n',x);
-           if (end != NULL)
-               x = end - bp;
-           retval += x;
-           bp += x;
-           *bp = '\0';
-           max -= x;
-           ctl->cget += x;
-           ctl->cavail -= x;
-           if (end != NULL)
-           {
-               bp -= 2;
-               if (strcmp(bp,"\r\n") == 0)
-               {
-                   *bp++ = '\n';
-                   *bp++ = '\0';
-                   --retval;
-               }
-               break;
-           }
-       }
-       if (max == 1)
-       {
-           *buf = '\0';
-           break;
-       }
-       if (ctl->cput == ctl->cget)
-       {
-           ctl->cput = ctl->cget = ctl->buf;
-           ctl->cavail = 0;
-           ctl->cleft = FTPLIB_BUFSIZ;
-       }
-       if (eof)
-       {
-           if (retval == 0)
-               retval = -1;
-           break;
-       }
-       if (!socket_wait(ctl))
-           return retval;
-       if ((x = net_read(ctl->handle,ctl->cput,ctl->cleft)) == -1)
-       {
-           perror("read");
-           retval = -1;
-           break;
-       }
-       if (x == 0)
-           eof = 1;
-       ctl->cleft -= x;
-       ctl->cavail += x;
-       ctl->cput += x;
-    }
-    while (1);
-    return retval;
-}
-\f
-/*
- * write lines of text
- *
- * return -1 on error or bytecount
- */
-static int writeline(char *buf, int len, netbuf *nData)
-{
-    int x, nb=0, w;
-    char *ubp = buf, *nbp;
-    char lc=0;
-
-    if (nData->dir != FTPLIB_WRITE)
-       return -1;
-    nbp = nData->buf;
-    for (x=0; x < len; x++)
-    {
-       if ((*ubp == '\n') && (lc != '\r'))
-       {
-           if (nb == FTPLIB_BUFSIZ)
-           {
-               if (!socket_wait(nData))
-                   return x;
-               w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ);
-               if (w != FTPLIB_BUFSIZ)
-               {
-                   printf("net_write(1) returned %d, errno = %d\n", w, errno);
-                   return(-1);
-               }
-               nb = 0;
-           }
-           nbp[nb++] = '\r';
-       }
-       if (nb == FTPLIB_BUFSIZ)
-       {
-           if (!socket_wait(nData))
-               return x;
-           w = net_write(nData->handle, nbp, FTPLIB_BUFSIZ);
-           if (w != FTPLIB_BUFSIZ)
-           {
-               printf("net_write(2) returned %d, errno = %d\n", w, errno);
-               return(-1);
-           }
-           nb = 0;
-       }
-       nbp[nb++] = lc = *ubp++;
-    }
-    if (nb)
-    {
-       if (!socket_wait(nData))
-           return x;
-       w = net_write(nData->handle, nbp, nb);
-       if (w != nb)
-       {
-           printf("net_write(3) returned %d, errno = %d\n", w, errno);
-           return(-1);
-       }
-    }
-    return len;
-}
-\f
-/*
- * read a response from the server
- *
- * return 0 if first char doesn't match
- * return 1 if first char matches
- */
-static int readresp(char c, netbuf *nControl)
-{
-    char match[5];
-    if (readline(nControl->response,256,nControl) == -1)
-    {
-       perror("Control socket read failed");
-       return 0;
-    }
-    if (ftplib_debug > 1)
-       fprintf(stderr,"%s",nControl->response);
-    if (nControl->response[3] == '-')
-    {
-       strncpy(match,nControl->response,3);
-       match[3] = ' ';
-       match[4] = '\0';
-       do
-       {
-           if (readline(nControl->response,256,nControl) == -1)
-           {
-               perror("Control socket read failed");
-               return 0;
-           }
-           if (ftplib_debug > 1)
-               fprintf(stderr,"%s",nControl->response);
-       }
-       while (strncmp(nControl->response,match,4));
-    }
-    if (nControl->response[0] == c)
-       return 1;
-    return 0;
-}
-\f
-/*
- * FtpInit for stupid operating systems that require it (Windows NT)
- */
-GLOBALDEF void FtpInit(void)
-{
-#if defined(_WIN32)
-    WORD wVersionRequested;
-    WSADATA wsadata;
-    int err;
-    wVersionRequested = MAKEWORD(1,1);
-    if ((err = WSAStartup(wVersionRequested,&wsadata)) != 0)
-       fprintf(stderr,"Network failed to start: %d\n",err);
-#endif
-}
-\f
-/*
- * FtpLastResponse - return a pointer to the last response received
- */
-GLOBALDEF char *FtpLastResponse(netbuf *nControl)
-{
-    if ((nControl) && (nControl->dir == FTPLIB_CONTROL))
-       return nControl->response;
-    return NULL;
-}
-\f
-/*
- * FtpConnect - connect to remote server
- *
- * return 1 if connected, 0 if not
- */
-GLOBALDEF int FtpConnect(const char *host, netbuf **nControl)
-{
-    int sControl;
-    struct sockaddr_in sin;
-    struct hostent *phe;
-    struct servent *pse;
-    int on=1;
-    netbuf *ctrl;
-    char *lhost;
-    char *pnum;
-
-    memset(&sin,0,sizeof(sin));
-    sin.sin_family = AF_INET;
-    lhost = strdup(host);
-    pnum = strchr(lhost,':');
-    if (pnum == NULL)
-    {
-#if defined(VMS)
-       sin.sin_port = htons(21);
-#else
-       if ((pse = getservbyname("ftp","tcp")) == NULL)
-       {
-           perror("getservbyname");
-           return 0;
-       }
-       sin.sin_port = pse->s_port;
-#endif
-    }
-    else
-    {
-       *pnum++ = '\0';
-       if (isdigit(*pnum))
-           sin.sin_port = htons(atoi(pnum));
-       else
-       {
-           pse = getservbyname(pnum,"tcp");
-           sin.sin_port = pse->s_port;
-       }
-    }
-    if ((sin.sin_addr.s_addr = inet_addr(lhost)) == -1)
-    {
-       if ((phe = gethostbyname(lhost)) == NULL)
-       {
-           perror("gethostbyname");
-           return 0;
-       }
-       memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length);
-    }
-    free(lhost);
-    sControl = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-    if (sControl == -1)
-    {
-       perror("socket");
-       return 0;
-    }
-    if (setsockopt(sControl,SOL_SOCKET,SO_REUSEADDR,
-                  SETSOCKOPT_OPTVAL_TYPE &on, sizeof(on)) == -1)
-    {
-       perror("setsockopt");
-       net_close(sControl);
-       return 0;
-    }
-    if (connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1)
-    {
-       perror("connect");
-       net_close(sControl);
-       return 0;
-    }
-    ctrl = calloc(1,sizeof(netbuf));
-    if (ctrl == NULL)
-    {
-       perror("calloc");
-       net_close(sControl);
-       return 0;
-    }
-    ctrl->buf = malloc(FTPLIB_BUFSIZ);
-    if (ctrl->buf == NULL)
-    {
-       perror("calloc");
-       net_close(sControl);
-       free(ctrl);
-       return 0;
-    }
-    ctrl->handle = sControl;
-    ctrl->dir = FTPLIB_CONTROL;
-    ctrl->ctrl = NULL;
-    ctrl->cmode = FTPLIB_DEFMODE;
-    ctrl->idlecb = NULL;
-    ctrl->idletime.tv_sec = ctrl->idletime.tv_usec = 0;
-    ctrl->idlearg = NULL;
-    ctrl->xfered = 0;
-    ctrl->xfered1 = 0;
-    ctrl->cbbytes = 0;
-    if (readresp('2', ctrl) == 0)
-    {
-       net_close(sControl);
-       free(ctrl->buf);
-       free(ctrl);
-       return 0;
-    }
-    *nControl = ctrl;
-    return 1;
-}
-\f
-/*
- * FtpOptions - change connection options
- *
- * returns 1 if successful, 0 on error
- */
-GLOBALDEF int FtpOptions(int opt, long val, netbuf *nControl)
-{
-    int v,rv=0;
-    switch (opt)
-    {
-      case FTPLIB_CONNMODE:
-       v = (int) val;
-       if ((v == FTPLIB_PASSIVE) || (v == FTPLIB_PORT))
-       {
-           nControl->cmode = v;
-           rv = 1;
-       }
-       break;
-      case FTPLIB_CALLBACK:
-       nControl->idlecb = (FtpCallback) val;
-       rv = 1;
-       break;
-      case FTPLIB_IDLETIME:
-       v = (int) val;
-       rv = 1;
-       nControl->idletime.tv_sec = v / 1000;
-       nControl->idletime.tv_usec = (v % 1000) * 1000;
-       break;
-      case FTPLIB_CALLBACKARG:
-       rv = 1;
-       nControl->idlearg = (void *) val;
-       break;
-      case FTPLIB_CALLBACKBYTES:
-        rv = 1;
-        nControl->cbbytes = (int) val;
-        break;
-    }
-    return rv;
-}
-\f
-/*
- * FtpSendCmd - send a command and wait for expected response
- *
- * return 1 if proper response received, 0 otherwise
- */
-static int FtpSendCmd(const char *cmd, char expresp, netbuf *nControl)
-{
-    char buf[256];
-    if (nControl->dir != FTPLIB_CONTROL)
-       return 0;
-    if (ftplib_debug > 2)
-       fprintf(stderr,"%s\n",cmd);
-    if ((strlen(cmd) + 3) > sizeof(buf))
-        return 0;
-    sprintf(buf,"%s\r\n",cmd);
-    if (net_write(nControl->handle,buf,strlen(buf)) <= 0)
-    {
-       perror("write");
-       return 0;
-    }
-    return readresp(expresp, nControl);
-}
-\f
-/*
- * FtpLogin - log in to remote server
- *
- * return 1 if logged in, 0 otherwise
- */
-GLOBALDEF int FtpLogin(const char *user, const char *pass, netbuf *nControl)
-{
-    char tempbuf[64];
-
-    if (((strlen(user) + 7) > sizeof(tempbuf)) ||
-        ((strlen(pass) + 7) > sizeof(tempbuf)))
-        return 0;
-    sprintf(tempbuf,"USER %s",user);
-    if (!FtpSendCmd(tempbuf,'3',nControl))
-    {
-       if (nControl->response[0] == '2')
-           return 1;
-       return 0;
-    }
-    sprintf(tempbuf,"PASS %s",pass);
-    return FtpSendCmd(tempbuf,'2',nControl);
-}
-\f
-/*
- * FtpOpenPort - set up data connection
- *
- * return 1 if successful, 0 otherwise
- */
-static int FtpOpenPort(netbuf *nControl, netbuf **nData, int mode, int dir)
-{
-    int sData;
-    union {
-       struct sockaddr sa;
-       struct sockaddr_in in;
-    } sin;
-    struct linger lng = { 0, 0 };
-    unsigned int l;
-    int on=1;
-    netbuf *ctrl;
-    char *cp;
-    unsigned int v[6];
-    char buf[256];
-
-    if (nControl->dir != FTPLIB_CONTROL)
-       return -1;
-    if ((dir != FTPLIB_READ) && (dir != FTPLIB_WRITE))
-    {
-       sprintf(nControl->response, "Invalid direction %d\n", dir);
-       return -1;
-    }
-    if ((mode != FTPLIB_ASCII) && (mode != FTPLIB_IMAGE))
-    {
-       sprintf(nControl->response, "Invalid mode %c\n", mode);
-       return -1;
-    }
-    l = sizeof(sin);
-    if (nControl->cmode == FTPLIB_PASSIVE)
-    {
-       memset(&sin, 0, l);
-       sin.in.sin_family = AF_INET;
-       if (!FtpSendCmd("PASV",'2',nControl))
-           return -1;
-       cp = strchr(nControl->response,'(');
-       if (cp == NULL)
-           return -1;
-       cp++;
-       sscanf(cp,"%u,%u,%u,%u,%u,%u",&v[2],&v[3],&v[4],&v[5],&v[0],&v[1]);
-       sin.sa.sa_data[2] = v[2];
-       sin.sa.sa_data[3] = v[3];
-       sin.sa.sa_data[4] = v[4];
-       sin.sa.sa_data[5] = v[5];
-       sin.sa.sa_data[0] = v[0];
-       sin.sa.sa_data[1] = v[1];
-    }
-    else
-    {
-       if (getsockname(nControl->handle, &sin.sa, &l) < 0)
-       {
-           perror("getsockname");
-           return 0;
-       }
-    }
-    sData = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
-    if (sData == -1)
-    {
-       perror("socket");
-       return -1;
-    }
-    if (setsockopt(sData,SOL_SOCKET,SO_REUSEADDR,
-                  SETSOCKOPT_OPTVAL_TYPE &on,sizeof(on)) == -1)
-    {
-       perror("setsockopt");
-       net_close(sData);
-       return -1;
-    }
-    if (setsockopt(sData,SOL_SOCKET,SO_LINGER,
-                  SETSOCKOPT_OPTVAL_TYPE &lng,sizeof(lng)) == -1)
-    {
-       perror("setsockopt");
-       net_close(sData);
-       return -1;
-    }
-    if (nControl->cmode == FTPLIB_PASSIVE)
-    {
-       if (connect(sData, &sin.sa, sizeof(sin.sa)) == -1)
-       {
-           perror("connect");
-           net_close(sData);
-           return -1;
-       }
-    }
-    else
-    {
-       sin.in.sin_port = 0;
-       if (bind(sData, &sin.sa, sizeof(sin)) == -1)
-       {
-           perror("bind");
-           net_close(sData);
-           return 0;
-       }
-       if (listen(sData, 1) < 0)
-       {
-           perror("listen");
-           net_close(sData);
-           return 0;
-       }
-       if (getsockname(sData, &sin.sa, &l) < 0)
-           return 0;
-       sprintf(buf, "PORT %d,%d,%d,%d,%d,%d",
-               (unsigned char) sin.sa.sa_data[2],
-               (unsigned char) sin.sa.sa_data[3],
-               (unsigned char) sin.sa.sa_data[4],
-               (unsigned char) sin.sa.sa_data[5],
-               (unsigned char) sin.sa.sa_data[0],
-               (unsigned char) sin.sa.sa_data[1]);
-       if (!FtpSendCmd(buf,'2',nControl))
-       {
-           net_close(sData);
-           return 0;
-       }
-    }
-    ctrl = calloc(1,sizeof(netbuf));
-    if (ctrl == NULL)
-    {
-       perror("calloc");
-       net_close(sData);
-       return -1;
-    }
-    if ((mode == 'A') && ((ctrl->buf = malloc(FTPLIB_BUFSIZ)) == NULL))
-    {
-       perror("calloc");
-       net_close(sData);
-       free(ctrl);
-       return -1;
-    }
-    ctrl->handle = sData;
-    ctrl->dir = dir;
-    ctrl->ctrl = (nControl->cmode == FTPLIB_PASSIVE) ? nControl : NULL;
-    ctrl->idletime = nControl->idletime;
-    ctrl->idlearg = nControl->idlearg;
-    ctrl->xfered = 0;
-    ctrl->xfered1 = 0;
-    ctrl->cbbytes = nControl->cbbytes;
-    if (ctrl->idletime.tv_sec | ctrl->idletime.tv_usec)
-       ctrl->idlecb = nControl->idlecb;
-    else
-       ctrl->idlecb = NULL;
-    *nData = ctrl;
-    return 1;
-}
-\f
-/*
- * FtpAcceptConnection - accept connection from server
- *
- * return 1 if successful, 0 otherwise
- */
-static int FtpAcceptConnection(netbuf *nData, netbuf *nControl)
-{
-    int sData;
-    struct sockaddr addr;
-    unsigned int l;
-    int i;
-    struct timeval tv;
-    fd_set mask;
-    int rv;
-
-    FD_ZERO(&mask);
-    FD_SET(nControl->handle, &mask);
-    FD_SET(nData->handle, &mask);
-    tv.tv_usec = 0;
-    tv.tv_sec = ACCEPT_TIMEOUT;
-    i = nControl->handle;
-    if (i < nData->handle)
-       i = nData->handle;
-    i = select(i+1, &mask, NULL, NULL, &tv);
-    if (i == -1)
-    {
-        strncpy(nControl->response, strerror(errno),
-                sizeof(nControl->response));
-        net_close(nData->handle);
-        nData->handle = 0;
-        rv = 0;
-    }
-    else if (i == 0)
-    {
-       strcpy(nControl->response, "timed out waiting for connection");
-       net_close(nData->handle);
-       nData->handle = 0;
-       rv = 0;
-    }
-    else
-    {
-       if (FD_ISSET(nData->handle, &mask))
-       {
-           l = sizeof(addr);
-           sData = accept(nData->handle, &addr, &l);
-           i = errno;
-           net_close(nData->handle);
-           if (sData > 0)
-           {
-               rv = 1;
-               nData->handle = sData;
-                nData->ctrl = nControl;
-           }
-           else
-           {
-               strncpy(nControl->response, strerror(i),
-                        sizeof(nControl->response));
-               nData->handle = 0;
-               rv = 0;
-           }
-       }
-       else if (FD_ISSET(nControl->handle, &mask))
-       {
-           net_close(nData->handle);
-           nData->handle = 0;
-           readresp('2', nControl);
-           rv = 0;
-       }
-    }
-    return rv; 
-}
-\f
-/*
- * FtpAccess - return a handle for a data stream
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpAccess(const char *path, int typ, int mode, netbuf *nControl,
-    netbuf **nData)
-{
-    char buf[256];
-    int dir;
-    if ((path == NULL) &&
-        ((typ == FTPLIB_FILE_WRITE) || (typ == FTPLIB_FILE_READ)))
-    {
-       sprintf(nControl->response,
-                "Missing path argument for file transfer\n");
-       return 0;
-    }
-    sprintf(buf, "TYPE %c", mode);
-    if (!FtpSendCmd(buf, '2', nControl))
-       return 0;
-    switch (typ)
-    {
-      case FTPLIB_DIR:
-       strcpy(buf,"NLST");
-       dir = FTPLIB_READ;
-       break;
-      case FTPLIB_DIR_VERBOSE:
-       strcpy(buf,"LIST");
-       dir = FTPLIB_READ;
-       break;
-      case FTPLIB_FILE_READ:
-       strcpy(buf,"RETR");
-       dir = FTPLIB_READ;
-       break;
-      case FTPLIB_FILE_WRITE:
-       strcpy(buf,"STOR");
-       dir = FTPLIB_WRITE;
-       break;
-      default:
-       sprintf(nControl->response, "Invalid open type %d\n", typ);
-       return 0;
-    }
-    if (path != NULL)
-    {
-        int i = strlen(buf);
-        buf[i++] = ' ';
-        if ((strlen(path) + i) >= sizeof(buf))
-            return 0;
-        strcpy(&buf[i],path);
-    }
-    if (FtpOpenPort(nControl, nData, mode, dir) == -1)
-       return 0;
-    if (!FtpSendCmd(buf, '1', nControl))
-    {
-       FtpClose(*nData, 0);
-       *nData = NULL;
-       return 0;
-    }
-    if (nControl->cmode == FTPLIB_PORT)
-    {
-       if (!FtpAcceptConnection(*nData,nControl))
-       {
-           FtpClose(*nData, 0);
-           *nData = NULL;
-           return 0;
-       }
-    }
-    return 1;
-}
-\f
-/*
- * FtpRead - read from a data connection
- */
-GLOBALDEF int FtpRead(void *buf, int max, netbuf *nData)
-{
-    int i;
-    if (nData->dir != FTPLIB_READ)
-       return 0;
-    if (nData->buf)
-        i = readline(buf, max, nData);
-    else
-    {
-        socket_wait(nData);
-        i = net_read(nData->handle, buf, max);
-    }
-    nData->xfered += i;
-    if (nData->idlecb && nData->cbbytes)
-    {
-        nData->xfered1 += i;
-        if (nData->xfered1 > nData->cbbytes)
-        {
-            nData->idlecb(nData, nData->xfered, nData->idlearg);
-            nData->xfered1 = 0;
-        }
-    }
-    return i;
-}
-\f
-/*
- * FtpWrite - write to a data connection
- */
-GLOBALDEF int FtpWrite(void *buf, int len, netbuf *nData)
-{
-    int i;
-    if (nData->dir != FTPLIB_WRITE)
-       return 0;
-    if (nData->buf)
-       i = writeline(buf, len, nData);
-    else
-    {
-        socket_wait(nData);
-        i = net_write(nData->handle, buf, len);
-    }
-    nData->xfered += i;
-    if (nData->idlecb && nData->cbbytes)
-    {
-        nData->xfered1 += i;
-        if (nData->xfered1 > nData->cbbytes)
-        {
-            nData->idlecb(nData, nData->xfered, nData->idlearg);
-            nData->xfered1 = 0;
-        }
-    }
-    return i;
-}
-\f
-/*
- * FtpClose - close a data connection
- */
-GLOBALDEF int FtpClose(netbuf *nData, int readResp)
-{
-    netbuf *ctrl;
-    if (nData->dir == FTPLIB_WRITE)
-    {
-       if (nData->buf != NULL)
-           writeline(NULL, 0, nData);
-    }
-    else if (nData->dir != FTPLIB_READ)
-       return 0;
-    if (nData->buf)
-       free(nData->buf);
-    shutdown(nData->handle,2);
-    net_close(nData->handle);
-    ctrl = nData->ctrl;
-    free(nData);
-    if (readResp && ctrl)
-        return(readresp('2', ctrl));
-    return 1;
-}
-\f
-/*
- * FtpSite - send a SITE command
- *
- * return 1 if command successful, 0 otherwise
- */
-GLOBALDEF int FtpSite(const char *cmd, netbuf *nControl)
-{
-    char buf[256];
-    
-    if ((strlen(cmd) + 7) > sizeof(buf))
-        return 0;
-    sprintf(buf,"SITE %s",cmd);
-    if (!FtpSendCmd(buf,'2',nControl))
-       return 0;
-    return 1;
-}
-\f
-/*
- * FtpSysType - send a SYST command
- *
- * Fills in the user buffer with the remote system type.  If more
- * information from the response is required, the user can parse
- * it out of the response buffer returned by FtpLastResponse().
- *
- * return 1 if command successful, 0 otherwise
- */
-GLOBALDEF int FtpSysType(char *buf, int max, netbuf *nControl)
-{
-    int l = max;
-    char *b = buf;
-    char *s;
-    if (!FtpSendCmd("SYST",'2',nControl))
-       return 0;
-    s = &nControl->response[4];
-    while ((--l) && (*s != ' '))
-       *b++ = *s++;
-    *b++ = '\0';
-    return 1;
-}
-\f
-/*
- * FtpMkdir - create a directory at server
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpMkdir(const char *path, netbuf *nControl)
-{
-    char buf[256];
-
-    if ((strlen(path) + 6) > sizeof(buf))
-        return 0;
-    sprintf(buf,"MKD %s",path);
-    if (!FtpSendCmd(buf,'2', nControl))
-       return 0;
-    return 1;
-}
-\f
-/*
- * FtpChdir - change path at remote
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpChdir(const char *path, netbuf *nControl)
-{
-    char buf[256];
-
-    if ((strlen(path) + 6) > sizeof(buf))
-        return 0;
-    sprintf(buf,"CWD %s",path);
-    if (!FtpSendCmd(buf,'2',nControl))
-       return 0;
-    return 1;
-}
-\f
-/*
- * FtpCDUp - move to parent directory at remote
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpCDUp(netbuf *nControl)
-{
-    if (!FtpSendCmd("CDUP",'2',nControl))
-       return 0;
-    return 1;
-}
-\f
-/*
- * FtpRmdir - remove directory at remote
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpRmdir(const char *path, netbuf *nControl)
-{
-    char buf[256];
-
-    if ((strlen(path) + 6) > sizeof(buf))
-        return 0;
-    sprintf(buf,"RMD %s",path);
-    if (!FtpSendCmd(buf,'2',nControl))
-       return 0;
-    return 1;
-}
-\f
-/*
- * FtpPwd - get working directory at remote
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpPwd(char *path, int max, netbuf *nControl)
-{
-    int l = max;
-    char *b = path;
-    char *s;
-    if (!FtpSendCmd("PWD",'2',nControl))
-       return 0;
-    s = strchr(nControl->response, '"');
-    if (s == NULL)
-       return 0;
-    s++;
-    while ((--l) && (*s) && (*s != '"'))
-       *b++ = *s++;
-    *b++ = '\0';
-    return 1;
-}
-\f
-/*
- * FtpXfer - issue a command and transfer data
- *
- * return 1 if successful, 0 otherwise
- */
-static int FtpXfer(FILE *local, const char *path,
-       netbuf *nControl, int typ, int mode)
-{
-    int l,c;
-    char *dbuf;
-    netbuf *nData;
-
-    if (local == NULL)
-       local = (typ == FTPLIB_FILE_WRITE) ? stdin : stdout;
-    if (!FtpAccess(path, typ, mode, nControl, &nData))
-       return 0;
-    dbuf = malloc(FTPLIB_BUFSIZ);
-    if (typ == FTPLIB_FILE_WRITE)
-    {
-       while ((l = fread(dbuf, 1, FTPLIB_BUFSIZ, local)) > 0)
-           if ((c = FtpWrite(dbuf, l, nData)) < l)
-               printf("short write: passed %d, wrote %d\n", l, c);
-    }
-    else
-    {
-       while ((l = FtpRead(dbuf, FTPLIB_BUFSIZ, nData)) > 0)
-           if (fwrite(dbuf, 1, l, local) <= 0)
-           {
-               perror("localfile write");
-               break;
-           }
-    }
-    free(dbuf);
-    fflush(local);
-    return FtpClose(nData, 1);
-}
-\f
-/*
- * FtpNlst - issue an NLST command and write response to output
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpNlst(FILE *outfp, const char *path, netbuf *nControl)
-{
-    return FtpXfer(outfp, path, nControl, FTPLIB_DIR, FTPLIB_ASCII);
-}
-\f
-/*
- * FtpDir - issue a LIST command and write response to output
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpDir(FILE *outfp, const char *path, netbuf *nControl)
-{
-    return FtpXfer(outfp, path, nControl, FTPLIB_DIR_VERBOSE, FTPLIB_ASCII);
-}
-\f
-/*
- * FtpSize - determine the size of a remote file
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpSize(const char *path, int *size, char mode, netbuf *nControl)
-{
-    char cmd[256];
-    int resp,sz,rv=1;
-
-    if ((strlen(path) + 7) > sizeof(cmd))
-        return 0;
-    sprintf(cmd, "TYPE %c", mode);
-    if (!FtpSendCmd(cmd, '2', nControl))
-       return 0;
-    sprintf(cmd,"SIZE %s",path);
-    if (!FtpSendCmd(cmd,'2',nControl))
-       rv = 0;
-    else
-    {
-       if (sscanf(nControl->response, "%d %d", &resp, &sz) == 2)
-           *size = sz;
-       else
-           rv = 0;
-    }   
-    return rv;
-}
-\f
-/*
- * FtpModDate - determine the modification date of a remote file
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpModDate(const char *path, char *dt, int max, netbuf *nControl)
-{
-    char buf[256];
-    int rv = 1;
-
-    if ((strlen(path) + 7) > sizeof(buf))
-        return 0;
-    sprintf(buf,"MDTM %s",path);
-    if (!FtpSendCmd(buf,'2',nControl))
-       rv = 0;
-    else
-       strncpy(dt, &nControl->response[4], max);
-    return rv;
-}
-\f
-/*
- * FtpGet - issue a GET command and write received data to output
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpGet(FILE *outfp, const char *path, char mode, netbuf *nControl)
-{
-    return FtpXfer(outfp, path, nControl, FTPLIB_FILE_READ, mode);
-}
-\f
-/*
- * FtpPut - issue a PUT command and send data from input
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpPut(FILE *infp, const char *path, char mode, netbuf *nControl)
-{
-    return FtpXfer(infp, path, nControl, FTPLIB_FILE_WRITE, mode);
-}
-\f
-/*
- * FtpRename - rename a file at remote
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpRename(const char *src, const char *dst, netbuf *nControl)
-{
-    char cmd[256];
-
-    if (((strlen(src) + 7) > sizeof(cmd)) ||
-        ((strlen(dst) + 7) > sizeof(cmd)))
-        return 0;
-    sprintf(cmd,"RNFR %s",src);
-    if (!FtpSendCmd(cmd,'3',nControl))
-       return 0;
-    sprintf(cmd,"RNTO %s",dst);
-    if (!FtpSendCmd(cmd,'2',nControl))
-       return 0;
-    return 1;
-}
-\f
-/*
- * FtpDelete - delete a file at remote
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF int FtpDelete(const char *fnm, netbuf *nControl)
-{
-    char cmd[256];
-
-    if ((strlen(fnm) + 7) > sizeof(cmd))
-        return 0;
-    sprintf(cmd,"DELE %s",fnm);
-    if (!FtpSendCmd(cmd,'2', nControl))
-       return 0;
-    return 1;
-}
-\f
-/*
- * FtpQuit - disconnect from remote
- *
- * return 1 if successful, 0 otherwise
- */
-GLOBALDEF void FtpQuit(netbuf *nControl)
-{
-    if (nControl->dir != FTPLIB_CONTROL)
-       return;
-    FtpSendCmd("QUIT",'2',nControl);
-    net_close(nControl->handle);
-    free(nControl->buf);
-    free(nControl);
-}
-
-#endif /* HAVE_FTP */
diff --git a/ext/ftp/ftplib.h b/ext/ftp/ftplib.h
deleted file mode 100644 (file)
index e71e18f..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/***************************************************************************/
-/*                                                                        */
-/* ftplib.h - header file for callable ftp access routines                 */
-/* Copyright (C) 1996, 1997 Thomas Pfau, pfau@cnj.digex.net                */
-/*     73 Catherine Street, South Bound Brook, NJ, 08880                  */
-/*                                                                        */
-/* This library is free software; you can redistribute it and/or          */
-/* modify it under the terms of the GNU Library General Public            */
-/* License as published by the Free Software Foundation; either                   */
-/* version 2 of the License, or (at your option) any later version.       */
-/*                                                                        */
-/* This library 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      */
-/* Library General Public License for more details.                       */
-/*                                                                        */
-/* You should have received a copy of the GNU Library General Public      */
-/* License along with this progam; if not, write to the                           */
-/* Free Software Foundation, Inc., 59 Temple Place - Suite 330,                   */
-/* Boston, MA 02111-1307, USA.                                            */
-/*                                                                        */
-/***************************************************************************/
-
-/* Adapted by Andrew Skalski <askalski@chek.com> for use with PHP. */
-
-#if !defined(__FTPLIB_H)
-#define __FTPLIB_H
-
-#if defined(__unix__) || defined(VMS)
-#define GLOBALDEF
-#define GLOBALREF extern
-#elif defined(_WIN32)
-#if defined BUILDING_LIBRARY
-#define GLOBALDEF __declspec(dllexport)
-#define GLOBALREF __declspec(dllexport)
-#else
-#define GLOBALREF __declspec(dllimport)
-#endif
-#endif
-
-/* FtpAccess() type codes */
-#define FTPLIB_DIR 1
-#define FTPLIB_DIR_VERBOSE 2
-#define FTPLIB_FILE_READ 3
-#define FTPLIB_FILE_WRITE 4
-
-/* FtpAccess() mode codes */
-#define FTPLIB_ASCII 'A'
-#define FTPLIB_IMAGE 'I'
-#define FTPLIB_TEXT FTPLIB_ASCII
-#define FTPLIB_BINARY FTPLIB_IMAGE
-
-/* connection modes */
-#define FTPLIB_PASSIVE 1
-#define FTPLIB_PORT 2
-
-/* connection option names */
-#define FTPLIB_CONNMODE 1
-#define FTPLIB_CALLBACK 2
-#define FTPLIB_IDLETIME 3
-#define FTPLIB_CALLBACKARG 4
-#define FTPLIB_CALLBACKBYTES 5
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct NetBuf netbuf;
-typedef int (*FtpCallback)(netbuf *nControl, int xfered, void *arg);
-
-#define        _FTPLIB_NO_COMPAT 1
-
-/* v1 compatibility stuff */
-#if !defined(_FTPLIB_NO_COMPAT)
-netbuf *DefaultNetbuf;
-
-#define ftplib_lastresp FtpLastResponse(DefaultNetbuf)
-#define ftpInit FtpInit
-#define ftpOpen(x) FtpConnect(x, &DefaultNetbuf)
-#define ftpLogin(x,y) FtpLogin(x, y, DefaultNetbuf)
-#define ftpSite(x) FtpSite(x, DefaultNetbuf)
-#define ftpMkdir(x) FtpMkdir(x, DefaultNetbuf)
-#define ftpChdir(x) FtpChdir(x, DefaultNetbuf)
-#define ftpRmdir(x) FtpRmdir(x, DefaultNetbuf)
-#define ftpNlst(x, y) FtpNlst(x, y, DefaultNetbuf)
-#define ftpDir(x, y) FtpDir(x, y, DefaultNetbuf)
-#define ftpGet(x, y, z) FtpGet(x, y, z, DefaultNetbuf)
-#define ftpPut(x, y, z) FtpPut(x, y, z, DefaultNetbuf)
-#define ftpRename(x, y) FtpRename(x, y, DefaultNetbuf)
-#define ftpDelete(x) FtpDelete(x, DefaultNetbuf)
-#define ftpQuit() FtpQuit(DefaultNetbuf)
-#endif /* (_FTPLIB_NO_COMPAT) */
-/* end v1 compatibility stuff */
-
-GLOBALREF int ftplib_debug;
-GLOBALREF void FtpInit(void);
-GLOBALREF char *FtpLastResponse(netbuf *nControl);
-GLOBALREF int FtpConnect(const char *host, netbuf **nControl);
-GLOBALREF int FtpOptions(int opt, long val, netbuf *nControl);
-GLOBALREF int FtpLogin(const char *user, const char *pass, netbuf *nControl);
-GLOBALREF int FtpAccess(const char *path, int typ, int mode, netbuf *nControl,
-    netbuf **nData);
-GLOBALREF int FtpRead(void *buf, int max, netbuf *nData);
-GLOBALREF int FtpWrite(void *buf, int len, netbuf *nData);
-GLOBALREF int FtpClose(netbuf *nData, int readResp);
-GLOBALREF int FtpSite(const char *cmd, netbuf *nControl);
-GLOBALREF int FtpSysType(char *buf, int max, netbuf *nControl);
-GLOBALREF int FtpMkdir(const char *path, netbuf *nControl);
-GLOBALREF int FtpChdir(const char *path, netbuf *nControl);
-GLOBALREF int FtpCDUp(netbuf *nControl);
-GLOBALREF int FtpRmdir(const char *path, netbuf *nControl);
-GLOBALREF int FtpPwd(char *path, int max, netbuf *nControl);
-GLOBALREF int FtpNlst(FILE *outfp, const char *path, netbuf *nControl);
-GLOBALREF int FtpDir(FILE *outfp, const char *path, netbuf *nControl);
-GLOBALREF int FtpSize(const char *path, int *size, char mode, netbuf *nControl);
-GLOBALREF int FtpModDate(const char *path, char *dt, int max, netbuf *nControl);
-GLOBALREF int FtpGet(FILE *outfp, const char *path, char mode,
-       netbuf *nControl);
-GLOBALREF int FtpPut(FILE *infp, const char *path, char mode,
-       netbuf *nControl);
-GLOBALREF int FtpRename(const char *src, const char *dst, netbuf *nControl);
-GLOBALREF int FtpDelete(const char *fnm, netbuf *nControl);
-GLOBALREF void FtpQuit(netbuf *nControl);
-
-#ifdef __cplusplus
-};
-#endif
-
-#endif /* __FTPLIB_H */
diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c
new file mode 100644 (file)
index 0000000..cd3b019
--- /dev/null
@@ -0,0 +1,631 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP HTML Embedded Scripting Language Version 3.0                     |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-1999 PHP Development Team (See Credits file)      |
+   +----------------------------------------------------------------------+
+   | This program is free software; you can redistribute it and/or modify |
+   | it under the terms of one of the following licenses:                 |
+   |                                                                      |
+   |  A) 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.                                               |
+   |                                                                      |
+   |  B) the PHP License as published by the PHP Development Team and     |
+   |     included in the distribution in the file: LICENSE                |
+   |                                                                      |
+   | 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 both licenses referred to here.   |
+   | If you did not, or have any questions about PHP licensing, please    |
+   | contact core@php.net.                                                |
+   +----------------------------------------------------------------------+
+   | Authors:                                                             |
+   |          Andrew Skalski      <askalski@chek.com>                     |
+   +----------------------------------------------------------------------+
+ */
+
+#include "php.h"
+#include "php_globals.h"
+
+#if HAVE_FTP
+
+#include "php_ftp.h"
+#include "ftp.h"
+
+static int     le_ftpbuf;
+
+
+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_ftpbuf(ftpbuf_t *ftp)
+{
+       ftp_close(ftp);
+}
+
+PHP_MINIT_FUNCTION(ftp)
+{
+       le_ftpbuf = register_list_destructors(ftp_destructor_ftpbuf, NULL);
+       REGISTER_MAIN_LONG_CONSTANT("FTP_ASCII", FTPTYPE_ASCII,
+               CONST_PERSISTENT | CONST_CS);
+       REGISTER_MAIN_LONG_CONSTANT("FTP_BINARY", FTPTYPE_IMAGE,
+               CONST_PERSISTENT | CONST_CS);
+       REGISTER_MAIN_LONG_CONSTANT("FTP_IMAGE", FTPTYPE_IMAGE,
+               CONST_PERSISTENT | CONST_CS);
+       REGISTER_MAIN_LONG_CONSTANT("FTP_TEXT", FTPTYPE_ASCII,
+               CONST_PERSISTENT | CONST_CS);
+       return SUCCESS;
+}
+
+/* {{{ proto int ftp_connect(string host)
+   Open a FTP stream */
+PHP_FUNCTION(ftp_connect)
+{
+       pval            *arg1;
+       int             id;
+       ftpbuf_t        *ftp;
+
+       /* arg1 - hostname
+        */
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_string(arg1);
+
+       /* connect */
+       ftp = ftp_open(arg1->value.str.val, 0);
+       if (ftp == NULL) {
+               php_error(E_WARNING, "ftp_connect: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+
+       id = php3_list_insert(ftp, le_ftpbuf);
+       RETURN_LONG(id);
+}
+/* }}} */
+
+/* {{{ 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;
+       ftpbuf_t        *ftp;
+
+       /* arg1 - ftp
+        * arg2 - username
+        * arg3 - password
+        */
+       if (    ARG_COUNT(ht) != 3 ||
+               getParameters(ht, 3, &arg1, &arg2, &arg3) == FAILURE)
+       {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+       convert_to_string(arg3);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       /* log in */
+       if (!ftp_login(ftp, arg2->value.str.val, arg3->value.str.val)) {
+               php_error(E_WARNING, "ftp_login: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string ftp_pwd(int stream)
+   Returns the present working directory. */
+PHP_FUNCTION(ftp_pwd)
+{
+       pval            *arg1;
+       int             id, type;
+       ftpbuf_t        *ftp;
+       const char      *pwd;
+
+       /* arg1 - ftp
+        */
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       pwd = ftp_pwd(ftp);
+       if (pwd == NULL) {
+               php_error(E_WARNING, "ftp_pwd: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+
+       RETURN_STRING((char*) pwd, 1);
+}
+/* }}} */
+
+/* {{{ proto int ftp_cdup(int stream)
+   Changes to the parent directory */
+PHP_FUNCTION(ftp_cdup)
+{
+       pval            *arg1;
+       int             id, type;
+       ftpbuf_t        *ftp;
+
+       /* arg1 - ftp
+        */
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       if (!ftp_cdup(ftp)) {
+               php_error(E_WARNING, "ftp_cdup: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int ftp_chdir(int stream, string directory)
+   Changes directories */
+PHP_FUNCTION(ftp_chdir)
+{
+       pval            *arg1, *arg2;
+       int             id, type;
+       ftpbuf_t        *ftp;
+
+       /* arg1 - ftp
+        * arg2 - directory
+        */
+       if (    ARG_COUNT(ht) != 2 ||
+               getParameters(ht, 2, &arg1, &arg2) == FAILURE)
+       {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       /* change directories */
+       if (!ftp_chdir(ftp, arg2->value.str.val)) {
+               php_error(E_WARNING, "ftp_chdir: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string ftp_mkdir(int stream, string directory)
+   Creates a directory */
+PHP_FUNCTION(ftp_mkdir)
+{
+       pval            *arg1, *arg2;
+       int             id, type;
+       ftpbuf_t        *ftp;
+       char            *ret, *tmp;
+
+       /* arg1 - ftp
+        * arg2 - directory
+        */
+       if (    ARG_COUNT(ht) != 2 ||
+               getParameters(ht, 2, &arg1, &arg2) == FAILURE)
+       {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       /* change directories */
+       tmp = ftp_mkdir(ftp, arg2->value.str.val);
+       if (tmp == NULL) {
+               php_error(E_WARNING, "ftp_mkdir: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+
+       if ((ret = estrdup(tmp)) == NULL) {
+               free(tmp);
+               php_error(E_WARNING, "estrdup failed");
+               RETURN_FALSE;
+       }
+
+       RETURN_STRING(ret, 0);
+}
+/* }}} */
+
+/* {{{ proto int ftp_rmdir(int stream, string directory)
+   Removes a directory */
+PHP_FUNCTION(ftp_rmdir)
+{
+       pval            *arg1, *arg2;
+       int             id, type;
+       ftpbuf_t        *ftp;
+
+       /* arg1 - ftp
+        * arg2 - directory
+        */
+       if (    ARG_COUNT(ht) != 2 ||
+               getParameters(ht, 2, &arg1, &arg2) == FAILURE)
+       {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       /* change directories */
+       if (!ftp_rmdir(ftp, arg2->value.str.val)) {
+               php_error(E_WARNING, "ftp_rmdir: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto array ftp_nlist(int stream, string directory)
+   Returns an array of filenames in the given directory */
+PHP_FUNCTION(ftp_nlist)
+{
+       pval            *arg1, *arg2;
+       int             id, type;
+       ftpbuf_t        *ftp;
+       char            **nlist, **ptr;
+
+       /* arg1 - ftp
+        * arg2 - directory
+        */
+       if (    ARG_COUNT(ht) != 2 ||
+               getParameters(ht, 2, &arg1, &arg2) == FAILURE)
+       {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       /* get list of files */
+       nlist = ftp_nlist(ftp, arg2->value.str.val);
+       if (nlist == NULL) {
+               RETURN_FALSE;
+       }
+
+       array_init(return_value);
+       for (ptr = nlist; *ptr; ptr++)
+               add_next_index_string(return_value, *ptr, 1);
+       free(nlist);
+}
+/* }}} */
+
+/* {{{ 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)
+{
+       pval            *arg1, *arg2;
+       int             id, type;
+       ftpbuf_t        *ftp;
+       char            **llist, **ptr;
+
+       /* arg1 - ftp
+        * arg2 - directory
+        */
+       if (    ARG_COUNT(ht) != 2 ||
+               getParameters(ht, 2, &arg1, &arg2) == FAILURE)
+       {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       /* get directory listing */
+       llist = ftp_list(ftp, arg2->value.str.val);
+       if (llist == NULL) {
+               RETURN_FALSE;
+       }
+
+       array_init(return_value);
+       for (ptr = llist; *ptr; ptr++)
+               add_next_index_string(return_value, *ptr, 1);
+       free(llist);
+}
+/* }}} */
+
+/* {{{ proto string ftp_systype(int stream)
+   Returns the system type identifier */
+PHP_FUNCTION(ftp_systype)
+{
+       pval            *arg1;
+       int             id, type;
+       ftpbuf_t        *ftp;
+       const char      *syst;
+
+
+       /* arg1 - ftp
+        * arg2 - directory
+        */
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       syst = ftp_syst(ftp);
+       if (syst == NULL) {
+               php_error(E_WARNING, "ftp_syst: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+
+       RETURN_STRING((char*) syst, 1);
+}
+/* }}} */
+
+/* {{{ 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)
+{
+       pval            *arg1, *arg2, *arg3, *arg4;
+       int             id, type;
+       ftpbuf_t        *ftp;
+       ftptype_t       xtype;
+       FILE            *outfp, *tmpfp;
+       int             ch;
+
+
+       /* arg1 - ftp
+        * 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;
+       }
+
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+       convert_to_string(arg3);
+       convert_to_long(arg4);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       if (    arg4->value.lval != FTPTYPE_ASCII &&
+               arg4->value.lval != FTPTYPE_IMAGE)
+       {
+               php_error(E_WARNING, "arg4 must be FTP_ASCII or FTP_IMAGE");
+               RETURN_FALSE;
+       }
+
+       xtype = arg4->value.lval;
+
+       /* 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;
+       }
+
+       if (    !ftp_get(ftp, tmpfp, arg3->value.str.val, xtype) ||
+               ferror(tmpfp))
+       {
+               fclose(tmpfp);
+               php_error(E_WARNING, "ftp_get: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+
+       if ((outfp = fopen(arg2->value.str.val, "w")) == NULL) {
+               fclose(tmpfp);
+               php_error(E_WARNING, "error opening %s", arg2->value.str.val);
+               RETURN_FALSE;
+       }
+
+       rewind(tmpfp);
+       while ((ch = getc(tmpfp)) != EOF)
+               putc(ch, outfp);
+
+       if (ferror(tmpfp) || ferror(outfp)) {
+               fclose(tmpfp);
+               fclose(outfp);
+               php_error(E_WARNING, "error writing %s", arg2->value.str.val);
+               RETURN_FALSE;
+       }
+
+       fclose(tmpfp);
+       fclose(outfp);
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ 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)
+{
+       pval            *arg1, *arg2, *arg3, *arg4;
+       int             id, type;
+       ftpbuf_t        *ftp;
+       ftptype_t       xtype;
+       FILE            *infp;
+
+
+       /* arg1 - ftp
+        * 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;
+       }
+
+       convert_to_long(arg1);
+       convert_to_string(arg2);
+       convert_to_string(arg3);
+       convert_to_long(arg4);
+
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       if (    arg4->value.lval != FTPTYPE_ASCII &&
+               arg4->value.lval != FTPTYPE_IMAGE)
+       {
+               php_error(E_WARNING, "arg4 must be FTP_ASCII or FTP_IMAGE");
+               RETURN_FALSE;
+       }
+
+       xtype = arg4->value.lval;
+
+       if ((infp = fopen(arg3->value.str.val, "r")) == NULL) {
+               php_error(E_WARNING, "error opening %s", arg3->value.str.val);
+               RETURN_FALSE;
+       }
+       if (    !ftp_put(ftp, arg2->value.str.val, infp, xtype) ||
+               ferror(infp))
+       {
+               fclose(infp);
+               php_error(E_WARNING, "ftp_put: %s", ftp->inbuf);
+               RETURN_FALSE;
+       }
+       fclose(infp);
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int ftp_quit(int stream)
+   Closes the FTP stream */
+PHP_FUNCTION(ftp_quit)
+{
+       pval            *arg1;
+       int             id, type;
+       ftpbuf_t        *ftp;
+
+       /* arg1 - ftp
+        */
+       if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg1) == FAILURE) {
+               WRONG_PARAM_COUNT;
+       }
+
+       convert_to_long(arg1);
+       id = arg1->value.lval;
+       ftp = php3_list_find(id, &type);
+       if (!ftp || type != le_ftpbuf) {
+               php_error(E_WARNING, "Unable to find ftpbuf %d", id);
+               RETURN_FALSE;
+       }
+
+       php3_list_delete(id);
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+#endif /* HAVE_FTP */
diff --git a/ext/ftp/php_ftp.h b/ext/ftp/php_ftp.h
new file mode 100644 (file)
index 0000000..1a71ba7
--- /dev/null
@@ -0,0 +1,38 @@
+/* $Id$ */
+
+#ifndef        _INCLUDED_FTP_H
+#define        _INCLUDED_FTP_H
+
+#if COMPILE_DL
+#undef HAVE_FTP
+#define HAVE_FTP 1
+#endif
+
+#if HAVE_FTP
+
+extern php3_module_entry php3_ftp_module_entry;
+#define php3_ftp_module_ptr &php3_ftp_module_entry
+
+extern PHP_MINIT_FUNCTION(ftp);
+
+PHP_FUNCTION(ftp_connect);
+PHP_FUNCTION(ftp_login);
+PHP_FUNCTION(ftp_pwd);
+PHP_FUNCTION(ftp_cdup);
+PHP_FUNCTION(ftp_chdir);
+PHP_FUNCTION(ftp_mkdir);
+PHP_FUNCTION(ftp_rmdir);
+PHP_FUNCTION(ftp_nlist);
+PHP_FUNCTION(ftp_listraw);
+PHP_FUNCTION(ftp_systype);
+PHP_FUNCTION(ftp_get);
+PHP_FUNCTION(ftp_put);
+PHP_FUNCTION(ftp_quit);
+
+#define phpext_ftp_ptr php3_ftp_module_ptr
+
+#else
+#define php3_ftp_module_ptr NULL
+#endif /* HAVE_FTP */
+
+#endif