14ca1ab94SDag-Erling Smørgrav /*- 24ca1ab94SDag-Erling Smørgrav * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav 34ca1ab94SDag-Erling Smørgrav * All rights reserved. 44ca1ab94SDag-Erling Smørgrav * 54ca1ab94SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 64ca1ab94SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 74ca1ab94SDag-Erling Smørgrav * are met: 84ca1ab94SDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 94ca1ab94SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer 104ca1ab94SDag-Erling Smørgrav * in this position and unchanged. 114ca1ab94SDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 124ca1ab94SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 134ca1ab94SDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 144ca1ab94SDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote products 154ca1ab94SDag-Erling Smørgrav * derived from this software without specific prior written permission 164ca1ab94SDag-Erling Smørgrav * 174ca1ab94SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 184ca1ab94SDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 194ca1ab94SDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 204ca1ab94SDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 214ca1ab94SDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 224ca1ab94SDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 234ca1ab94SDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 244ca1ab94SDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 254ca1ab94SDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 264ca1ab94SDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274ca1ab94SDag-Erling Smørgrav * 287f3dea24SPeter Wemm * $FreeBSD$ 294ca1ab94SDag-Erling Smørgrav */ 304ca1ab94SDag-Erling Smørgrav 314ca1ab94SDag-Erling Smørgrav /* 328e3986eaSDag-Erling Smørgrav * Portions of this code were taken from or based on ftpio.c: 334ca1ab94SDag-Erling Smørgrav * 344ca1ab94SDag-Erling Smørgrav * ---------------------------------------------------------------------------- 354ca1ab94SDag-Erling Smørgrav * "THE BEER-WARE LICENSE" (Revision 42): 364ca1ab94SDag-Erling Smørgrav * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 374ca1ab94SDag-Erling Smørgrav * can do whatever you want with this stuff. If we meet some day, and you think 384ca1ab94SDag-Erling Smørgrav * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 394ca1ab94SDag-Erling Smørgrav * ---------------------------------------------------------------------------- 404ca1ab94SDag-Erling Smørgrav * 414ca1ab94SDag-Erling Smørgrav * Major Changelog: 424ca1ab94SDag-Erling Smørgrav * 434ca1ab94SDag-Erling Smørgrav * Dag-Erling Co�dan Sm�rgrav 444ca1ab94SDag-Erling Smørgrav * 9 Jun 1998 454ca1ab94SDag-Erling Smørgrav * 464ca1ab94SDag-Erling Smørgrav * Incorporated into libfetch 474ca1ab94SDag-Erling Smørgrav * 484ca1ab94SDag-Erling Smørgrav * Jordan K. Hubbard 494ca1ab94SDag-Erling Smørgrav * 17 Jan 1996 504ca1ab94SDag-Erling Smørgrav * 514ca1ab94SDag-Erling Smørgrav * Turned inside out. Now returns xfers as new file ids, not as a special 524ca1ab94SDag-Erling Smørgrav * `state' of FTP_t 534ca1ab94SDag-Erling Smørgrav * 544ca1ab94SDag-Erling Smørgrav * $ftpioId: ftpio.c,v 1.30 1998/04/11 07:28:53 phk Exp $ 554ca1ab94SDag-Erling Smørgrav * 564ca1ab94SDag-Erling Smørgrav */ 574ca1ab94SDag-Erling Smørgrav 580fba3a00SDag-Erling Smørgrav #include <sys/param.h> 594ca1ab94SDag-Erling Smørgrav #include <sys/socket.h> 604ca1ab94SDag-Erling Smørgrav #include <netinet/in.h> 614ca1ab94SDag-Erling Smørgrav 624ca1ab94SDag-Erling Smørgrav #include <ctype.h> 63fc6e9e65SDag-Erling Smørgrav #include <errno.h> 64c7d40ef2SDag-Erling Smørgrav #include <fcntl.h> 6532425dafSDag-Erling Smørgrav #include <netdb.h> 66346298f0SDag-Erling Smørgrav #include <stdarg.h> 674ca1ab94SDag-Erling Smørgrav #include <stdio.h> 688e3986eaSDag-Erling Smørgrav #include <stdlib.h> 694ca1ab94SDag-Erling Smørgrav #include <string.h> 705aea254fSDag-Erling Smørgrav #include <time.h> 718e3986eaSDag-Erling Smørgrav #include <unistd.h> 724ca1ab94SDag-Erling Smørgrav 734ca1ab94SDag-Erling Smørgrav #include "fetch.h" 74842a95ccSDag-Erling Smørgrav #include "common.h" 750fba3a00SDag-Erling Smørgrav #include "ftperr.h" 764ca1ab94SDag-Erling Smørgrav 774ca1ab94SDag-Erling Smørgrav #define FTP_ANONYMOUS_USER "ftp" 784ca1ab94SDag-Erling Smørgrav #define FTP_ANONYMOUS_PASSWORD "ftp" 79346298f0SDag-Erling Smørgrav 80ea014d85SDag-Erling Smørgrav #define FTP_CONNECTION_ALREADY_OPEN 125 81346298f0SDag-Erling Smørgrav #define FTP_OPEN_DATA_CONNECTION 150 82346298f0SDag-Erling Smørgrav #define FTP_OK 200 835aea254fSDag-Erling Smørgrav #define FTP_FILE_STATUS 213 843b7a6740SDag-Erling Smørgrav #define FTP_SERVICE_READY 220 85346298f0SDag-Erling Smørgrav #define FTP_PASSIVE_MODE 227 8628c645cfSHajimu UMEMOTO #define FTP_LPASSIVE_MODE 228 8728c645cfSHajimu UMEMOTO #define FTP_EPASSIVE_MODE 229 88346298f0SDag-Erling Smørgrav #define FTP_LOGGED_IN 230 89346298f0SDag-Erling Smørgrav #define FTP_FILE_ACTION_OK 250 90346298f0SDag-Erling Smørgrav #define FTP_NEED_PASSWORD 331 91346298f0SDag-Erling Smørgrav #define FTP_NEED_ACCOUNT 332 9232425dafSDag-Erling Smørgrav #define FTP_FILE_OK 350 93fc6e9e65SDag-Erling Smørgrav #define FTP_SYNTAX_ERROR 500 945cd33c40SDag-Erling Smørgrav #define FTP_PROTOCOL_ERROR 999 954ca1ab94SDag-Erling Smørgrav 96d8acd8dcSDag-Erling Smørgrav static struct url cached_host; 97fc6e9e65SDag-Erling Smørgrav static int cached_socket; 984ca1ab94SDag-Erling Smørgrav 99fc6e9e65SDag-Erling Smørgrav static char *last_reply; 100fc6e9e65SDag-Erling Smørgrav static size_t lr_size, lr_length; 101fc6e9e65SDag-Erling Smørgrav static int last_code; 102fc6e9e65SDag-Erling Smørgrav 103fc6e9e65SDag-Erling Smørgrav #define isftpreply(foo) (isdigit(foo[0]) && isdigit(foo[1]) \ 1046efb30c8SDag-Erling Smørgrav && isdigit(foo[2]) \ 1056efb30c8SDag-Erling Smørgrav && (foo[3] == ' ' || foo[3] == '\0')) 106fc6e9e65SDag-Erling Smørgrav #define isftpinfo(foo) (isdigit(foo[0]) && isdigit(foo[1]) \ 107fc6e9e65SDag-Erling Smørgrav && isdigit(foo[2]) && foo[3] == '-') 1084ca1ab94SDag-Erling Smørgrav 10928c645cfSHajimu UMEMOTO /* translate IPv4 mapped IPv6 address to IPv4 address */ 11028c645cfSHajimu UMEMOTO static void 11128c645cfSHajimu UMEMOTO unmappedaddr(struct sockaddr_in6 *sin6) 11228c645cfSHajimu UMEMOTO { 11328c645cfSHajimu UMEMOTO struct sockaddr_in *sin4; 11428c645cfSHajimu UMEMOTO u_int32_t addr; 11528c645cfSHajimu UMEMOTO int port; 11628c645cfSHajimu UMEMOTO 11728c645cfSHajimu UMEMOTO if (sin6->sin6_family != AF_INET6 || 11828c645cfSHajimu UMEMOTO !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 11928c645cfSHajimu UMEMOTO return; 12028c645cfSHajimu UMEMOTO sin4 = (struct sockaddr_in *)sin6; 12128c645cfSHajimu UMEMOTO addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12]; 12228c645cfSHajimu UMEMOTO port = sin6->sin6_port; 12328c645cfSHajimu UMEMOTO memset(sin4, 0, sizeof(struct sockaddr_in)); 12428c645cfSHajimu UMEMOTO sin4->sin_addr.s_addr = addr; 12528c645cfSHajimu UMEMOTO sin4->sin_port = port; 12628c645cfSHajimu UMEMOTO sin4->sin_family = AF_INET; 12728c645cfSHajimu UMEMOTO sin4->sin_len = sizeof(struct sockaddr_in); 12828c645cfSHajimu UMEMOTO } 12928c645cfSHajimu UMEMOTO 1304ca1ab94SDag-Erling Smørgrav /* 131fc6e9e65SDag-Erling Smørgrav * Get server response 1328e3986eaSDag-Erling Smørgrav */ 1338e3986eaSDag-Erling Smørgrav static int 134fc6e9e65SDag-Erling Smørgrav _ftp_chkerr(int cd) 1358e3986eaSDag-Erling Smørgrav { 136fc6e9e65SDag-Erling Smørgrav if (_fetch_getln(cd, &last_reply, &lr_size, &lr_length) == -1) { 137842a95ccSDag-Erling Smørgrav _fetch_syserr(); 1388e3986eaSDag-Erling Smørgrav return -1; 1398e3986eaSDag-Erling Smørgrav } 140eac7a1e0SDag-Erling Smørgrav if (isftpinfo(last_reply)) { 141eac7a1e0SDag-Erling Smørgrav while (!isftpreply(last_reply)) { 142eac7a1e0SDag-Erling Smørgrav if (_fetch_getln(cd, &last_reply, &lr_size, &lr_length) == -1) { 143eac7a1e0SDag-Erling Smørgrav _fetch_syserr(); 144eac7a1e0SDag-Erling Smørgrav return -1; 145eac7a1e0SDag-Erling Smørgrav } 146eac7a1e0SDag-Erling Smørgrav } 147eac7a1e0SDag-Erling Smørgrav } 148346298f0SDag-Erling Smørgrav 149fc6e9e65SDag-Erling Smørgrav while (lr_length && isspace(last_reply[lr_length-1])) 150fc6e9e65SDag-Erling Smørgrav lr_length--; 151fc6e9e65SDag-Erling Smørgrav last_reply[lr_length] = 0; 152fc6e9e65SDag-Erling Smørgrav 153fc6e9e65SDag-Erling Smørgrav if (!isftpreply(last_reply)) { 1545cd33c40SDag-Erling Smørgrav _ftp_seterr(FTP_PROTOCOL_ERROR); 1558e3986eaSDag-Erling Smørgrav return -1; 1568e3986eaSDag-Erling Smørgrav } 1578e3986eaSDag-Erling Smørgrav 158fc6e9e65SDag-Erling Smørgrav last_code = (last_reply[0] - '0') * 100 159fc6e9e65SDag-Erling Smørgrav + (last_reply[1] - '0') * 10 160fc6e9e65SDag-Erling Smørgrav + (last_reply[2] - '0'); 161fc6e9e65SDag-Erling Smørgrav 162fc6e9e65SDag-Erling Smørgrav return last_code; 1638e3986eaSDag-Erling Smørgrav } 1648e3986eaSDag-Erling Smørgrav 1658e3986eaSDag-Erling Smørgrav /* 166346298f0SDag-Erling Smørgrav * Send a command and check reply 1674ca1ab94SDag-Erling Smørgrav */ 1684ca1ab94SDag-Erling Smørgrav static int 169fc6e9e65SDag-Erling Smørgrav _ftp_cmd(int cd, char *fmt, ...) 1704ca1ab94SDag-Erling Smørgrav { 171346298f0SDag-Erling Smørgrav va_list ap; 172e137bcebSDag-Erling Smørgrav size_t len; 173fc6e9e65SDag-Erling Smørgrav char *msg; 174fc6e9e65SDag-Erling Smørgrav int r; 1758e3986eaSDag-Erling Smørgrav 176346298f0SDag-Erling Smørgrav va_start(ap, fmt); 177e137bcebSDag-Erling Smørgrav len = vasprintf(&msg, fmt, ap); 178346298f0SDag-Erling Smørgrav va_end(ap); 179346298f0SDag-Erling Smørgrav 180fc6e9e65SDag-Erling Smørgrav if (msg == NULL) { 181fc6e9e65SDag-Erling Smørgrav errno = ENOMEM; 182fc6e9e65SDag-Erling Smørgrav _fetch_syserr(); 183fc6e9e65SDag-Erling Smørgrav return -1; 184fc6e9e65SDag-Erling Smørgrav } 185e137bcebSDag-Erling Smørgrav 186e137bcebSDag-Erling Smørgrav r = _fetch_putln(cd, msg, len); 187fc6e9e65SDag-Erling Smørgrav free(msg); 188e137bcebSDag-Erling Smørgrav 189fc6e9e65SDag-Erling Smørgrav if (r == -1) { 190fc6e9e65SDag-Erling Smørgrav _fetch_syserr(); 191fc6e9e65SDag-Erling Smørgrav return -1; 192fc6e9e65SDag-Erling Smørgrav } 193fc6e9e65SDag-Erling Smørgrav 194fc6e9e65SDag-Erling Smørgrav return _ftp_chkerr(cd); 1954ca1ab94SDag-Erling Smørgrav } 1964ca1ab94SDag-Erling Smørgrav 1974ca1ab94SDag-Erling Smørgrav /* 1981a5faa10SDag-Erling Smørgrav * Return a pointer to the filename part of a path 1991a5faa10SDag-Erling Smørgrav */ 2001a5faa10SDag-Erling Smørgrav static char * 2011a5faa10SDag-Erling Smørgrav _ftp_filename(char *file) 2021a5faa10SDag-Erling Smørgrav { 2031a5faa10SDag-Erling Smørgrav char *s; 2041a5faa10SDag-Erling Smørgrav 2051a5faa10SDag-Erling Smørgrav if ((s = strrchr(file, '/')) == NULL) 2061a5faa10SDag-Erling Smørgrav return file; 2071a5faa10SDag-Erling Smørgrav else 2081a5faa10SDag-Erling Smørgrav return s + 1; 2091a5faa10SDag-Erling Smørgrav } 2101a5faa10SDag-Erling Smørgrav 2111a5faa10SDag-Erling Smørgrav /* 2121a5faa10SDag-Erling Smørgrav * Change working directory to the directory that contains the 2131a5faa10SDag-Erling Smørgrav * specified file. 2141a5faa10SDag-Erling Smørgrav */ 2151a5faa10SDag-Erling Smørgrav static int 2161a5faa10SDag-Erling Smørgrav _ftp_cwd(int cd, char *file) 2171a5faa10SDag-Erling Smørgrav { 2181a5faa10SDag-Erling Smørgrav char *s; 2191a5faa10SDag-Erling Smørgrav int e; 2201a5faa10SDag-Erling Smørgrav 2215e3f46b5SDag-Erling Smørgrav if ((s = strrchr(file, '/')) == NULL || s == file) { 2221a5faa10SDag-Erling Smørgrav e = _ftp_cmd(cd, "CWD /"); 2231a5faa10SDag-Erling Smørgrav } else { 2241a5faa10SDag-Erling Smørgrav e = _ftp_cmd(cd, "CWD %.*s", s - file, file); 2251a5faa10SDag-Erling Smørgrav } 2261a5faa10SDag-Erling Smørgrav if (e != FTP_FILE_ACTION_OK) { 2271a5faa10SDag-Erling Smørgrav _ftp_seterr(e); 2281a5faa10SDag-Erling Smørgrav return -1; 2291a5faa10SDag-Erling Smørgrav } 2301a5faa10SDag-Erling Smørgrav return 0; 2311a5faa10SDag-Erling Smørgrav } 2321a5faa10SDag-Erling Smørgrav 2331a5faa10SDag-Erling Smørgrav /* 2341a5faa10SDag-Erling Smørgrav * Request and parse file stats 2351a5faa10SDag-Erling Smørgrav */ 2361a5faa10SDag-Erling Smørgrav static int 2371a5faa10SDag-Erling Smørgrav _ftp_stat(int cd, char *file, struct url_stat *us) 2381a5faa10SDag-Erling Smørgrav { 2391a5faa10SDag-Erling Smørgrav char *ln, *s; 2401a5faa10SDag-Erling Smørgrav struct tm tm; 2411a5faa10SDag-Erling Smørgrav time_t t; 2421a5faa10SDag-Erling Smørgrav int e; 2431a5faa10SDag-Erling Smørgrav 244269532d9SDag-Erling Smørgrav us->size = -1; 245269532d9SDag-Erling Smørgrav us->atime = us->mtime = 0; 246269532d9SDag-Erling Smørgrav 2471a5faa10SDag-Erling Smørgrav if ((s = strrchr(file, '/')) == NULL) 2481a5faa10SDag-Erling Smørgrav s = file; 2491a5faa10SDag-Erling Smørgrav else 2501a5faa10SDag-Erling Smørgrav ++s; 2511a5faa10SDag-Erling Smørgrav 2521a5faa10SDag-Erling Smørgrav if ((e = _ftp_cmd(cd, "SIZE %s", s)) != FTP_FILE_STATUS) { 2531a5faa10SDag-Erling Smørgrav _ftp_seterr(e); 2541a5faa10SDag-Erling Smørgrav return -1; 2551a5faa10SDag-Erling Smørgrav } 2561a5faa10SDag-Erling Smørgrav for (ln = last_reply + 4; *ln && isspace(*ln); ln++) 2571a5faa10SDag-Erling Smørgrav /* nothing */ ; 2581a5faa10SDag-Erling Smørgrav for (us->size = 0; *ln && isdigit(*ln); ln++) 2591a5faa10SDag-Erling Smørgrav us->size = us->size * 10 + *ln - '0'; 2601a5faa10SDag-Erling Smørgrav if (*ln && !isspace(*ln)) { 2611a5faa10SDag-Erling Smørgrav _ftp_seterr(FTP_PROTOCOL_ERROR); 2621a5faa10SDag-Erling Smørgrav return -1; 2631a5faa10SDag-Erling Smørgrav } 26463428824SDag-Erling Smørgrav if (us->size == 0) 26563428824SDag-Erling Smørgrav us->size = -1; 2661a5faa10SDag-Erling Smørgrav DEBUG(fprintf(stderr, "size: [\033[1m%lld\033[m]\n", us->size)); 2671a5faa10SDag-Erling Smørgrav 2681a5faa10SDag-Erling Smørgrav if ((e = _ftp_cmd(cd, "MDTM %s", s)) != FTP_FILE_STATUS) { 2691a5faa10SDag-Erling Smørgrav _ftp_seterr(e); 2701a5faa10SDag-Erling Smørgrav return -1; 2711a5faa10SDag-Erling Smørgrav } 2721a5faa10SDag-Erling Smørgrav for (ln = last_reply + 4; *ln && isspace(*ln); ln++) 2731a5faa10SDag-Erling Smørgrav /* nothing */ ; 2741a5faa10SDag-Erling Smørgrav switch (strspn(ln, "0123456789")) { 2751a5faa10SDag-Erling Smørgrav case 14: 2761a5faa10SDag-Erling Smørgrav break; 2771a5faa10SDag-Erling Smørgrav case 15: 2781a5faa10SDag-Erling Smørgrav ln++; 2791a5faa10SDag-Erling Smørgrav ln[0] = '2'; 2801a5faa10SDag-Erling Smørgrav ln[1] = '0'; 2811a5faa10SDag-Erling Smørgrav break; 2821a5faa10SDag-Erling Smørgrav default: 2831a5faa10SDag-Erling Smørgrav _ftp_seterr(FTP_PROTOCOL_ERROR); 2841a5faa10SDag-Erling Smørgrav return -1; 2851a5faa10SDag-Erling Smørgrav } 2861a5faa10SDag-Erling Smørgrav if (sscanf(ln, "%04d%02d%02d%02d%02d%02d", 2871a5faa10SDag-Erling Smørgrav &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 2881a5faa10SDag-Erling Smørgrav &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) { 2891a5faa10SDag-Erling Smørgrav _ftp_seterr(FTP_PROTOCOL_ERROR); 2901a5faa10SDag-Erling Smørgrav return -1; 2911a5faa10SDag-Erling Smørgrav } 2921a5faa10SDag-Erling Smørgrav tm.tm_mon--; 2931a5faa10SDag-Erling Smørgrav tm.tm_year -= 1900; 2941a5faa10SDag-Erling Smørgrav tm.tm_isdst = -1; 2951a5faa10SDag-Erling Smørgrav t = timegm(&tm); 2961a5faa10SDag-Erling Smørgrav if (t == (time_t)-1) 2971a5faa10SDag-Erling Smørgrav t = time(NULL); 2981a5faa10SDag-Erling Smørgrav us->mtime = t; 2991a5faa10SDag-Erling Smørgrav us->atime = t; 3001a5faa10SDag-Erling Smørgrav DEBUG(fprintf(stderr, "last modified: [\033[1m%04d-%02d-%02d " 3011a5faa10SDag-Erling Smørgrav "%02d:%02d:%02d\033[m]\n", 3021a5faa10SDag-Erling Smørgrav tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 3031a5faa10SDag-Erling Smørgrav tm.tm_hour, tm.tm_min, tm.tm_sec)); 3041a5faa10SDag-Erling Smørgrav return 0; 3051a5faa10SDag-Erling Smørgrav } 3061a5faa10SDag-Erling Smørgrav 3071a5faa10SDag-Erling Smørgrav /* 308c7d40ef2SDag-Erling Smørgrav * I/O functions for FTP 309c7d40ef2SDag-Erling Smørgrav */ 310c7d40ef2SDag-Erling Smørgrav struct ftpio { 311c7d40ef2SDag-Erling Smørgrav int csd; /* Control socket descriptor */ 312c7d40ef2SDag-Erling Smørgrav int dsd; /* Data socket descriptor */ 313c7d40ef2SDag-Erling Smørgrav int dir; /* Direction */ 314c7d40ef2SDag-Erling Smørgrav int eof; /* EOF reached */ 315c7d40ef2SDag-Erling Smørgrav int err; /* Error code */ 316c7d40ef2SDag-Erling Smørgrav }; 317c7d40ef2SDag-Erling Smørgrav 318c7d40ef2SDag-Erling Smørgrav static int _ftp_readfn(void *, char *, int); 319c7d40ef2SDag-Erling Smørgrav static int _ftp_writefn(void *, const char *, int); 320c7d40ef2SDag-Erling Smørgrav static fpos_t _ftp_seekfn(void *, fpos_t, int); 321c7d40ef2SDag-Erling Smørgrav static int _ftp_closefn(void *); 322c7d40ef2SDag-Erling Smørgrav 323c7d40ef2SDag-Erling Smørgrav static int 324c7d40ef2SDag-Erling Smørgrav _ftp_readfn(void *v, char *buf, int len) 325c7d40ef2SDag-Erling Smørgrav { 326c7d40ef2SDag-Erling Smørgrav struct ftpio *io; 327c7d40ef2SDag-Erling Smørgrav int r; 328c7d40ef2SDag-Erling Smørgrav 329c7d40ef2SDag-Erling Smørgrav io = (struct ftpio *)v; 330c7d40ef2SDag-Erling Smørgrav if (io->csd == -1 || io->dsd == -1 || io->dir == O_WRONLY) { 331c7d40ef2SDag-Erling Smørgrav errno = EBADF; 332c7d40ef2SDag-Erling Smørgrav return -1; 333c7d40ef2SDag-Erling Smørgrav } 334c7d40ef2SDag-Erling Smørgrav if (io->err) { 335c7d40ef2SDag-Erling Smørgrav errno = io->err; 336c7d40ef2SDag-Erling Smørgrav return -1; 337c7d40ef2SDag-Erling Smørgrav } 338c7d40ef2SDag-Erling Smørgrav if (io->eof) 339c7d40ef2SDag-Erling Smørgrav return 0; 340c7d40ef2SDag-Erling Smørgrav r = read(io->dsd, buf, len); 341c7d40ef2SDag-Erling Smørgrav if (r > 0) 342c7d40ef2SDag-Erling Smørgrav return r; 343c7d40ef2SDag-Erling Smørgrav if (r == 0) { 344c7d40ef2SDag-Erling Smørgrav io->eof = 1; 345c7d40ef2SDag-Erling Smørgrav return _ftp_closefn(v); 346c7d40ef2SDag-Erling Smørgrav } 347c7d40ef2SDag-Erling Smørgrav io->err = errno; 348c7d40ef2SDag-Erling Smørgrav return -1; 349c7d40ef2SDag-Erling Smørgrav } 350c7d40ef2SDag-Erling Smørgrav 351c7d40ef2SDag-Erling Smørgrav static int 352c7d40ef2SDag-Erling Smørgrav _ftp_writefn(void *v, const char *buf, int len) 353c7d40ef2SDag-Erling Smørgrav { 354c7d40ef2SDag-Erling Smørgrav struct ftpio *io; 355c7d40ef2SDag-Erling Smørgrav int w; 356c7d40ef2SDag-Erling Smørgrav 357c7d40ef2SDag-Erling Smørgrav io = (struct ftpio *)v; 358c7d40ef2SDag-Erling Smørgrav if (io->csd == -1 || io->dsd == -1 || io->dir == O_RDONLY) { 359c7d40ef2SDag-Erling Smørgrav errno = EBADF; 360c7d40ef2SDag-Erling Smørgrav return -1; 361c7d40ef2SDag-Erling Smørgrav } 362c7d40ef2SDag-Erling Smørgrav if (io->err) { 363c7d40ef2SDag-Erling Smørgrav errno = io->err; 364c7d40ef2SDag-Erling Smørgrav return -1; 365c7d40ef2SDag-Erling Smørgrav } 366c7d40ef2SDag-Erling Smørgrav w = write(io->dsd, buf, len); 367c7d40ef2SDag-Erling Smørgrav if (w >= 0) 368c7d40ef2SDag-Erling Smørgrav return w; 369c7d40ef2SDag-Erling Smørgrav io->err = errno; 370c7d40ef2SDag-Erling Smørgrav return -1; 371c7d40ef2SDag-Erling Smørgrav } 372c7d40ef2SDag-Erling Smørgrav 373c7d40ef2SDag-Erling Smørgrav static fpos_t 374c7d40ef2SDag-Erling Smørgrav _ftp_seekfn(void *v, fpos_t pos, int whence) 375c7d40ef2SDag-Erling Smørgrav { 376c7d40ef2SDag-Erling Smørgrav errno = ESPIPE; 377c7d40ef2SDag-Erling Smørgrav return -1; 378c7d40ef2SDag-Erling Smørgrav } 379c7d40ef2SDag-Erling Smørgrav 380c7d40ef2SDag-Erling Smørgrav static int 381c7d40ef2SDag-Erling Smørgrav _ftp_closefn(void *v) 382c7d40ef2SDag-Erling Smørgrav { 383c7d40ef2SDag-Erling Smørgrav struct ftpio *io; 384c7d40ef2SDag-Erling Smørgrav 385c7d40ef2SDag-Erling Smørgrav io = (struct ftpio *)v; 386c7d40ef2SDag-Erling Smørgrav if (io->dir == -1) 387c7d40ef2SDag-Erling Smørgrav return 0; 388c7d40ef2SDag-Erling Smørgrav if (io->csd == -1 || io->dsd == -1) { 389c7d40ef2SDag-Erling Smørgrav errno = EBADF; 390c7d40ef2SDag-Erling Smørgrav return -1; 391c7d40ef2SDag-Erling Smørgrav } 392c7d40ef2SDag-Erling Smørgrav io->err = _ftp_chkerr(io->csd); 393c7d40ef2SDag-Erling Smørgrav io->dir = -1; 394c7d40ef2SDag-Erling Smørgrav if (close(io->dsd) == -1) 395c7d40ef2SDag-Erling Smørgrav return -1; 396c7d40ef2SDag-Erling Smørgrav io->dsd = -1; 397c7d40ef2SDag-Erling Smørgrav close(io->csd); 398c7d40ef2SDag-Erling Smørgrav io->csd = -1; 399c7d40ef2SDag-Erling Smørgrav return io->err ? -1 : 0; 400c7d40ef2SDag-Erling Smørgrav } 401c7d40ef2SDag-Erling Smørgrav 402c7d40ef2SDag-Erling Smørgrav static FILE * 403c7d40ef2SDag-Erling Smørgrav _ftp_setup(int csd, int dsd, int mode) 404c7d40ef2SDag-Erling Smørgrav { 405c7d40ef2SDag-Erling Smørgrav struct ftpio *io; 406c7d40ef2SDag-Erling Smørgrav FILE *f; 407c7d40ef2SDag-Erling Smørgrav 408c7d40ef2SDag-Erling Smørgrav if ((io = malloc(sizeof *io)) == NULL) 409c7d40ef2SDag-Erling Smørgrav return NULL; 410c7d40ef2SDag-Erling Smørgrav io->csd = dup(csd); 411c7d40ef2SDag-Erling Smørgrav io->dsd = dsd; 412c7d40ef2SDag-Erling Smørgrav io->dir = mode; 413c7d40ef2SDag-Erling Smørgrav io->eof = io->err = 0; 414c7d40ef2SDag-Erling Smørgrav f = funopen(io, _ftp_readfn, _ftp_writefn, _ftp_seekfn, _ftp_closefn); 415c7d40ef2SDag-Erling Smørgrav if (f == NULL) 416c7d40ef2SDag-Erling Smørgrav free(io); 417c7d40ef2SDag-Erling Smørgrav return f; 418c7d40ef2SDag-Erling Smørgrav } 419c7d40ef2SDag-Erling Smørgrav 420c7d40ef2SDag-Erling Smørgrav /* 421f62e5228SDag-Erling Smørgrav * Transfer file 4224ca1ab94SDag-Erling Smørgrav */ 4234ca1ab94SDag-Erling Smørgrav static FILE * 42432425dafSDag-Erling Smørgrav _ftp_transfer(int cd, char *oper, char *file, 425c7d40ef2SDag-Erling Smørgrav int mode, off_t offset, char *flags) 4264ca1ab94SDag-Erling Smørgrav { 42728c645cfSHajimu UMEMOTO struct sockaddr_storage sin; 42828c645cfSHajimu UMEMOTO struct sockaddr_in6 *sin6; 42928c645cfSHajimu UMEMOTO struct sockaddr_in *sin4; 430f5f109a0SDag-Erling Smørgrav int pasv, high, verbose; 431f5f109a0SDag-Erling Smørgrav int e, sd = -1; 432f5f109a0SDag-Erling Smørgrav socklen_t l; 433346298f0SDag-Erling Smørgrav char *s; 434346298f0SDag-Erling Smørgrav FILE *df; 4358e3986eaSDag-Erling Smørgrav 436f5f109a0SDag-Erling Smørgrav /* check flags */ 437f5f109a0SDag-Erling Smørgrav pasv = (flags && strchr(flags, 'p')); 438f5f109a0SDag-Erling Smørgrav high = (flags && strchr(flags, 'h')); 439f5f109a0SDag-Erling Smørgrav verbose = (flags && strchr(flags, 'v')); 440f5f109a0SDag-Erling Smørgrav 441d02e84a6SDag-Erling Smørgrav /* passive mode */ 4428b9ba466SDag-Erling Smørgrav if (!pasv) 4438b9ba466SDag-Erling Smørgrav pasv = ((s = getenv("FTP_PASSIVE_MODE")) == NULL || 4448b9ba466SDag-Erling Smørgrav strncasecmp(s, "no", 2) != 0); 445d02e84a6SDag-Erling Smørgrav 44628c645cfSHajimu UMEMOTO /* find our own address, bind, and listen */ 44728c645cfSHajimu UMEMOTO l = sizeof sin; 44828c645cfSHajimu UMEMOTO if (getsockname(cd, (struct sockaddr *)&sin, &l) == -1) 44928c645cfSHajimu UMEMOTO goto sysouch; 45028c645cfSHajimu UMEMOTO if (sin.ss_family == AF_INET6) 45128c645cfSHajimu UMEMOTO unmappedaddr((struct sockaddr_in6 *)&sin); 45228c645cfSHajimu UMEMOTO 453346298f0SDag-Erling Smørgrav /* open data socket */ 45428c645cfSHajimu UMEMOTO if ((sd = socket(sin.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) { 455842a95ccSDag-Erling Smørgrav _fetch_syserr(); 456346298f0SDag-Erling Smørgrav return NULL; 457346298f0SDag-Erling Smørgrav } 458346298f0SDag-Erling Smørgrav 459346298f0SDag-Erling Smørgrav if (pasv) { 46028c645cfSHajimu UMEMOTO u_char addr[64]; 461346298f0SDag-Erling Smørgrav char *ln, *p; 462346298f0SDag-Erling Smørgrav int i; 46328c645cfSHajimu UMEMOTO int port; 464346298f0SDag-Erling Smørgrav 465346298f0SDag-Erling Smørgrav /* send PASV command */ 466f5f109a0SDag-Erling Smørgrav if (verbose) 467f5f109a0SDag-Erling Smørgrav _fetch_info("setting passive mode"); 46828c645cfSHajimu UMEMOTO switch (sin.ss_family) { 46928c645cfSHajimu UMEMOTO case AF_INET: 470fc6e9e65SDag-Erling Smørgrav if ((e = _ftp_cmd(cd, "PASV")) != FTP_PASSIVE_MODE) 471346298f0SDag-Erling Smørgrav goto ouch; 47228c645cfSHajimu UMEMOTO break; 47328c645cfSHajimu UMEMOTO case AF_INET6: 47428c645cfSHajimu UMEMOTO if ((e = _ftp_cmd(cd, "EPSV")) != FTP_EPASSIVE_MODE) { 47528c645cfSHajimu UMEMOTO if (e == -1) 47628c645cfSHajimu UMEMOTO goto ouch; 47728c645cfSHajimu UMEMOTO if ((e = _ftp_cmd(cd, "LPSV")) != FTP_LPASSIVE_MODE) 47828c645cfSHajimu UMEMOTO goto ouch; 47928c645cfSHajimu UMEMOTO } 48028c645cfSHajimu UMEMOTO break; 48128c645cfSHajimu UMEMOTO default: 4825cd33c40SDag-Erling Smørgrav e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */ 48328c645cfSHajimu UMEMOTO goto ouch; 48428c645cfSHajimu UMEMOTO } 485346298f0SDag-Erling Smørgrav 486f5f109a0SDag-Erling Smørgrav /* 487f5f109a0SDag-Erling Smørgrav * Find address and port number. The reply to the PASV command 488f5f109a0SDag-Erling Smørgrav * is IMHO the one and only weak point in the FTP protocol. 489f5f109a0SDag-Erling Smørgrav */ 490fc6e9e65SDag-Erling Smørgrav ln = last_reply; 491fa5dce6cSHajimu UMEMOTO switch (e) { 492fa5dce6cSHajimu UMEMOTO case FTP_PASSIVE_MODE: 493fa5dce6cSHajimu UMEMOTO case FTP_LPASSIVE_MODE: 49451e3d46eSDag-Erling Smørgrav for (p = ln + 3; *p && !isdigit(*p); p++) 495346298f0SDag-Erling Smørgrav /* nothing */ ; 49628c645cfSHajimu UMEMOTO if (!*p) { 4975cd33c40SDag-Erling Smørgrav e = FTP_PROTOCOL_ERROR; 4986efb30c8SDag-Erling Smørgrav goto ouch; 499346298f0SDag-Erling Smørgrav } 50028c645cfSHajimu UMEMOTO l = (e == FTP_PASSIVE_MODE ? 6 : 21); 50128c645cfSHajimu UMEMOTO for (i = 0; *p && i < l; i++, p++) 50228c645cfSHajimu UMEMOTO addr[i] = strtol(p, &p, 10); 50328c645cfSHajimu UMEMOTO if (i < l) { 5045cd33c40SDag-Erling Smørgrav e = FTP_PROTOCOL_ERROR; 50528c645cfSHajimu UMEMOTO goto ouch; 50628c645cfSHajimu UMEMOTO } 50728c645cfSHajimu UMEMOTO break; 50828c645cfSHajimu UMEMOTO case FTP_EPASSIVE_MODE: 509fa5dce6cSHajimu UMEMOTO for (p = ln + 3; *p && *p != '('; p++) 510fa5dce6cSHajimu UMEMOTO /* nothing */ ; 511fa5dce6cSHajimu UMEMOTO if (!*p) { 5125cd33c40SDag-Erling Smørgrav e = FTP_PROTOCOL_ERROR; 513fa5dce6cSHajimu UMEMOTO goto ouch; 514fa5dce6cSHajimu UMEMOTO } 515fa5dce6cSHajimu UMEMOTO ++p; 51628c645cfSHajimu UMEMOTO if (sscanf(p, "%c%c%c%d%c", &addr[0], &addr[1], &addr[2], 51728c645cfSHajimu UMEMOTO &port, &addr[3]) != 5 || 51828c645cfSHajimu UMEMOTO addr[0] != addr[1] || 51928c645cfSHajimu UMEMOTO addr[0] != addr[2] || addr[0] != addr[3]) { 5205cd33c40SDag-Erling Smørgrav e = FTP_PROTOCOL_ERROR; 52128c645cfSHajimu UMEMOTO goto ouch; 52228c645cfSHajimu UMEMOTO } 52328c645cfSHajimu UMEMOTO break; 52428c645cfSHajimu UMEMOTO } 525346298f0SDag-Erling Smørgrav 52632425dafSDag-Erling Smørgrav /* seek to required offset */ 52732425dafSDag-Erling Smørgrav if (offset) 52832425dafSDag-Erling Smørgrav if (_ftp_cmd(cd, "REST %lu", (u_long)offset) != FTP_FILE_OK) 52932425dafSDag-Erling Smørgrav goto sysouch; 53032425dafSDag-Erling Smørgrav 531346298f0SDag-Erling Smørgrav /* construct sockaddr for data socket */ 53232425dafSDag-Erling Smørgrav l = sizeof sin; 533fc6e9e65SDag-Erling Smørgrav if (getpeername(cd, (struct sockaddr *)&sin, &l) == -1) 534346298f0SDag-Erling Smørgrav goto sysouch; 53528c645cfSHajimu UMEMOTO if (sin.ss_family == AF_INET6) 53628c645cfSHajimu UMEMOTO unmappedaddr((struct sockaddr_in6 *)&sin); 53728c645cfSHajimu UMEMOTO switch (sin.ss_family) { 53828c645cfSHajimu UMEMOTO case AF_INET6: 53928c645cfSHajimu UMEMOTO sin6 = (struct sockaddr_in6 *)&sin; 54028c645cfSHajimu UMEMOTO if (e == FTP_EPASSIVE_MODE) 54128c645cfSHajimu UMEMOTO sin6->sin6_port = htons(port); 54228c645cfSHajimu UMEMOTO else { 54328c645cfSHajimu UMEMOTO bcopy(addr + 2, (char *)&sin6->sin6_addr, 16); 54428c645cfSHajimu UMEMOTO bcopy(addr + 19, (char *)&sin6->sin6_port, 2); 54528c645cfSHajimu UMEMOTO } 54628c645cfSHajimu UMEMOTO break; 54728c645cfSHajimu UMEMOTO case AF_INET: 54828c645cfSHajimu UMEMOTO sin4 = (struct sockaddr_in *)&sin; 54928c645cfSHajimu UMEMOTO if (e == FTP_EPASSIVE_MODE) 55028c645cfSHajimu UMEMOTO sin4->sin_port = htons(port); 55128c645cfSHajimu UMEMOTO else { 55228c645cfSHajimu UMEMOTO bcopy(addr, (char *)&sin4->sin_addr, 4); 55328c645cfSHajimu UMEMOTO bcopy(addr + 4, (char *)&sin4->sin_port, 2); 55428c645cfSHajimu UMEMOTO } 55528c645cfSHajimu UMEMOTO break; 55628c645cfSHajimu UMEMOTO default: 5575cd33c40SDag-Erling Smørgrav e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */ 55828c645cfSHajimu UMEMOTO break; 55928c645cfSHajimu UMEMOTO } 560346298f0SDag-Erling Smørgrav 561346298f0SDag-Erling Smørgrav /* connect to data port */ 562f5f109a0SDag-Erling Smørgrav if (verbose) 563f5f109a0SDag-Erling Smørgrav _fetch_info("opening data connection"); 56428c645cfSHajimu UMEMOTO if (connect(sd, (struct sockaddr *)&sin, sin.ss_len) == -1) 565346298f0SDag-Erling Smørgrav goto sysouch; 566346298f0SDag-Erling Smørgrav 567346298f0SDag-Erling Smørgrav /* make the server initiate the transfer */ 568f5f109a0SDag-Erling Smørgrav if (verbose) 569def5f54cSDag-Erling Smørgrav _fetch_info("initiating transfer"); 5701a5faa10SDag-Erling Smørgrav e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file)); 571ea014d85SDag-Erling Smørgrav if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION) 572346298f0SDag-Erling Smørgrav goto ouch; 573346298f0SDag-Erling Smørgrav 574346298f0SDag-Erling Smørgrav } else { 575346298f0SDag-Erling Smørgrav u_int32_t a; 576346298f0SDag-Erling Smørgrav u_short p; 577f5f109a0SDag-Erling Smørgrav int arg, d; 57828c645cfSHajimu UMEMOTO char *ap; 57928c645cfSHajimu UMEMOTO char hname[INET6_ADDRSTRLEN]; 580346298f0SDag-Erling Smørgrav 58128c645cfSHajimu UMEMOTO switch (sin.ss_family) { 58228c645cfSHajimu UMEMOTO case AF_INET6: 58328c645cfSHajimu UMEMOTO ((struct sockaddr_in6 *)&sin)->sin6_port = 0; 58428c645cfSHajimu UMEMOTO #ifdef IPV6_PORTRANGE 58528c645cfSHajimu UMEMOTO arg = high ? IPV6_PORTRANGE_HIGH : IPV6_PORTRANGE_DEFAULT; 58628c645cfSHajimu UMEMOTO if (setsockopt(sd, IPPROTO_IPV6, IPV6_PORTRANGE, 58728c645cfSHajimu UMEMOTO (char *)&arg, sizeof(arg)) == -1) 588346298f0SDag-Erling Smørgrav goto sysouch; 58928c645cfSHajimu UMEMOTO #endif 59028c645cfSHajimu UMEMOTO break; 59128c645cfSHajimu UMEMOTO case AF_INET: 59228c645cfSHajimu UMEMOTO ((struct sockaddr_in *)&sin)->sin_port = 0; 593f5f109a0SDag-Erling Smørgrav arg = high ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; 594f5f109a0SDag-Erling Smørgrav if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE, 59532425dafSDag-Erling Smørgrav (char *)&arg, sizeof arg) == -1) 596f5f109a0SDag-Erling Smørgrav goto sysouch; 59728c645cfSHajimu UMEMOTO break; 59828c645cfSHajimu UMEMOTO } 599f5f109a0SDag-Erling Smørgrav if (verbose) 600f5f109a0SDag-Erling Smørgrav _fetch_info("binding data socket"); 60128c645cfSHajimu UMEMOTO if (bind(sd, (struct sockaddr *)&sin, sin.ss_len) == -1) 602346298f0SDag-Erling Smørgrav goto sysouch; 603ecc91352SDag-Erling Smørgrav if (listen(sd, 1) == -1) 604346298f0SDag-Erling Smørgrav goto sysouch; 605346298f0SDag-Erling Smørgrav 606346298f0SDag-Erling Smørgrav /* find what port we're on and tell the server */ 607ecc91352SDag-Erling Smørgrav if (getsockname(sd, (struct sockaddr *)&sin, &l) == -1) 608346298f0SDag-Erling Smørgrav goto sysouch; 60928c645cfSHajimu UMEMOTO switch (sin.ss_family) { 61028c645cfSHajimu UMEMOTO case AF_INET: 61128c645cfSHajimu UMEMOTO sin4 = (struct sockaddr_in *)&sin; 61228c645cfSHajimu UMEMOTO a = ntohl(sin4->sin_addr.s_addr); 61328c645cfSHajimu UMEMOTO p = ntohs(sin4->sin_port); 614fc6e9e65SDag-Erling Smørgrav e = _ftp_cmd(cd, "PORT %d,%d,%d,%d,%d,%d", 6155aea254fSDag-Erling Smørgrav (a >> 24) & 0xff, (a >> 16) & 0xff, 6165aea254fSDag-Erling Smørgrav (a >> 8) & 0xff, a & 0xff, 6175aea254fSDag-Erling Smørgrav (p >> 8) & 0xff, p & 0xff); 61828c645cfSHajimu UMEMOTO break; 61928c645cfSHajimu UMEMOTO case AF_INET6: 62028c645cfSHajimu UMEMOTO #define UC(b) (((int)b)&0xff) 62128c645cfSHajimu UMEMOTO e = -1; 62228c645cfSHajimu UMEMOTO sin6 = (struct sockaddr_in6 *)&sin; 62328c645cfSHajimu UMEMOTO if (getnameinfo((struct sockaddr *)&sin, sin.ss_len, 62428c645cfSHajimu UMEMOTO hname, sizeof(hname), 62528c645cfSHajimu UMEMOTO NULL, 0, NI_NUMERICHOST) == 0) { 62628c645cfSHajimu UMEMOTO e = _ftp_cmd(cd, "EPRT |%d|%s|%d|", 2, hname, 62728c645cfSHajimu UMEMOTO htons(sin6->sin6_port)); 62828c645cfSHajimu UMEMOTO if (e == -1) 62928c645cfSHajimu UMEMOTO goto ouch; 63028c645cfSHajimu UMEMOTO } 63128c645cfSHajimu UMEMOTO if (e != FTP_OK) { 63228c645cfSHajimu UMEMOTO ap = (char *)&sin6->sin6_addr; 63328c645cfSHajimu UMEMOTO e = _ftp_cmd(cd, 63428c645cfSHajimu UMEMOTO "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 63528c645cfSHajimu UMEMOTO 6, 16, 63628c645cfSHajimu UMEMOTO UC(ap[0]), UC(ap[1]), UC(ap[2]), UC(ap[3]), 63728c645cfSHajimu UMEMOTO UC(ap[4]), UC(ap[5]), UC(ap[6]), UC(ap[7]), 63828c645cfSHajimu UMEMOTO UC(ap[8]), UC(ap[9]), UC(ap[10]), UC(ap[11]), 63928c645cfSHajimu UMEMOTO UC(ap[12]), UC(ap[13]), UC(ap[14]), UC(ap[15]), 64028c645cfSHajimu UMEMOTO 2, 64128c645cfSHajimu UMEMOTO (ntohs(sin6->sin6_port) >> 8) & 0xff, 64228c645cfSHajimu UMEMOTO ntohs(sin6->sin6_port) & 0xff); 64328c645cfSHajimu UMEMOTO } 64428c645cfSHajimu UMEMOTO break; 64528c645cfSHajimu UMEMOTO default: 6465cd33c40SDag-Erling Smørgrav e = FTP_PROTOCOL_ERROR; /* XXX: error code should be prepared */ 64728c645cfSHajimu UMEMOTO goto ouch; 64828c645cfSHajimu UMEMOTO } 6495aea254fSDag-Erling Smørgrav if (e != FTP_OK) 650346298f0SDag-Erling Smørgrav goto ouch; 651346298f0SDag-Erling Smørgrav 652893980adSDag-Erling Smørgrav /* seek to required offset */ 653893980adSDag-Erling Smørgrav if (offset) 654893980adSDag-Erling Smørgrav if (_ftp_cmd(cd, "REST %lu", (u_long)offset) != FTP_FILE_OK) 655893980adSDag-Erling Smørgrav goto sysouch; 656893980adSDag-Erling Smørgrav 657346298f0SDag-Erling Smørgrav /* make the server initiate the transfer */ 658f5f109a0SDag-Erling Smørgrav if (verbose) 659f5f109a0SDag-Erling Smørgrav _fetch_info("initiating transfer"); 6601a5faa10SDag-Erling Smørgrav e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file)); 6615aea254fSDag-Erling Smørgrav if (e != FTP_OPEN_DATA_CONNECTION) 662346298f0SDag-Erling Smørgrav goto ouch; 663346298f0SDag-Erling Smørgrav 664346298f0SDag-Erling Smørgrav /* accept the incoming connection and go to town */ 665ecc91352SDag-Erling Smørgrav if ((d = accept(sd, NULL, NULL)) == -1) 666346298f0SDag-Erling Smørgrav goto sysouch; 667346298f0SDag-Erling Smørgrav close(sd); 668346298f0SDag-Erling Smørgrav sd = d; 669346298f0SDag-Erling Smørgrav } 670346298f0SDag-Erling Smørgrav 671c7d40ef2SDag-Erling Smørgrav if ((df = _ftp_setup(cd, sd, mode)) == NULL) 672346298f0SDag-Erling Smørgrav goto sysouch; 673346298f0SDag-Erling Smørgrav return df; 674346298f0SDag-Erling Smørgrav 675346298f0SDag-Erling Smørgrav sysouch: 676842a95ccSDag-Erling Smørgrav _fetch_syserr(); 67728c645cfSHajimu UMEMOTO if (sd >= 0) 6785aea254fSDag-Erling Smørgrav close(sd); 6795aea254fSDag-Erling Smørgrav return NULL; 6805aea254fSDag-Erling Smørgrav 681346298f0SDag-Erling Smørgrav ouch: 682fc6e9e65SDag-Erling Smørgrav if (e != -1) 6835aea254fSDag-Erling Smørgrav _ftp_seterr(e); 68428c645cfSHajimu UMEMOTO if (sd >= 0) 685346298f0SDag-Erling Smørgrav close(sd); 6864ca1ab94SDag-Erling Smørgrav return NULL; 6874ca1ab94SDag-Erling Smørgrav } 6884ca1ab94SDag-Erling Smørgrav 6898e3986eaSDag-Erling Smørgrav /* 69010851dc4SDag-Erling Smørgrav * Return default port 69110851dc4SDag-Erling Smørgrav */ 69210851dc4SDag-Erling Smørgrav static int 69310851dc4SDag-Erling Smørgrav _ftp_default_port(void) 69410851dc4SDag-Erling Smørgrav { 69510851dc4SDag-Erling Smørgrav struct servent *se; 69610851dc4SDag-Erling Smørgrav 6971a16ed4cSDag-Erling Smørgrav if ((se = getservbyname(SCHEME_FTP, "tcp")) != NULL) 69810851dc4SDag-Erling Smørgrav return ntohs(se->s_port); 69910851dc4SDag-Erling Smørgrav return FTP_DEFAULT_PORT; 70010851dc4SDag-Erling Smørgrav } 70110851dc4SDag-Erling Smørgrav 70210851dc4SDag-Erling Smørgrav /* 7038e3986eaSDag-Erling Smørgrav * Log on to FTP server 7044ca1ab94SDag-Erling Smørgrav */ 705fc6e9e65SDag-Erling Smørgrav static int 7061a16ed4cSDag-Erling Smørgrav _ftp_connect(struct url *url, struct url *purl, char *flags) 7078e3986eaSDag-Erling Smørgrav { 7081a16ed4cSDag-Erling Smørgrav int cd, e, direct, verbose; 70928c645cfSHajimu UMEMOTO #ifdef INET6 71028c645cfSHajimu UMEMOTO int af = AF_UNSPEC; 71128c645cfSHajimu UMEMOTO #else 71228c645cfSHajimu UMEMOTO int af = AF_INET; 71328c645cfSHajimu UMEMOTO #endif 7144ab587f4SHajimu UMEMOTO const char *logname; 7151a16ed4cSDag-Erling Smørgrav char *user, *pwd; 7164ab587f4SHajimu UMEMOTO char localhost[MAXHOSTNAMELEN]; 7174ab587f4SHajimu UMEMOTO char pbuf[MAXHOSTNAMELEN + MAXLOGNAME + 1]; 7188e3986eaSDag-Erling Smørgrav 719f5f109a0SDag-Erling Smørgrav direct = (flags && strchr(flags, 'd')); 720f5f109a0SDag-Erling Smørgrav verbose = (flags && strchr(flags, 'v')); 72128c645cfSHajimu UMEMOTO if ((flags && strchr(flags, '4'))) 72228c645cfSHajimu UMEMOTO af = AF_INET; 72328c645cfSHajimu UMEMOTO else if ((flags && strchr(flags, '6'))) 72428c645cfSHajimu UMEMOTO af = AF_INET6; 725f5f109a0SDag-Erling Smørgrav 7261a16ed4cSDag-Erling Smørgrav if (direct) 7271a16ed4cSDag-Erling Smørgrav purl = NULL; 72828c645cfSHajimu UMEMOTO 7291a16ed4cSDag-Erling Smørgrav /* check for proxy */ 7301a16ed4cSDag-Erling Smørgrav if (purl) { 7311a16ed4cSDag-Erling Smørgrav /* XXX proxy authentication! */ 7321a16ed4cSDag-Erling Smørgrav cd = _fetch_connect(purl->host, purl->port, af, verbose); 733f62e5228SDag-Erling Smørgrav } else { 734f62e5228SDag-Erling Smørgrav /* no proxy, go straight to target */ 7351a16ed4cSDag-Erling Smørgrav cd = _fetch_connect(url->host, url->port, af, verbose); 7361a16ed4cSDag-Erling Smørgrav purl = NULL; 737f62e5228SDag-Erling Smørgrav } 738f62e5228SDag-Erling Smørgrav 739f62e5228SDag-Erling Smørgrav /* check connection */ 740fc6e9e65SDag-Erling Smørgrav if (cd == -1) { 741842a95ccSDag-Erling Smørgrav _fetch_syserr(); 7428e3986eaSDag-Erling Smørgrav return NULL; 7438e3986eaSDag-Erling Smørgrav } 744f62e5228SDag-Erling Smørgrav 7458e3986eaSDag-Erling Smørgrav /* expect welcome message */ 746fc6e9e65SDag-Erling Smørgrav if ((e = _ftp_chkerr(cd)) != FTP_SERVICE_READY) 7478e3986eaSDag-Erling Smørgrav goto fouch; 7488e3986eaSDag-Erling Smørgrav 7491a16ed4cSDag-Erling Smørgrav /* XXX FTP_AUTH, and maybe .netrc */ 7501a16ed4cSDag-Erling Smørgrav 7518e3986eaSDag-Erling Smørgrav /* send user name and password */ 7521a16ed4cSDag-Erling Smørgrav user = url->user; 753f62e5228SDag-Erling Smørgrav if (!user || !*user) 754f62e5228SDag-Erling Smørgrav user = FTP_ANONYMOUS_USER; 7551a16ed4cSDag-Erling Smørgrav if (purl && url->port == FTP_DEFAULT_PORT) 756cb5b7353SDag-Erling Smørgrav e = _ftp_cmd(cd, "USER %s@%s", user, url->host); 7571a16ed4cSDag-Erling Smørgrav else if (purl) 758cb5b7353SDag-Erling Smørgrav e = _ftp_cmd(cd, "USER %s@%s@%d", user, url->host, url->port); 7592e88106bSDag-Erling Smørgrav else 760cb5b7353SDag-Erling Smørgrav e = _ftp_cmd(cd, "USER %s", user); 761f62e5228SDag-Erling Smørgrav 762f62e5228SDag-Erling Smørgrav /* did the server request a password? */ 763f62e5228SDag-Erling Smørgrav if (e == FTP_NEED_PASSWORD) { 7641a16ed4cSDag-Erling Smørgrav pwd = url->pwd; 765f62e5228SDag-Erling Smørgrav if (!pwd || !*pwd) 7664ab587f4SHajimu UMEMOTO pwd = getenv("FTP_PASSWORD"); 7674ab587f4SHajimu UMEMOTO if (!pwd || !*pwd) { 7684ab587f4SHajimu UMEMOTO if ((logname = getlogin()) == 0) 7694ab587f4SHajimu UMEMOTO logname = FTP_ANONYMOUS_PASSWORD; 7704ab587f4SHajimu UMEMOTO gethostname(localhost, sizeof localhost); 7714ab587f4SHajimu UMEMOTO snprintf(pbuf, sizeof pbuf, "%s@%s", logname, localhost); 7724ab587f4SHajimu UMEMOTO pwd = pbuf; 7734ab587f4SHajimu UMEMOTO } 774fc6e9e65SDag-Erling Smørgrav e = _ftp_cmd(cd, "PASS %s", pwd); 775f62e5228SDag-Erling Smørgrav } 776f62e5228SDag-Erling Smørgrav 777f62e5228SDag-Erling Smørgrav /* did the server request an account? */ 7785aea254fSDag-Erling Smørgrav if (e == FTP_NEED_ACCOUNT) 7793b7a6740SDag-Erling Smørgrav goto fouch; 780f62e5228SDag-Erling Smørgrav 781f62e5228SDag-Erling Smørgrav /* we should be done by now */ 7825aea254fSDag-Erling Smørgrav if (e != FTP_LOGGED_IN) 7838e3986eaSDag-Erling Smørgrav goto fouch; 7848e3986eaSDag-Erling Smørgrav 7858e3986eaSDag-Erling Smørgrav /* might as well select mode and type at once */ 7868e3986eaSDag-Erling Smørgrav #ifdef FTP_FORCE_STREAM_MODE 787fc6e9e65SDag-Erling Smørgrav if ((e = _ftp_cmd(cd, "MODE S")) != FTP_OK) /* default is S */ 7885aea254fSDag-Erling Smørgrav goto fouch; 7898e3986eaSDag-Erling Smørgrav #endif 790fc6e9e65SDag-Erling Smørgrav if ((e = _ftp_cmd(cd, "TYPE I")) != FTP_OK) /* default is A */ 7915aea254fSDag-Erling Smørgrav goto fouch; 7928e3986eaSDag-Erling Smørgrav 7938e3986eaSDag-Erling Smørgrav /* done */ 794fc6e9e65SDag-Erling Smørgrav return cd; 7958e3986eaSDag-Erling Smørgrav 7968e3986eaSDag-Erling Smørgrav fouch: 797fc6e9e65SDag-Erling Smørgrav if (e != -1) 7985aea254fSDag-Erling Smørgrav _ftp_seterr(e); 799fc6e9e65SDag-Erling Smørgrav close(cd); 8008e3986eaSDag-Erling Smørgrav return NULL; 8018e3986eaSDag-Erling Smørgrav } 8028e3986eaSDag-Erling Smørgrav 8038e3986eaSDag-Erling Smørgrav /* 8048e3986eaSDag-Erling Smørgrav * Disconnect from server 8058e3986eaSDag-Erling Smørgrav */ 8068e3986eaSDag-Erling Smørgrav static void 807fc6e9e65SDag-Erling Smørgrav _ftp_disconnect(int cd) 8088e3986eaSDag-Erling Smørgrav { 809fc6e9e65SDag-Erling Smørgrav (void)_ftp_cmd(cd, "QUIT"); 810fc6e9e65SDag-Erling Smørgrav close(cd); 8118e3986eaSDag-Erling Smørgrav } 8128e3986eaSDag-Erling Smørgrav 8138e3986eaSDag-Erling Smørgrav /* 8148e3986eaSDag-Erling Smørgrav * Check if we're already connected 8158e3986eaSDag-Erling Smørgrav */ 8168e3986eaSDag-Erling Smørgrav static int 817d8acd8dcSDag-Erling Smørgrav _ftp_isconnected(struct url *url) 8188e3986eaSDag-Erling Smørgrav { 8198e3986eaSDag-Erling Smørgrav return (cached_socket 8208e3986eaSDag-Erling Smørgrav && (strcmp(url->host, cached_host.host) == 0) 8218e3986eaSDag-Erling Smørgrav && (strcmp(url->user, cached_host.user) == 0) 8228e3986eaSDag-Erling Smørgrav && (strcmp(url->pwd, cached_host.pwd) == 0) 8238e3986eaSDag-Erling Smørgrav && (url->port == cached_host.port)); 8248e3986eaSDag-Erling Smørgrav } 8258e3986eaSDag-Erling Smørgrav 826f62e5228SDag-Erling Smørgrav /* 8275aea254fSDag-Erling Smørgrav * Check the cache, reconnect if no luck 828f62e5228SDag-Erling Smørgrav */ 829fc6e9e65SDag-Erling Smørgrav static int 8301a16ed4cSDag-Erling Smørgrav _ftp_cached_connect(struct url *url, struct url *purl, char *flags) 8314ca1ab94SDag-Erling Smørgrav { 832fc6e9e65SDag-Erling Smørgrav int e, cd; 8335aea254fSDag-Erling Smørgrav 834fc6e9e65SDag-Erling Smørgrav cd = -1; 8358e3986eaSDag-Erling Smørgrav 8368e3986eaSDag-Erling Smørgrav /* set default port */ 83710851dc4SDag-Erling Smørgrav if (!url->port) 83810851dc4SDag-Erling Smørgrav url->port = _ftp_default_port(); 8398e3986eaSDag-Erling Smørgrav 8403b7a6740SDag-Erling Smørgrav /* try to use previously cached connection */ 841fc6e9e65SDag-Erling Smørgrav if (_ftp_isconnected(url)) { 842fc6e9e65SDag-Erling Smørgrav e = _ftp_cmd(cached_socket, "NOOP"); 843fc6e9e65SDag-Erling Smørgrav if (e == FTP_OK || e == FTP_SYNTAX_ERROR) 8441a16ed4cSDag-Erling Smørgrav return cached_socket; 845fc6e9e65SDag-Erling Smørgrav } 8464ca1ab94SDag-Erling Smørgrav 8478e3986eaSDag-Erling Smørgrav /* connect to server */ 8481a16ed4cSDag-Erling Smørgrav if ((cd = _ftp_connect(url, purl, flags)) == -1) 849fc6e9e65SDag-Erling Smørgrav return -1; 8508e3986eaSDag-Erling Smørgrav if (cached_socket) 8518e3986eaSDag-Erling Smørgrav _ftp_disconnect(cached_socket); 852fc6e9e65SDag-Erling Smørgrav cached_socket = cd; 85332425dafSDag-Erling Smørgrav memcpy(&cached_host, url, sizeof *url); 854fc6e9e65SDag-Erling Smørgrav return cd; 8558e3986eaSDag-Erling Smørgrav } 8568e3986eaSDag-Erling Smørgrav 8578e3986eaSDag-Erling Smørgrav /* 8581a16ed4cSDag-Erling Smørgrav * Check the proxy settings 859dfe7c55fSDag-Erling Smørgrav */ 8601a16ed4cSDag-Erling Smørgrav static struct url * 8611a16ed4cSDag-Erling Smørgrav _ftp_get_proxy(void) 862dfe7c55fSDag-Erling Smørgrav { 8631a16ed4cSDag-Erling Smørgrav struct url *purl; 864dfe7c55fSDag-Erling Smørgrav char *p; 865dfe7c55fSDag-Erling Smørgrav 8661a16ed4cSDag-Erling Smørgrav if (((p = getenv("FTP_PROXY")) || (p = getenv("HTTP_PROXY"))) && 8671a16ed4cSDag-Erling Smørgrav *p && (purl = fetchParseURL(p)) != NULL) { 8681a16ed4cSDag-Erling Smørgrav if (!*purl->scheme) 8691a16ed4cSDag-Erling Smørgrav strcpy(purl->scheme, SCHEME_FTP); 8701a16ed4cSDag-Erling Smørgrav if (!purl->port) 8711a16ed4cSDag-Erling Smørgrav purl->port = _ftp_default_port(); 8721a16ed4cSDag-Erling Smørgrav if (strcasecmp(purl->scheme, SCHEME_FTP) == 0 || 8731a16ed4cSDag-Erling Smørgrav strcasecmp(purl->scheme, SCHEME_HTTP) == 0) 8741a16ed4cSDag-Erling Smørgrav return purl; 8751a16ed4cSDag-Erling Smørgrav fetchFreeURL(purl); 8761a16ed4cSDag-Erling Smørgrav } 8771a16ed4cSDag-Erling Smørgrav return NULL; 878dfe7c55fSDag-Erling Smørgrav } 879dfe7c55fSDag-Erling Smørgrav 880dfe7c55fSDag-Erling Smørgrav /* 8811a5faa10SDag-Erling Smørgrav * Get and stat file 8828e3986eaSDag-Erling Smørgrav */ 8834ca1ab94SDag-Erling Smørgrav FILE * 8841a5faa10SDag-Erling Smørgrav fetchXGetFTP(struct url *url, struct url_stat *us, char *flags) 885f62e5228SDag-Erling Smørgrav { 8861a16ed4cSDag-Erling Smørgrav struct url *purl; 887fc6e9e65SDag-Erling Smørgrav int cd; 8885aea254fSDag-Erling Smørgrav 8891a16ed4cSDag-Erling Smørgrav /* get the proxy URL, and check if we should use HTTP instead */ 8901a16ed4cSDag-Erling Smørgrav if (!strchr(flags, 'd') && (purl = _ftp_get_proxy()) != NULL) { 8911a16ed4cSDag-Erling Smørgrav if (strcasecmp(purl->scheme, SCHEME_HTTP) == 0) 8921a16ed4cSDag-Erling Smørgrav return _http_request(url, "GET", us, purl, flags); 8931a16ed4cSDag-Erling Smørgrav } else { 8941a16ed4cSDag-Erling Smørgrav purl = NULL; 8951a16ed4cSDag-Erling Smørgrav } 896dfe7c55fSDag-Erling Smørgrav 8975aea254fSDag-Erling Smørgrav /* connect to server */ 8981a16ed4cSDag-Erling Smørgrav cd = _ftp_cached_connect(url, purl, flags); 8991a16ed4cSDag-Erling Smørgrav if (purl) 9001a16ed4cSDag-Erling Smørgrav fetchFreeURL(purl); 9011a16ed4cSDag-Erling Smørgrav if (cd == NULL) 9025aea254fSDag-Erling Smørgrav return NULL; 9035aea254fSDag-Erling Smørgrav 9041a5faa10SDag-Erling Smørgrav /* change directory */ 9051a5faa10SDag-Erling Smørgrav if (_ftp_cwd(cd, url->doc) == -1) 9061a5faa10SDag-Erling Smørgrav return NULL; 9071a5faa10SDag-Erling Smørgrav 9081a5faa10SDag-Erling Smørgrav /* stat file */ 909269532d9SDag-Erling Smørgrav if (us && _ftp_stat(cd, url->doc, us) == -1 9100f27c783SDag-Erling Smørgrav && fetchLastErrCode != FETCH_PROTO 911269532d9SDag-Erling Smørgrav && fetchLastErrCode != FETCH_UNAVAIL) 9121a5faa10SDag-Erling Smørgrav return NULL; 9131a5faa10SDag-Erling Smørgrav 9145aea254fSDag-Erling Smørgrav /* initiate the transfer */ 915c7d40ef2SDag-Erling Smørgrav return _ftp_transfer(cd, "RETR", url->doc, O_RDONLY, url->offset, flags); 916f62e5228SDag-Erling Smørgrav } 917f62e5228SDag-Erling Smørgrav 9185aea254fSDag-Erling Smørgrav /* 9191a5faa10SDag-Erling Smørgrav * Get file 9201a5faa10SDag-Erling Smørgrav */ 9211a5faa10SDag-Erling Smørgrav FILE * 9221a5faa10SDag-Erling Smørgrav fetchGetFTP(struct url *url, char *flags) 9231a5faa10SDag-Erling Smørgrav { 9241a5faa10SDag-Erling Smørgrav return fetchXGetFTP(url, NULL, flags); 9251a5faa10SDag-Erling Smørgrav } 9261a5faa10SDag-Erling Smørgrav 9271a5faa10SDag-Erling Smørgrav /* 9285aea254fSDag-Erling Smørgrav * Put file 9295aea254fSDag-Erling Smørgrav */ 930f62e5228SDag-Erling Smørgrav FILE * 931d8acd8dcSDag-Erling Smørgrav fetchPutFTP(struct url *url, char *flags) 9324ca1ab94SDag-Erling Smørgrav { 9331a16ed4cSDag-Erling Smørgrav struct url *purl; 934fc6e9e65SDag-Erling Smørgrav int cd; 9355aea254fSDag-Erling Smørgrav 9361a16ed4cSDag-Erling Smørgrav /* get the proxy URL, and check if we should use HTTP instead */ 9371a16ed4cSDag-Erling Smørgrav if (!strchr(flags, 'd') && (purl = _ftp_get_proxy()) != NULL) { 9381a16ed4cSDag-Erling Smørgrav if (strcasecmp(purl->scheme, SCHEME_HTTP) == 0) 9391a16ed4cSDag-Erling Smørgrav /* XXX HTTP PUT is not implemented, so try without the proxy */ 9401a16ed4cSDag-Erling Smørgrav purl = NULL; 9411a16ed4cSDag-Erling Smørgrav } else { 9421a16ed4cSDag-Erling Smørgrav purl = NULL; 9431a16ed4cSDag-Erling Smørgrav } 944dfe7c55fSDag-Erling Smørgrav 9455aea254fSDag-Erling Smørgrav /* connect to server */ 9461a16ed4cSDag-Erling Smørgrav cd = _ftp_cached_connect(url, purl, flags); 9471a16ed4cSDag-Erling Smørgrav if (purl) 9481a16ed4cSDag-Erling Smørgrav fetchFreeURL(purl); 9491a16ed4cSDag-Erling Smørgrav if (cd == NULL) 9505aea254fSDag-Erling Smørgrav return NULL; 9515aea254fSDag-Erling Smørgrav 9521a5faa10SDag-Erling Smørgrav /* change directory */ 9531a5faa10SDag-Erling Smørgrav if (_ftp_cwd(cd, url->doc) == -1) 9541a5faa10SDag-Erling Smørgrav return NULL; 9551a5faa10SDag-Erling Smørgrav 9565aea254fSDag-Erling Smørgrav /* initiate the transfer */ 957fc6e9e65SDag-Erling Smørgrav return _ftp_transfer(cd, (flags && strchr(flags, 'a')) ? "APPE" : "STOR", 958c7d40ef2SDag-Erling Smørgrav url->doc, O_WRONLY, url->offset, flags); 9598e3986eaSDag-Erling Smørgrav } 960d8acd8dcSDag-Erling Smørgrav 9615aea254fSDag-Erling Smørgrav /* 9625aea254fSDag-Erling Smørgrav * Get file stats 9635aea254fSDag-Erling Smørgrav */ 964d8acd8dcSDag-Erling Smørgrav int 965d8acd8dcSDag-Erling Smørgrav fetchStatFTP(struct url *url, struct url_stat *us, char *flags) 966d8acd8dcSDag-Erling Smørgrav { 9671a16ed4cSDag-Erling Smørgrav struct url *purl; 9681a5faa10SDag-Erling Smørgrav int cd; 9695aea254fSDag-Erling Smørgrav 9701a16ed4cSDag-Erling Smørgrav /* get the proxy URL, and check if we should use HTTP instead */ 9711a16ed4cSDag-Erling Smørgrav if (!strchr(flags, 'd') && (purl = _ftp_get_proxy()) != NULL) { 9721a16ed4cSDag-Erling Smørgrav if (strcasecmp(purl->scheme, SCHEME_HTTP) == 0) { 9731a16ed4cSDag-Erling Smørgrav FILE *f; 9741a16ed4cSDag-Erling Smørgrav 9751a16ed4cSDag-Erling Smørgrav if ((f = _http_request(url, "HEAD", us, purl, flags)) == NULL) 9761a16ed4cSDag-Erling Smørgrav return -1; 9771a16ed4cSDag-Erling Smørgrav fclose(f); 9781a16ed4cSDag-Erling Smørgrav return 0; 9791a16ed4cSDag-Erling Smørgrav } 9801a16ed4cSDag-Erling Smørgrav } else { 9811a16ed4cSDag-Erling Smørgrav purl = NULL; 9821a16ed4cSDag-Erling Smørgrav } 983dfe7c55fSDag-Erling Smørgrav 9845aea254fSDag-Erling Smørgrav /* connect to server */ 9851a16ed4cSDag-Erling Smørgrav cd = _ftp_cached_connect(url, purl, flags); 9861a16ed4cSDag-Erling Smørgrav if (purl) 9871a16ed4cSDag-Erling Smørgrav fetchFreeURL(purl); 9881a16ed4cSDag-Erling Smørgrav if (cd == NULL) 9891a16ed4cSDag-Erling Smørgrav return NULL; 9905aea254fSDag-Erling Smørgrav 9915aea254fSDag-Erling Smørgrav /* change directory */ 9921a5faa10SDag-Erling Smørgrav if (_ftp_cwd(cd, url->doc) == -1) 9935aea254fSDag-Erling Smørgrav return -1; 9945aea254fSDag-Erling Smørgrav 9951a5faa10SDag-Erling Smørgrav /* stat file */ 9961a5faa10SDag-Erling Smørgrav return _ftp_stat(cd, url->doc, us); 997d8acd8dcSDag-Erling Smørgrav } 998ce71b736SDag-Erling Smørgrav 999ce71b736SDag-Erling Smørgrav /* 1000ce71b736SDag-Erling Smørgrav * List a directory 1001ce71b736SDag-Erling Smørgrav */ 1002ce71b736SDag-Erling Smørgrav extern void warnx(char *, ...); 1003ce71b736SDag-Erling Smørgrav struct url_ent * 1004ce71b736SDag-Erling Smørgrav fetchListFTP(struct url *url, char *flags) 1005ce71b736SDag-Erling Smørgrav { 1006def5f54cSDag-Erling Smørgrav warnx("fetchListFTP(): not implemented"); 1007ce71b736SDag-Erling Smørgrav return NULL; 1008ce71b736SDag-Erling Smørgrav } 1009