1999-09-16 15:57:51 +00:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| 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> |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
1999-09-22 16:07:41 +00:00
|
|
|
/* $Id$ */
|
|
|
|
|
1999-09-16 15:57:51 +00:00
|
|
|
#include "php.h"
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
#if HAVE_FTP
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netdb.h>
|
1999-09-16 15:57:51 +00:00
|
|
|
#include "ftp.h"
|
|
|
|
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* reads an ftp response, returns true on success, false on error */
|
|
|
|
static int ftp_getresp(ftpbuf_t *ftp);
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* sets the ftp transfer type */
|
|
|
|
static int ftp_type(ftpbuf_t *ftp, ftptype_t type);
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* 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);
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* 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)
|
1999-09-16 15:57:51 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
memcpy(&addr.sin_addr, he->h_addr, he->h_length);
|
1999-09-21 23:34:45 +00:00
|
|
|
addr.sin_family = AF_INET;
|
1999-09-20 14:10:25 +00:00
|
|
|
addr.sin_port = port ? port : htons(21);
|
|
|
|
|
|
|
|
|
|
|
|
/* alloc the ftp structure */
|
|
|
|
ftp = calloc(1, sizeof(*ftp));
|
|
|
|
if (ftp == NULL) {
|
|
|
|
perror("calloc");
|
|
|
|
return NULL;
|
|
|
|
}
|
1999-09-16 15:57:51 +00:00
|
|
|
|
|
|
|
/* connect */
|
1999-09-20 14:10:25 +00:00
|
|
|
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
|
|
|
|
perror("socket");
|
|
|
|
goto bail;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (connect(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
|
|
|
|
perror("connect");
|
|
|
|
goto bail;
|
|
|
|
}
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
size = sizeof(addr);
|
|
|
|
if (getsockname(fd, (struct sockaddr*) &addr, &size) == -1) {
|
|
|
|
perror("getsockname");
|
|
|
|
goto bail;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
ftp->localaddr = addr.sin_addr;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if ((ftp->fp = fdopen(fd, "r+")) == NULL) {
|
|
|
|
perror("fdopen");
|
|
|
|
goto bail;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (!ftp_getresp(ftp) || ftp->resp != 220) {
|
|
|
|
goto bail;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
return ftp;
|
|
|
|
|
|
|
|
bail:
|
|
|
|
if (ftp->fp)
|
|
|
|
fclose(ftp->fp);
|
|
|
|
else if (fd != -1)
|
|
|
|
close(fd);
|
|
|
|
free(ftp);
|
|
|
|
return NULL;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
ftpbuf_t*
|
|
|
|
ftp_close(ftpbuf_t *ftp)
|
1999-09-16 19:03:27 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ftp == NULL)
|
|
|
|
return NULL;
|
|
|
|
if (ftp->fp)
|
|
|
|
fclose(ftp->fp);
|
|
|
|
ftp_gc(ftp);
|
|
|
|
free(ftp);
|
|
|
|
return NULL;
|
|
|
|
}
|
1999-09-16 19:03:27 +00:00
|
|
|
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
void
|
|
|
|
ftp_gc(ftpbuf_t *ftp)
|
|
|
|
{
|
|
|
|
if (ftp == NULL)
|
|
|
|
return;
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
free(ftp->pwd);
|
|
|
|
ftp->pwd = NULL;
|
|
|
|
free(ftp->syst);
|
|
|
|
ftp->syst = NULL;
|
|
|
|
}
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
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;
|
1999-09-16 19:03:27 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
ftp_login(ftpbuf_t *ftp, const char *user, const char *pass)
|
1999-09-16 19:03:27 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
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);
|
|
|
|
}
|
1999-09-16 19:03:27 +00:00
|
|
|
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
int
|
|
|
|
ftp_reinit(ftpbuf_t *ftp)
|
|
|
|
{
|
|
|
|
if (ftp == NULL)
|
|
|
|
return 0;
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
ftp_gc(ftp);
|
|
|
|
|
|
|
|
fprintf(ftp->fp, "REIN\r\n");
|
|
|
|
if (!ftp_getresp(ftp) || ftp->resp != 220)
|
|
|
|
return 0;
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
return 1;
|
1999-09-16 19:03:27 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
const char*
|
|
|
|
ftp_syst(ftpbuf_t *ftp)
|
1999-09-16 15:57:51 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
char *syst, *end;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ftp == NULL)
|
|
|
|
return NULL;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* default to cached value */
|
|
|
|
if (ftp->syst)
|
|
|
|
return ftp->syst;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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 = ' ';
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
return ftp->syst;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
const char*
|
|
|
|
ftp_pwd(ftpbuf_t *ftp)
|
1999-09-16 19:03:27 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
char *pwd, *end;
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ftp == NULL)
|
|
|
|
return NULL;
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* default to cached value */
|
|
|
|
if (ftp->pwd)
|
|
|
|
return ftp->pwd;
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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 = '"';
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
return ftp->pwd;
|
1999-09-16 19:03:27 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
ftp_chdir(ftpbuf_t *ftp, const char *dir)
|
1999-09-16 19:03:27 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ftp == NULL)
|
|
|
|
return 0;
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
free(ftp->pwd);
|
|
|
|
ftp->pwd = NULL;
|
1999-09-16 19:03:27 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
fprintf(ftp->fp, "CWD %s\r\n", dir);
|
|
|
|
if (!ftp_getresp(ftp) || ftp->resp != 250)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
1999-09-16 19:03:27 +00:00
|
|
|
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
1999-09-16 19:03:27 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
char*
|
|
|
|
ftp_mkdir(ftpbuf_t *ftp, const char *dir)
|
1999-09-16 15:57:51 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
char *mkd, *end;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ftp == NULL)
|
|
|
|
return NULL;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
fprintf(ftp->fp, "MKD %s\r\n", dir);
|
|
|
|
if (!ftp_getresp(ftp) || ftp->resp != 257)
|
|
|
|
return NULL;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* copy out the dir from response */
|
|
|
|
if ((mkd = strchr(ftp->inbuf, '"')) == NULL)
|
|
|
|
return NULL;
|
|
|
|
end = strrchr(++mkd, '"');
|
|
|
|
*end = 0;
|
|
|
|
mkd = strdup(mkd);
|
|
|
|
*end = '"';
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
return mkd;
|
|
|
|
}
|
1999-09-16 15:57:51 +00:00
|
|
|
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
int
|
|
|
|
ftp_rmdir(ftpbuf_t *ftp, const char *dir)
|
|
|
|
{
|
|
|
|
if (ftp == NULL)
|
|
|
|
return 0;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
fprintf(ftp->fp, "RMD %s\r\n", dir);
|
|
|
|
if (!ftp_getresp(ftp) || ftp->resp != 250)
|
|
|
|
return 0;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
return 1;
|
|
|
|
}
|
1999-09-16 15:57:51 +00:00
|
|
|
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
char**
|
|
|
|
ftp_nlist(ftpbuf_t *ftp, const char *path)
|
|
|
|
{
|
|
|
|
return ftp_genlist(ftp, "NLST", path);
|
|
|
|
}
|
|
|
|
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
char**
|
|
|
|
ftp_list(ftpbuf_t *ftp, const char *path)
|
|
|
|
{
|
|
|
|
return ftp_genlist(ftp, "LIST", path);
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
ftp_getresp(ftpbuf_t *ftp)
|
1999-09-16 18:38:11 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
char tag[4];
|
|
|
|
int ch;
|
|
|
|
char *buf;
|
1999-09-16 18:38:11 +00:00
|
|
|
char *ptr;
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ftp == NULL)
|
|
|
|
return 0;
|
|
|
|
buf = ftp->inbuf;
|
|
|
|
ftp->resp = 0;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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] == '-');
|
1999-09-16 18:38:11 +00:00
|
|
|
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* translate the tag */
|
|
|
|
if (!isdigit(tag[0]) || !isdigit(tag[1]) || !isdigit(tag[2]))
|
|
|
|
return 0;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
ftp->resp = 100 * (tag[0] - '0') +
|
|
|
|
10 * (tag[1] - '0') +
|
|
|
|
(tag[2] - '0');
|
|
|
|
return 1;
|
|
|
|
}
|
1999-09-16 18:38:11 +00:00
|
|
|
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
int
|
|
|
|
ftp_type(ftpbuf_t *ftp, ftptype_t type)
|
|
|
|
{
|
|
|
|
char typechar;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ftp == NULL)
|
|
|
|
return 0;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (type == ftp->type)
|
|
|
|
return 1;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
ftp->type = type;
|
|
|
|
|
|
|
|
return 1;
|
1999-09-16 18:38:11 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
ftp_get(ftpbuf_t *ftp, FILE *outfp, const char *path, ftptype_t type)
|
1999-09-16 18:38:11 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
databuf_t *data = NULL;
|
|
|
|
int ch, lastch;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ftp == NULL)
|
|
|
|
return 0;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (!ftp_type(ftp, type))
|
|
|
|
goto bail;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if ((data = ftp_port(ftp)) == NULL)
|
|
|
|
goto bail;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
fprintf(ftp->fp, "RETR %s\r\n", path);
|
|
|
|
if (!ftp_getresp(ftp) || ftp->resp != 150)
|
|
|
|
goto bail;
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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);
|
|
|
|
}
|
1999-09-16 18:38:11 +00:00
|
|
|
}
|
1999-09-20 14:10:25 +00:00
|
|
|
if (type == FTPTYPE_ASCII && lastch == '\r')
|
|
|
|
putc('\r', outfp);
|
|
|
|
|
|
|
|
if (ferror(data->fp) || ferror(outfp))
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
data = data_close(data);
|
1999-09-16 18:38:11 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (!ftp_getresp(ftp) || ftp->resp != 226)
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
bail:
|
|
|
|
data_close(data);
|
|
|
|
return 0;
|
1999-09-16 18:38:11 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
ftp_put(ftpbuf_t *ftp, const char *path, FILE *infp, ftptype_t type)
|
1999-09-16 15:57:51 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
databuf_t *data = NULL;
|
|
|
|
int ch;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ftp == NULL)
|
|
|
|
return 0;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (!ftp_type(ftp, type))
|
|
|
|
goto bail;
|
|
|
|
|
|
|
|
if ((data = ftp_port(ftp)) == NULL)
|
|
|
|
goto bail;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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);
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
1999-09-20 14:10:25 +00:00
|
|
|
data->listener = -1;
|
|
|
|
data->type = ftp->type;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* bind/listen */
|
|
|
|
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
|
|
|
|
perror("socket");
|
|
|
|
goto bail;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
/* bind to a local address */
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
1999-09-21 23:34:45 +00:00
|
|
|
addr.sin_family = AF_INET;
|
1999-09-20 14:10:25 +00:00
|
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
addr.sin_port = 0;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (bind(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
|
|
|
|
perror("bind");
|
|
|
|
goto bail;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
size = sizeof(addr);
|
|
|
|
if (getsockname(fd, (struct sockaddr*) &addr, &size) == -1) {
|
|
|
|
perror("getsockname");
|
|
|
|
goto bail;
|
|
|
|
}
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (listen(fd, 5) == -1) {
|
|
|
|
perror("listen");
|
|
|
|
goto bail;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
bail:
|
|
|
|
if (fd != -1)
|
|
|
|
close(fd);
|
|
|
|
free(data);
|
|
|
|
return NULL;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
databuf_t*
|
|
|
|
data_accept(databuf_t *data)
|
1999-09-16 15:57:51 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
struct sockaddr_in addr;
|
|
|
|
int size;
|
|
|
|
int fd;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
size = sizeof(addr);
|
|
|
|
fd = accept(data->listener, (struct sockaddr*) &addr, &size);
|
|
|
|
close(data->listener);
|
|
|
|
data->listener = -1;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (fd == -1) {
|
|
|
|
free(data);
|
|
|
|
return NULL;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if ((data->fp = fdopen(fd, "r+")) == NULL) {
|
|
|
|
close(fd);
|
|
|
|
free(data);
|
|
|
|
return NULL;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
|
|
|
|
char**
|
|
|
|
ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path)
|
1999-09-16 15:57:51 +00:00
|
|
|
{
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
1999-09-20 14:10:25 +00:00
|
|
|
*entry = NULL;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
if (ferror(tmpfp))
|
|
|
|
goto bail;
|
1999-09-16 15:57:51 +00:00
|
|
|
|
1999-09-20 14:10:25 +00:00
|
|
|
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;
|
1999-09-16 15:57:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_FTP */
|