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