ftp.c revision 37536
1/*-
2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 *	$Id$
29 */
30
31/*
32 * Portions of this code were taken from ftpio.c:
33 *
34 * ----------------------------------------------------------------------------
35 * "THE BEER-WARE LICENSE" (Revision 42):
36 * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
37 * can do whatever you want with this stuff. If we meet some day, and you think
38 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
39 * ----------------------------------------------------------------------------
40 *
41 * Major Changelog:
42 *
43 * Dag-Erling Co�dan Sm�rgrav
44 * 9 Jun 1998
45 *
46 * Incorporated into libfetch
47 *
48 * Jordan K. Hubbard
49 * 17 Jan 1996
50 *
51 * Turned inside out. Now returns xfers as new file ids, not as a special
52 * `state' of FTP_t
53 *
54 * $ftpioId: ftpio.c,v 1.30 1998/04/11 07:28:53 phk Exp $
55 *
56 */
57
58#include <sys/types.h>
59#include <sys/socket.h>
60#include <netinet/in.h>
61
62#include <ctype.h>
63#include <netdb.h>
64#include <stdio.h>
65#include <string.h>
66
67#include "fetch.h"
68#include "ftperr.c"
69
70#define FTP_ANONYMOUS_USER	"ftp"
71#define FTP_ANONYMOUS_PASSWORD	"ftp"
72
73static url_t cached_host;
74static FILE *cached_socket;
75static int _ftp_errcode;
76
77static int
78_ftp_isconnected(url_t *url)
79{
80    return (cached_socket
81	    && (strcmp(url->host, cached_host.host) == 0)
82	    && (strcmp(url->user, cached_host.user) == 0)
83	    && (strcmp(url->pwd, cached_host.pwd) == 0)
84	    && (url->port == cached_host.port));
85}
86
87/*
88 * Get server response, check that first digit is a '2'
89 */
90static int
91_ftp_chkerr(FILE *s, char *e)
92{
93    char *line;
94    size_t len;
95
96    do {
97	if (((line = fgetln(s, &len)) == NULL) || (len < 4))
98	    return -1;
99    } while (line[3] == '-');
100
101    if (!isdigit(line[0]) || !isdigit(line[1]) || !isdigit(line[2]) || (line[3] != ' '))
102	return -1;
103
104    _ftp_errcode = (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0');
105
106    if (e)
107	*e = _ftp_errcode;
108
109    return (line[0] == '2') - 1;
110}
111
112/*
113 * Map error code to string
114 */
115static const char *
116_ftp_errstring(int e)
117{
118    struct ftperr *p = _ftp_errlist;
119
120    while ((p->num) && (p->num != e))
121	p++;
122
123    return p->string;
124}
125
126/*
127 * Change remote working directory
128 */
129static int
130_ftp_cwd(FILE *s, char *dir)
131{
132    fprintf(s, "CWD %s\n", dir);
133    if (ferror(s))
134	return -1;
135    return _ftp_chkerr(s, NULL); /* expecting 250 */
136}
137
138/*
139 * Retrieve file
140 */
141static FILE *
142_ftp_retr(FILE *s, char *file, int pasv)
143{
144    char *p;
145
146    /* change directory */
147    if (((p = strrchr(file, '/')) != NULL) && (p != file)) {
148	*p = 0;
149	if (_ftp_cwd(s, file) < 0) {
150	    *p = '/';
151	    return NULL;
152	}
153	*p++ = '/';
154    } else {
155	if (_ftp_cwd(s, "/") < 0)
156	    return NULL;
157    }
158
159    /* retrieve file; p now points to file name */
160    return NULL;
161}
162
163
164/*
165 * XXX rewrite these
166 */
167#if 0
168FILE *
169fetchGetFTP(url_t *url, char *flags)
170{
171    int retcode = 0;
172    static FILE *fp = NULL;
173    static char *prev_host = NULL;
174    FILE *fp2;
175
176#ifdef DEFAULT_TO_ANONYMOUS
177    if (!url->user[0]) {
178	strcpy(url->user, FTP_ANONYMOUS_USER);
179	strcpy(url->pwd, FTP_ANONYMOUS_PASSWORD);
180    }
181#endif
182
183    if (fp && prev_host) {
184	if (!strcmp(prev_host, url->host)) {
185	    /* Try to use cached connection */
186	    fp2 = ftpGet(fp, url->doc, NULL);
187	    if (!fp2) {
188		/* Connection timed out or was no longer valid */
189		fclose(fp);
190		free(prev_host);
191		prev_host = NULL;
192	    }
193	    else
194		return fp2;
195	}
196	else {
197	    /* It's a different host now, flush old */
198	    fclose(fp);
199	    free(prev_host);
200	    prev_host = NULL;
201	}
202    }
203    fp = ftpLogin(url->host, url->user, url->pwd, url->port, 0, &retcode);
204    if (fp) {
205	if (strchr(flags, 'p')) {
206	    if (ftpPassive(fp, 1) != SUCCESS)
207		/* XXX what should we do? */ ;
208	}
209	fp2 = ftpGet(fp, url->doc, NULL);
210	if (!fp2) {
211	    /* Connection timed out or was no longer valid */
212	    retcode = ftpErrno(fp);
213	    fclose(fp);
214	    fp = NULL;
215	}
216	else
217	    prev_host = strdup(url->host);
218	return fp2;
219    }
220    return NULL;
221}
222
223FILE *
224fetchPutFTP(url_t *url, char *flags)
225{
226    static FILE *fp = NULL;
227    FILE *fp2;
228    int retcode = 0;
229
230    if (fp) {	/* Close previous managed connection */
231	fclose(fp);
232	fp = NULL;
233    }
234    fp = ftpLogin(url->host, url->user, url->pwd, url->port, 0, &retcode);
235    if (fp) {
236	if (strchr(flags, 'p')) {
237	    if (ftpPassive(fp, 1) != SUCCESS)
238		/* XXX what should we do? */ ;
239	}
240	fp2 = ftpPut(fp, url->doc);
241	if (!fp2) {
242	    retcode = ftpErrno(fp);
243	    fclose(fp);
244	    fp = NULL;
245	}
246	return fp2;
247    }
248    return NULL;
249}
250#endif
251