xref: /freebsd/lib/libfetch/ftp.c (revision 4ca1ab94348cfb9bf0b65b9f523e26c136a94210)
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 
73 static url_t cached_host;
74 static FILE *cached_socket;
75 static int _ftp_errcode;
76 
77 static 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  */
90 static 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  */
115 static 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  */
129 static 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  */
141 static 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
168 FILE *
169 fetchGetFTP(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 
223 FILE *
224 fetchPutFTP(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