summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libfetch/fetch.36
-rw-r--r--lib/libfetch/ftp.c175
2 files changed, 132 insertions, 49 deletions
diff --git a/lib/libfetch/fetch.3 b/lib/libfetch/fetch.3
index c5d50bf..0c6aa7d 100644
--- a/lib/libfetch/fetch.3
+++ b/lib/libfetch/fetch.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $Id: fetch.3,v 1.4 1998/11/06 22:14:08 des Exp $
+.\" $Id: fetch.3,v 1.5 1998/12/16 10:24:54 des Exp $
.\"
.Dd July 1, 1998
.Dt FETCH 3
@@ -108,7 +108,8 @@ structure is defined as follows in
.Bd -literal
struct url_stat {
off_t size;
- time_t time;
+ time_t atime;
+ time_t mtime;
};
.Ed
.Pp
@@ -330,7 +331,6 @@ This manual page was written by
Some parts of the library are not yet implemented. The most notable
examples of this are
.Fn fetchPutHTTP ,
-.Fn fetchStatFTP ,
.Fn fetchStatHTTP
and FTP proxy support.
.Pp
diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c
index 3fe7181..2d05424 100644
--- a/lib/libfetch/ftp.c
+++ b/lib/libfetch/ftp.c
@@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: ftp.c,v 1.8 1998/12/16 10:24:55 des Exp $
+ * $Id: ftp.c,v 1.9 1998/12/16 11:44:31 des Exp $
*/
/*
@@ -64,6 +64,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include "fetch.h"
@@ -76,6 +77,7 @@
#define FTP_OPEN_DATA_CONNECTION 150
#define FTP_OK 200
+#define FTP_FILE_STATUS 213
#define FTP_SERVICE_READY 220
#define FTP_PASSIVE_MODE 227
#define FTP_LOGGED_IN 230
@@ -88,7 +90,7 @@
static struct url cached_host;
static FILE *cached_socket;
-static char *_ftp_last_reply;
+static char _ftp_last_reply[1024];
/*
* Get server response, check that first digit is a '2'
@@ -104,17 +106,20 @@ _ftp_chkerr(FILE *s)
_fetch_syserr();
return -1;
}
- } while (line[3] == '-');
+ } while (len >= 4 && line[3] == '-');
- _ftp_last_reply = line;
+ while (len && isspace(line[len-1]))
+ len--;
+ snprintf(_ftp_last_reply, sizeof(_ftp_last_reply),
+ "%*.*s", (int)len, (int)len, line);
#ifndef NDEBUG
fprintf(stderr, "\033[1m<<< ");
- fprintf(stderr, "%*.*s", (int)len, (int)len, line);
+ fprintf(stderr, "%*.*s\n", (int)len, (int)len, line);
fprintf(stderr, "\033[m");
#endif
- if (!isdigit(line[1]) || !isdigit(line[1])
+ if (len < 4 || !isdigit(line[1]) || !isdigit(line[1])
|| !isdigit(line[2]) || (line[3] != ' ')) {
return -1;
}
@@ -149,21 +154,24 @@ static FILE *
_ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv)
{
struct sockaddr_in sin;
- int sd = -1, l;
+ int e, sd = -1, l;
char *s;
FILE *df;
/* change directory */
if (((s = strrchr(file, '/')) != NULL) && (s != file)) {
*s = 0;
- if (_ftp_cmd(cf, "CWD %s" ENDL, file) != FTP_FILE_ACTION_OK) {
+ if ((e = _ftp_cmd(cf, "CWD %s" ENDL, file)) != FTP_FILE_ACTION_OK) {
*s = '/';
+ _ftp_seterr(e);
return NULL;
}
*s++ = '/';
} else {
- if (_ftp_cmd(cf, "CWD /" ENDL) != FTP_FILE_ACTION_OK)
+ if ((e = _ftp_cmd(cf, "CWD /" ENDL)) != FTP_FILE_ACTION_OK) {
+ _ftp_seterr(e);
return NULL;
+ }
}
/* s now points to file name */
@@ -180,7 +188,7 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv)
int i;
/* send PASV command */
- if (_ftp_cmd(cf, "PASV" ENDL) != FTP_PASSIVE_MODE)
+ if ((e = _ftp_cmd(cf, "PASV" ENDL)) != FTP_PASSIVE_MODE)
goto ouch;
/* find address and port number. The reply to the PASV command
@@ -205,7 +213,8 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv)
goto sysouch;
/* make the server initiate the transfer */
- if (_ftp_cmd(cf, "%s %s" ENDL, oper, s) != FTP_OPEN_DATA_CONNECTION)
+ e = _ftp_cmd(cf, "%s %s" ENDL, oper, s);
+ if (e != FTP_OPEN_DATA_CONNECTION)
goto ouch;
} else {
@@ -228,13 +237,16 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv)
goto sysouch;
a = ntohl(sin.sin_addr.s_addr);
p = ntohs(sin.sin_port);
- if (_ftp_cmd(cf, "PORT %d,%d,%d,%d,%d,%d" ENDL,
- (a >> 24) & 0xff, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff,
- (p >> 8) & 0xff, p & 0xff) != FTP_OK)
+ e = _ftp_cmd(cf, "PORT %d,%d,%d,%d,%d,%d" ENDL,
+ (a >> 24) & 0xff, (a >> 16) & 0xff,
+ (a >> 8) & 0xff, a & 0xff,
+ (p >> 8) & 0xff, p & 0xff);
+ if (e != FTP_OK)
goto ouch;
/* make the server initiate the transfer */
- if (_ftp_cmd(cf, "%s %s" ENDL, oper, s) != FTP_OPEN_DATA_CONNECTION)
+ e = _ftp_cmd(cf, "%s %s" ENDL, oper, s);
+ if (e != FTP_OPEN_DATA_CONNECTION)
goto ouch;
/* accept the incoming connection and go to town */
@@ -250,7 +262,11 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv)
sysouch:
_fetch_syserr();
+ close(sd);
+ return NULL;
+
ouch:
+ _ftp_seterr(e);
close(sd);
return NULL;
}
@@ -290,14 +306,13 @@ _ftp_connect(char *host, int port, char *user, char *pwd, int verbose)
/* streams make life easier */
if ((f = fdopen(sd, "r+")) == NULL) {
_fetch_syserr();
- goto ouch;
+ close(sd);
+ return NULL;
}
/* expect welcome message */
- if ((e = _ftp_chkerr(f)) != FTP_SERVICE_READY) {
- _ftp_seterr(e);
+ if ((e = _ftp_chkerr(f)) != FTP_SERVICE_READY)
goto fouch;
- }
/* send user name and password */
if (!user || !*user)
@@ -313,32 +328,26 @@ _ftp_connect(char *host, int port, char *user, char *pwd, int verbose)
}
/* did the server request an account? */
- if (e == FTP_NEED_ACCOUNT) {
- _ftp_seterr(e);
+ if (e == FTP_NEED_ACCOUNT)
goto fouch;
- }
/* we should be done by now */
- if (e != FTP_LOGGED_IN) {
- _ftp_seterr(e);
+ if (e != FTP_LOGGED_IN)
goto fouch;
- }
/* might as well select mode and type at once */
#ifdef FTP_FORCE_STREAM_MODE
- if (_ftp_cmd(f, "MODE S" ENDL) != FTP_OK) /* default is S */
- goto ouch;
+ if ((e = _ftp_cmd(f, "MODE S" ENDL)) != FTP_OK) /* default is S */
+ goto fouch;
#endif
- if (_ftp_cmd(f, "TYPE I" ENDL) != FTP_OK) /* default is A */
- goto ouch;
+ if ((e = _ftp_cmd(f, "TYPE I" ENDL)) != FTP_OK) /* default is A */
+ goto fouch;
/* done */
return f;
-ouch:
- close(sd);
- return NULL;
fouch:
+ _ftp_seterr(e);
fclose(f);
return NULL;
}
@@ -367,20 +376,22 @@ _ftp_isconnected(struct url *url)
}
/*
- * FTP session
+ * Check the cache, reconnect if no luck
*/
static FILE *
-fetchXxxFTP(struct url *url, char *oper, char *mode, char *flags)
+_ftp_cached_connect(struct url *url, char *flags)
{
- FILE *cf = NULL;
+ FILE *cf;
+ cf = NULL;
+
/* set default port */
if (!url->port)
url->port = FTP_DEFAULT_PORT;
/* try to use previously cached connection */
if (_ftp_isconnected(url))
- if (_ftp_cmd(cached_socket, "NOOP" ENDL) > 0)
+ if (_ftp_cmd(cached_socket, "NOOP" ENDL) != -1)
cf = cached_socket;
/* connect to server */
@@ -395,32 +406,104 @@ fetchXxxFTP(struct url *url, char *oper, char *mode, char *flags)
memcpy(&cached_host, url, sizeof(struct url));
}
- /* initiate the transfer */
- return _ftp_transfer(cf, oper, url->doc, mode,
- (flags && strchr(flags, 'p')));
+ return cf;
}
/*
- * Itsy bitsy teeny weenie
+ * Get file
*/
FILE *
fetchGetFTP(struct url *url, char *flags)
{
- return fetchXxxFTP(url, "RETR", "r", flags);
+ FILE *cf;
+
+ /* connect to server */
+ if ((cf = _ftp_cached_connect(url, flags)) == NULL)
+ return NULL;
+
+ /* initiate the transfer */
+ return _ftp_transfer(cf, "RETR", url->doc, "r",
+ (flags && strchr(flags, 'p')));
}
+/*
+ * Put file
+ */
FILE *
fetchPutFTP(struct url *url, char *flags)
{
- if (flags && strchr(flags, 'a'))
- return fetchXxxFTP(url, "APPE", "w", flags);
- else return fetchXxxFTP(url, "STOR", "w", flags);
+ FILE *cf;
+
+ /* connect to server */
+ if ((cf = _ftp_cached_connect(url, flags)) == NULL)
+ return NULL;
+
+ /* initiate the transfer */
+ return _ftp_transfer(cf, (flags && strchr(flags, 'a')) ? "APPE" : "STOR",
+ url->doc, "w", (flags && strchr(flags, 'p')));
}
-extern void warnx(char *fmt, ...);
+/*
+ * Get file stats
+ */
int
fetchStatFTP(struct url *url, struct url_stat *us, char *flags)
{
- warnx("fetchStatFTP(): not implemented");
+ FILE *cf;
+ char *ln, *s;
+ struct tm tm;
+ time_t t;
+ int e;
+
+ /* connect to server */
+ if ((cf = _ftp_cached_connect(url, flags)) == NULL)
+ return -1;
+
+ /* change directory */
+ if (((s = strrchr(url->doc, '/')) != NULL) && (s != url->doc)) {
+ *s = 0;
+ if ((e = _ftp_cmd(cf, "CWD %s" ENDL, url->doc)) != FTP_FILE_ACTION_OK) {
+ *s = '/';
+ goto ouch;
+ }
+ *s++ = '/';
+ } else {
+ if ((e = _ftp_cmd(cf, "CWD /" ENDL)) != FTP_FILE_ACTION_OK)
+ goto ouch;
+ }
+
+ /* s now points to file name */
+
+ if (_ftp_cmd(cf, "SIZE %s" ENDL, s) != FTP_FILE_STATUS)
+ goto ouch;
+ for (ln = _ftp_last_reply + 4; *ln && isspace(*ln); ln++)
+ /* nothing */ ;
+ for (us->size = 0; *ln && isdigit(*ln); ln++)
+ us->size = us->size * 10 + *ln - '0';
+ if (*ln && !isspace(*ln)) {
+ _ftp_seterr(999); /* XXX should signal a FETCH_PROTO error */
+ return -1;
+ }
+
+ if ((e = _ftp_cmd(cf, "MDTM %s" ENDL, s)) != FTP_FILE_STATUS)
+ goto ouch;
+ for (ln = _ftp_last_reply + 4; *ln && isspace(*ln); ln++)
+ /* nothing */ ;
+ t = time(NULL);
+ us->mtime = localtime(&t)->tm_gmtoff;
+ sscanf(ln, "%04d%02d%02d%02d%02d%02d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+ /* XXX should check the return value from sscanf */
+ tm.tm_mon--;
+ tm.tm_year -= 1900;
+ tm.tm_isdst = -1;
+ tm.tm_gmtoff = 0;
+ us->mtime += mktime(&tm);
+ us->atime = us->mtime;
+ return 0;
+
+ouch:
+ _ftp_seterr(e);
return -1;
}
OpenPOWER on IntegriCloud