[BACK]Return to fetch.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / ftp

Annotation of src/usr.bin/ftp/fetch.c, Revision 1.30

1.30    ! lukem       1: /*     $NetBSD: fetch.c,v 1.29 1998/08/04 03:35:24 lukem Exp $ */
1.1       lukem       2:
                      3: /*-
1.25      lukem       4:  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
1.1       lukem       5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Jason Thorpe and Luke Mewburn.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *        This product includes software developed by the NetBSD
                     21:  *        Foundation, Inc. and its contributors.
                     22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     23:  *    contributors may be used to endorse or promote products derived
                     24:  *    from this software without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1.14      lukem      29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1.1       lukem      31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     36:  * POSSIBILITY OF SUCH DAMAGE.
                     37:  */
                     38:
1.12      lukem      39: #include <sys/cdefs.h>
1.1       lukem      40: #ifndef lint
1.30    ! lukem      41: __RCSID("$NetBSD: fetch.c,v 1.29 1998/08/04 03:35:24 lukem Exp $");
1.1       lukem      42: #endif /* not lint */
                     43:
                     44: /*
                     45:  * FTP User Program -- Command line file retrieval
                     46:  */
                     47:
                     48: #include <sys/types.h>
                     49: #include <sys/param.h>
                     50: #include <sys/socket.h>
1.30    ! lukem      51: #include <sys/stat.h>
1.1       lukem      52:
                     53: #include <netinet/in.h>
                     54:
1.2       lukem      55: #include <arpa/ftp.h>
1.1       lukem      56: #include <arpa/inet.h>
                     57:
                     58: #include <ctype.h>
                     59: #include <err.h>
1.22      lukem      60: #include <errno.h>
1.1       lukem      61: #include <netdb.h>
                     62: #include <fcntl.h>
1.3       lukem      63: #include <signal.h>
1.1       lukem      64: #include <stdio.h>
                     65: #include <stdlib.h>
                     66: #include <string.h>
                     67: #include <unistd.h>
1.24      lukem      68: #include <util.h>
1.1       lukem      69:
                     70: #include "ftp_var.h"
                     71:
1.27      lukem      72: typedef enum {
                     73:        UNKNOWN_URL_T=-1,
                     74:        HTTP_URL_T,
                     75:        FTP_URL_T,
                     76:        FILE_URL_T
                     77: } url_t;
                     78:
                     79: static int     parse_url __P((const char *, const char *, url_t *, char **,
                     80:                                char **, char **, in_port_t *, char **));
1.22      lukem      81: static int     url_get __P((const char *, const char *, const char *));
1.12      lukem      82: void           aborthttp __P((int));
                     83:
                     84:
1.25      lukem      85: #define        ABOUT_URL       "about:"        /* propaganda */
                     86: #define        FILE_URL        "file://"       /* file URL prefix */
1.1       lukem      87: #define        FTP_URL         "ftp://"        /* ftp URL prefix */
                     88: #define        HTTP_URL        "http://"       /* http URL prefix */
1.5       lukem      89: #define FTP_PROXY      "ftp_proxy"     /* env var with ftp proxy location */
1.1       lukem      90: #define HTTP_PROXY     "http_proxy"    /* env var with http proxy location */
1.27      lukem      91: #define NO_PROXY       "no_proxy"      /* env var with list of non-proxied
                     92:                                         * hosts, comma or space separated */
1.1       lukem      93:
                     94:
                     95: #define EMPTYSTRING(x) ((x) == NULL || (*(x) == '\0'))
1.27      lukem      96: #define FREEPTR(x)     if ((x) != NULL) { free(x); (x) = NULL; }
                     97:
                     98: /*
                     99:  * Parse URL of form:
                    100:  *     <type>://[<user>[:<password>@]]<host>[:<port>]/<url-path>
                    101:  * Returns -1 if a parse error occurred, otherwise 0.
                    102:  * Sets type to url_t, each of the given char ** pointers to a
                    103:  * malloc(3)ed strings of the relevant section, and port to
                    104:  * 0 if not given, or the number given.
                    105:  */
                    106: static int
                    107: parse_url(url, desc, type, user, pass, host, port, path)
                    108:        const char       *url;
                    109:        const char       *desc;
                    110:        url_t            *type;
                    111:        char            **user;
                    112:        char            **pass;
                    113:        char            **host;
                    114:        in_port_t        *port;
                    115:        char            **path;
                    116: {
                    117:        char *cp, *ep, *thost;
                    118:
                    119:        if (url == NULL || desc == NULL || type == NULL || user == NULL
                    120:            || pass == NULL || host == NULL || port == NULL || path == NULL)
                    121:                errx(1, "parse_url: invoked with NULL argument!");
                    122:
                    123:        *type = UNKNOWN_URL_T;
                    124:        *user = *pass = *host = *path = NULL;
                    125:        *port = 0;
                    126:
                    127:        if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) {
                    128:                url += sizeof(HTTP_URL) - 1;
                    129:                *type = HTTP_URL_T;
                    130:        } else if (strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
                    131:                url += sizeof(FTP_URL) - 1;
                    132:                *type = FTP_URL_T;
                    133:        } else if (strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
                    134:                url += sizeof(FILE_URL) - 1;
                    135:                *type = FILE_URL_T;
                    136:        } else {
                    137:                warnx("Invalid %s `%s'", desc, url);
                    138: cleanup_parse_url:
                    139:                FREEPTR(*user);
                    140:                FREEPTR(*pass);
                    141:                FREEPTR(*host);
                    142:                FREEPTR(*path);
                    143:                return (-1);
                    144:        }
                    145:
                    146:        if (*url == '\0')
                    147:                return (0);
                    148:
                    149:                        /* find [user[:pass]@]host[:port] */
                    150:        ep = strchr(url, '/');
                    151:        if (ep == NULL)
                    152:                thost = xstrdup(url);
                    153:        else {
                    154:                size_t len = ep - url;
                    155:                thost = (char *)xmalloc(len + 1);
                    156:                strncpy(thost, url, len);
                    157:                thost[len] = '\0';
                    158:                *path = xstrdup(ep);
                    159:        }
                    160:
                    161:        cp = strchr(thost, '@');
                    162:        if (cp != NULL) {
                    163:                *user = thost;
                    164:                *cp = '\0';
                    165:                *host = xstrdup(cp + 1);
                    166:                cp = strchr(*user, ':');
                    167:                if (cp != NULL) {
                    168:                        *cp = '\0';
                    169:                        *pass = xstrdup(cp + 1);
                    170:                }
                    171:        } else
                    172:                *host = thost;
                    173:
                    174:                        /* look for [:port] */
                    175:        cp = strrchr(*host, ':');
                    176:        if (cp != NULL) {
                    177:                long nport;
                    178:
                    179:                *cp = '\0';
                    180:                nport = strtol(cp + 1, &ep, 10);
                    181:                if (nport < 1 || nport > MAX_IN_PORT_T || *ep != '\0') {
                    182:                        warnx("Invalid port `%s' in %s `%s'", cp, desc, line);
                    183:                        goto cleanup_parse_url;
                    184:                }
                    185:                *port = htons((in_port_t)nport);
                    186:        }
                    187:
                    188:        if (debug)
                    189:                fprintf(ttyout,
                    190:                    "parse_url: user `%s', pass `%s', host %s:%d, path `%s'\n",
                    191:                    *user ? *user : "", *pass ? *pass : "", *host ? *host : "",
                    192:                    ntohs(*port), *path ? *path : "");
                    193:
                    194:        return (0);
                    195: }
                    196:
1.1       lukem     197:
1.2       lukem     198: jmp_buf        httpabort;
                    199:
1.1       lukem     200: /*
1.5       lukem     201:  * Retrieve URL, via the proxy in $proxyvar if necessary.
1.1       lukem     202:  * Modifies the string argument given.
                    203:  * Returns -1 on failure, 0 on success
                    204:  */
1.12      lukem     205: static int
1.27      lukem     206: url_get(url, proxyenv, outfile)
                    207:        const char *url;
1.9       lukem     208:        const char *proxyenv;
1.22      lukem     209:        const char *outfile;
1.1       lukem     210: {
                    211:        struct sockaddr_in sin;
1.27      lukem     212:        int isredirected, isproxy;
1.12      lukem     213:        volatile int s;
1.13      lukem     214:        size_t len;
1.27      lukem     215:        char *cp, *ep;
1.29      lukem     216:        char *buf, *savefile;
1.22      lukem     217:        volatile sig_t oldintr, oldintp;
1.1       lukem     218:        off_t hashbytes;
1.22      lukem     219:        struct hostent *hp = NULL;
                    220:        int (*closefunc) __P((FILE *));
1.24      lukem     221:        FILE *fin, *fout;
                    222:        int retval;
1.25      lukem     223:        time_t mtime;
1.27      lukem     224:        url_t urltype;
                    225:        char *user, *pass, *host;
                    226:        in_port_t port;
                    227:        char *path;
1.1       lukem     228:
1.22      lukem     229:        closefunc = NULL;
1.24      lukem     230:        fin = fout = NULL;
1.1       lukem     231:        s = -1;
1.29      lukem     232:        buf = savefile = NULL;
1.27      lukem     233:        isredirected = isproxy = 0;
1.24      lukem     234:        retval = -1;
1.1       lukem     235:
1.27      lukem     236: #ifdef __GNUC__                        /* shut up gcc warnings */
1.22      lukem     237:        (void)&closefunc;
1.24      lukem     238:        (void)&fin;
1.22      lukem     239:        (void)&fout;
1.24      lukem     240:        (void)&buf;
1.12      lukem     241:        (void)&savefile;
1.24      lukem     242:        (void)&retval;
1.28      fvdl      243:        (void)&isproxy;
1.12      lukem     244: #endif
                    245:
1.27      lukem     246:        if (parse_url(url, "URL", &urltype, &user, &pass, &host, &port, &path)
                    247:            == -1)
                    248:                goto cleanup_url_get;
                    249:        if (port == 0)
                    250:                port = httpport;
1.5       lukem     251:
1.27      lukem     252:        if (urltype == FILE_URL_T && ! EMPTYSTRING(host)
                    253:            && strcasecmp(host, "localhost") != 0) {
                    254:                warnx("No support for non local file URL `%s'", url);
1.5       lukem     255:                goto cleanup_url_get;
1.9       lukem     256:        }
1.27      lukem     257:
1.9       lukem     258:        if (EMPTYSTRING(path)) {
1.25      lukem     259:                if (urltype == FTP_URL_T)
1.11      lukem     260:                        goto noftpautologin;
1.27      lukem     261:                if (urltype != HTTP_URL_T || outfile == NULL)  {
                    262:                        warnx("Invalid URL (no file after host) `%s'", url);
                    263:                        goto cleanup_url_get;
                    264:                }
1.9       lukem     265:        }
1.1       lukem     266:
1.22      lukem     267:        if (outfile)
1.29      lukem     268:                savefile = xstrdup(outfile);
1.22      lukem     269:        else {
1.29      lukem     270:                cp = strrchr(path, '/');                /* find savefile */
                    271:                if (cp != NULL)
                    272:                        savefile = xstrdup(cp + 1);
1.22      lukem     273:                else
1.29      lukem     274:                        savefile = xstrdup(path);
1.22      lukem     275:        }
1.9       lukem     276:        if (EMPTYSTRING(savefile)) {
1.25      lukem     277:                if (urltype == FTP_URL_T)
1.11      lukem     278:                        goto noftpautologin;
1.27      lukem     279:                warnx("Invalid URL (no file after directory) `%s'", url);
1.5       lukem     280:                goto cleanup_url_get;
1.9       lukem     281:        }
1.1       lukem     282:
1.25      lukem     283:        filesize = -1;
                    284:        mtime = -1;
                    285:        if (urltype == FILE_URL_T) {            /* file:// URLs */
                    286:                struct stat sb;
                    287:
                    288:                direction = "copied";
                    289:                fin = fopen(path, "r");
                    290:                if (fin == NULL) {
1.27      lukem     291:                        warn("Cannot open file `%s'", path);
1.5       lukem     292:                        goto cleanup_url_get;
                    293:                }
1.25      lukem     294:                if (fstat(fileno(fin), &sb) == 0) {
                    295:                        mtime = sb.st_mtime;
                    296:                        filesize = sb.st_size;
                    297:                }
                    298:                fprintf(ttyout, "Copying %s\n", path);
                    299:        } else {                                /* ftp:// or http:// URLs */
                    300:                direction = "retrieved";
                    301:                if (proxyenv != NULL) {                         /* use proxy */
1.27      lukem     302:                        url_t purltype;
                    303:                        char *puser, *ppass, *phost;
                    304:                        in_port_t pport;
                    305:                        char *ppath;
                    306:                        char *no_proxy;
                    307:
                    308:                        isproxy = 1;
                    309:
                    310:                                /* check URL against list of no_proxied sites */
                    311:                        no_proxy = getenv(NO_PROXY);
                    312:                        if (no_proxy != NULL) {
                    313:                                char *np, *np_copy;
                    314:                                long np_port;
                    315:                                size_t hlen, plen;
                    316:
                    317:                                np_copy = xstrdup(no_proxy);
                    318:                                hlen = strlen(host);
                    319:                                while ((cp = strsep(&np_copy, " ,")) != NULL) {
                    320:                                        if (*cp == '\0')
                    321:                                                continue;
                    322:                                        if ((np = strchr(cp, ':')) != NULL) {
                    323:                                                *np = '\0';
                    324:                                                np_port =
                    325:                                                    strtol(np + 1, &ep, 10);
                    326:                                                if (*ep != '\0')
                    327:                                                        continue;
                    328:                                                if (port !=
                    329:                                                    htons((in_port_t)np_port))
                    330:                                                        continue;
                    331:                                        }
                    332:                                        plen = strlen(cp);
                    333:                                        if (strncasecmp(host + hlen - plen,
                    334:                                            cp, plen) == 0) {
                    335:                                                isproxy = 0;
                    336:                                                break;
                    337:                                        }
                    338:                                }
                    339:                                FREEPTR(np_copy);
1.25      lukem     340:                        }
1.1       lukem     341:
1.27      lukem     342:                        if (isproxy) {
                    343:                                if (parse_url(proxyenv, "proxy URL", &purltype,
                    344:                                    &puser, &ppass, &phost, &pport, &ppath)
                    345:                                    == -1)
                    346:                                        goto cleanup_url_get;
                    347:
                    348:                                if ((purltype != HTTP_URL_T
                    349:                                     && purltype != FTP_URL_T) ||
                    350:                                    EMPTYSTRING(phost) ||
                    351:                                    (! EMPTYSTRING(ppath)
                    352:                                     && strcmp(ppath, "/") != 0)) {
                    353:                                        warnx("Malformed proxy URL `%s'",
                    354:                                            proxyenv);
                    355:                                        FREEPTR(puser);
                    356:                                        FREEPTR(ppass);
                    357:                                        FREEPTR(phost);
                    358:                                        FREEPTR(ppath);
                    359:                                        goto cleanup_url_get;
                    360:                                }
1.12      lukem     361:
1.27      lukem     362:                                FREEPTR(user);
                    363:                                user = puser;
                    364:                                FREEPTR(pass);
                    365:                                pass = ppass;
                    366:                                FREEPTR(host);
                    367:                                host = phost;
                    368:                                if (pport == 0)
                    369:                                        port = httpport;
                    370:                                else
                    371:                                        port = pport;
                    372:                                FREEPTR(path);
                    373:                                FREEPTR(ppath);
                    374:                                path = xstrdup(url);
                    375:                        }
                    376:                } /* proxyenv != NULL */
1.25      lukem     377:
                    378:                memset(&sin, 0, sizeof(sin));
                    379:                sin.sin_family = AF_INET;
                    380:
                    381:                if (isdigit((unsigned char)host[0])) {
                    382:                        if (inet_aton(host, &sin.sin_addr) == 0) {
1.27      lukem     383:                                warnx("Invalid IP address `%s'", host);
1.25      lukem     384:                                goto cleanup_url_get;
                    385:                        }
                    386:                } else {
                    387:                        hp = gethostbyname(host);
                    388:                        if (hp == NULL) {
                    389:                                warnx("%s: %s", host, hstrerror(h_errno));
                    390:                                goto cleanup_url_get;
                    391:                        }
                    392:                        if (hp->h_addrtype != AF_INET) {
1.27      lukem     393:                                warnx("`%s': not an Internet address?", host);
1.25      lukem     394:                                goto cleanup_url_get;
                    395:                        }
                    396:                        memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
1.1       lukem     397:                }
                    398:
1.27      lukem     399:                if (port == 0)
1.25      lukem     400:                        port = httpport;
                    401:                sin.sin_port = port;
                    402:
                    403:                s = socket(AF_INET, SOCK_STREAM, 0);
                    404:                if (s == -1) {
                    405:                        warn("Can't create socket");
                    406:                        goto cleanup_url_get;
1.22      lukem     407:                }
1.1       lukem     408:
1.25      lukem     409:                while (xconnect(s, (struct sockaddr *)&sin,
                    410:                    sizeof(sin)) == -1) {
                    411:                        if (errno == EINTR)
                    412:                                continue;
                    413:                        if (hp && hp->h_addr_list[1]) {
                    414:                                int oerrno = errno;
                    415:                                char *ia;
                    416:
                    417:                                ia = inet_ntoa(sin.sin_addr);
                    418:                                errno = oerrno;
1.27      lukem     419:                                warn("Connect to address `%s'", ia);
1.25      lukem     420:                                hp->h_addr_list++;
                    421:                                memcpy(&sin.sin_addr, hp->h_addr_list[0],
                    422:                                    (size_t)hp->h_length);
                    423:                                fprintf(ttyout, "Trying %s...\n",
                    424:                                    inet_ntoa(sin.sin_addr));
                    425:                                (void)close(s);
                    426:                                s = socket(AF_INET, SOCK_STREAM, 0);
                    427:                                if (s < 0) {
                    428:                                        warn("Can't create socket");
                    429:                                        goto cleanup_url_get;
                    430:                                }
                    431:                                continue;
                    432:                        }
1.27      lukem     433:                        warn("Can't connect to `%s'", host);
1.25      lukem     434:                        goto cleanup_url_get;
                    435:                }
1.24      lukem     436:
1.25      lukem     437:                fin = fdopen(s, "r+");
                    438:                /*
1.27      lukem     439:                 * Construct and send the request.
                    440:                 * Proxy requests don't want leading /.
1.25      lukem     441:                 */
1.27      lukem     442:                if (isproxy) {
                    443:                        fprintf(ttyout, "Requesting %s\n  (via %s)\n",
                    444:                            url, proxyenv);
                    445:                        fprintf(fin, "GET %s HTTP/1.0\r\n\r\n", path);
                    446:                } else {
                    447:                        fprintf(ttyout, "Requesting %s\n", url);
                    448:                        fprintf(fin, "GET %s HTTP/1.1\r\n", path);
1.25      lukem     449:                        fprintf(fin, "Host: %s\r\n", host);
                    450:                        fprintf(fin, "Connection: close\r\n\r\n");
                    451:                }
                    452:                if (fflush(fin) == EOF) {
                    453:                        warn("Writing HTTP request");
                    454:                        goto cleanup_url_get;
                    455:                }
1.1       lukem     456:
1.25      lukem     457:                                /* Read the response */
1.24      lukem     458:                if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) {
                    459:                        warn("Receiving HTTP reply");
                    460:                        goto cleanup_url_get;
                    461:                }
                    462:                while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n'))
                    463:                        buf[--len] = '\0';
                    464:                if (debug)
1.27      lukem     465:                        fprintf(ttyout, "received `%s'\n", buf);
1.1       lukem     466:
1.25      lukem     467:                cp = strchr(buf, ' ');
                    468:                if (cp == NULL)
                    469:                        goto improper;
                    470:                else
                    471:                        cp++;
                    472:                if (strncmp(cp, "301", 3) == 0 || strncmp(cp, "302", 3) == 0) {
                    473:                        isredirected++;
                    474:                } else if (strncmp(cp, "200", 3)) {
1.27      lukem     475:                        warnx("Error retrieving file `%s'", cp);
1.25      lukem     476:                        goto cleanup_url_get;
                    477:                }
                    478:
                    479:                                /* Read the rest of the header. */
1.27      lukem     480:                FREEPTR(buf);
1.25      lukem     481:                while (1) {
                    482:                        if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0))
                    483:                            == NULL) {
                    484:                                warn("Receiving HTTP reply");
                    485:                                goto cleanup_url_get;
                    486:                        }
                    487:                        while (len > 0 &&
                    488:                            (buf[len-1] == '\r' || buf[len-1] == '\n'))
                    489:                                buf[--len] = '\0';
                    490:                        if (len == 0)
                    491:                                break;
                    492:                        if (debug)
1.27      lukem     493:                                fprintf(ttyout, "received `%s'\n", buf);
1.25      lukem     494:
                    495:                                /* Look for some headers */
                    496:                        cp = buf;
1.1       lukem     497: #define CONTENTLEN "Content-Length: "
1.25      lukem     498:                        if (strncasecmp(cp, CONTENTLEN,
                    499:                            sizeof(CONTENTLEN) - 1) == 0) {
                    500:                                cp += sizeof(CONTENTLEN) - 1;
                    501:                                filesize = strtol(cp, &ep, 10);
                    502:                                if (filesize < 1 || *ep != '\0')
                    503:                                        goto improper;
                    504:                                if (debug)
                    505:                                        fprintf(ttyout,
                    506: #ifndef NO_QUAD
                    507:                                            "parsed length as: %qd\n",
                    508:                                            (long long)filesize);
                    509: #else
                    510:                                            "parsed length as: %ld\n",
                    511:                                            (long)filesize);
                    512: #endif
                    513: #define LASTMOD "Last-Modified: "
                    514:                        } else if (strncasecmp(cp, LASTMOD,
                    515:                            sizeof(LASTMOD) - 1) == 0) {
                    516:                                struct tm parsed;
                    517:                                char *t;
                    518:
                    519:                                cp += sizeof(LASTMOD) - 1;
                    520:                                                        /* RFC 1123 */
                    521:                                if ((t = strptime(cp,
                    522:                                                "%a, %d %b %Y %H:%M:%S GMT",
                    523:                                                &parsed))
                    524:                                                        /* RFC 850 */
                    525:                                    || (t = strptime(cp,
                    526:                                                "%a, %d-%b-%y %H:%M:%S GMT",
                    527:                                                &parsed))
                    528:                                                        /* asctime */
                    529:                                    || (t = strptime(cp,
                    530:                                                "%a, %b %d %H:%M:%S %Y",
                    531:                                                &parsed))) {
                    532:                                        if (*t == '\0')
                    533:                                                mtime = mktime(&parsed);
                    534:                                        if (debug && mtime != -1)
                    535:                                                fprintf(ttyout,
                    536:                                                    "parsed date as: %s",
                    537:                                                    ctime(&mtime));
                    538:                                }
1.24      lukem     539: #define LOCATION "Location: "
1.25      lukem     540:                        } else if (isredirected &&
                    541:                            strncasecmp(cp, LOCATION,
                    542:                                sizeof(LOCATION) - 1) == 0) {
                    543:                                cp += sizeof(LOCATION) - 1;
                    544:                                if (debug)
                    545:                                        fprintf(ttyout,
                    546:                                            "parsed location as: %s\n", cp);
                    547:                                if (verbose)
                    548:                                        fprintf(ttyout,
                    549:                                            "Redirected to %s\n", cp);
                    550:                                retval = url_get(cp, proxyenv, outfile);
1.27      lukem     551:                                goto cleanup_url_get;
1.25      lukem     552:                        }
1.24      lukem     553:                }
1.27      lukem     554:                FREEPTR(buf);
1.1       lukem     555:        }
                    556:
1.22      lukem     557:        oldintr = oldintp = NULL;
                    558:
                    559:                        /* Open the output file. */
                    560:        if (strcmp(savefile, "-") == 0) {
                    561:                fout = stdout;
                    562:        } else if (*savefile == '|') {
                    563:                oldintp = signal(SIGPIPE, SIG_IGN);
                    564:                fout = popen(savefile + 1, "w");
                    565:                if (fout == NULL) {
1.27      lukem     566:                        warn("Can't run `%s'", savefile + 1);
1.22      lukem     567:                        goto cleanup_url_get;
                    568:                }
                    569:                closefunc = pclose;
                    570:        } else {
                    571:                fout = fopen(savefile, "w");
                    572:                if (fout == NULL) {
1.27      lukem     573:                        warn("Can't open `%s'", savefile);
1.22      lukem     574:                        goto cleanup_url_get;
                    575:                }
                    576:                closefunc = fclose;
1.1       lukem     577:        }
                    578:
1.22      lukem     579:                        /* Trap signals */
1.2       lukem     580:        if (setjmp(httpabort)) {
                    581:                if (oldintr)
1.3       lukem     582:                        (void)signal(SIGINT, oldintr);
1.22      lukem     583:                if (oldintp)
                    584:                        (void)signal(SIGPIPE, oldintp);
1.5       lukem     585:                goto cleanup_url_get;
1.2       lukem     586:        }
                    587:        oldintr = signal(SIGINT, aborthttp);
                    588:
1.1       lukem     589:        bytes = 0;
                    590:        hashbytes = mark;
                    591:        progressmeter(-1);
1.2       lukem     592:
1.24      lukem     593:                        /* Finally, suck down the file. */
1.27      lukem     594:        buf = xmalloc(BUFSIZ);
1.24      lukem     595:        while ((len = fread(buf, sizeof(char), BUFSIZ, fin)) > 0) {
1.1       lukem     596:                bytes += len;
1.25      lukem     597:                if (fwrite(buf, sizeof(char), len, fout) != len) {
1.27      lukem     598:                        warn("Writing `%s'", savefile);
1.25      lukem     599:                        goto cleanup_url_get;
1.1       lukem     600:                }
                    601:                if (hash && !progress) {
                    602:                        while (bytes >= hashbytes) {
1.22      lukem     603:                                (void)putc('#', ttyout);
1.1       lukem     604:                                hashbytes += mark;
                    605:                        }
1.22      lukem     606:                        (void)fflush(ttyout);
1.1       lukem     607:                }
                    608:        }
                    609:        if (hash && !progress && bytes > 0) {
                    610:                if (bytes < mark)
1.22      lukem     611:                        (void)putc('#', ttyout);
                    612:                (void)putc('\n', ttyout);
                    613:                (void)fflush(ttyout);
1.1       lukem     614:        }
1.25      lukem     615:        if (ferror(fin)) {
                    616:                warn("Reading file");
1.5       lukem     617:                goto cleanup_url_get;
1.1       lukem     618:        }
1.2       lukem     619:        progressmeter(1);
1.25      lukem     620:        (void)fflush(fout);
1.3       lukem     621:        (void)signal(SIGINT, oldintr);
1.22      lukem     622:        if (oldintp)
                    623:                (void)signal(SIGPIPE, oldintp);
1.25      lukem     624:        if (closefunc == fclose && mtime != -1) {
                    625:                struct timeval tval[2];
                    626:
                    627:                (void)gettimeofday(&tval[0], NULL);
                    628:                tval[1].tv_sec = mtime;
                    629:                tval[1].tv_usec = 0;
                    630:                if (futimes(fileno(fout), tval) == -1) {
                    631:                        fprintf(ttyout,
                    632:                            "Can't change modification time to %s",
                    633:                            asctime(localtime(&mtime)));
                    634:                }
                    635:        }
                    636:        if (bytes > 0)
                    637:                ptransfer(0);
1.1       lukem     638:
1.24      lukem     639:        retval = 0;
                    640:        goto cleanup_url_get;
1.1       lukem     641:
1.11      lukem     642: noftpautologin:
                    643:        warnx(
                    644:            "Auto-login using ftp URLs isn't supported when using $ftp_proxy");
                    645:        goto cleanup_url_get;
                    646:
1.1       lukem     647: improper:
1.27      lukem     648:        warnx("Improper response from `%s'", host);
1.11      lukem     649:
1.5       lukem     650: cleanup_url_get:
1.23      thorpej   651:        resetsockbufsize();
1.24      lukem     652:        if (fin != NULL)
                    653:                fclose(fin);
                    654:        else if (s != -1)
1.1       lukem     655:                close(s);
1.22      lukem     656:        if (closefunc != NULL && fout != NULL)
                    657:                (*closefunc)(fout);
1.29      lukem     658:        FREEPTR(savefile);
1.27      lukem     659:        FREEPTR(user);
                    660:        FREEPTR(pass);
                    661:        FREEPTR(host);
                    662:        FREEPTR(path);
                    663:        FREEPTR(buf);
1.24      lukem     664:        return (retval);
1.1       lukem     665: }
                    666:
                    667: /*
1.2       lukem     668:  * Abort a http retrieval
                    669:  */
                    670: void
1.3       lukem     671: aborthttp(notused)
                    672:        int notused;
1.2       lukem     673: {
                    674:
                    675:        alarmtimer(0);
1.24      lukem     676:        fputs("\nHTTP fetch aborted.\n", ttyout);
1.22      lukem     677:        (void)fflush(ttyout);
1.2       lukem     678:        longjmp(httpabort, 1);
                    679: }
                    680:
                    681: /*
1.1       lukem     682:  * Retrieve multiple files from the command line, transferring
1.25      lukem     683:  * URLs of the form "host:path", "ftp://host/path" using the
                    684:  * ftp protocol, URLs of the form "http://host/path" using the
                    685:  * http protocol, and URLs of the form "file:///" by simple
                    686:  * copying.
1.3       lukem     687:  * If path has a trailing "/", then return (-1);
1.1       lukem     688:  * the path will be cd-ed into and the connection remains open,
                    689:  * and the function will return -1 (to indicate the connection
                    690:  * is alive).
                    691:  * If an error occurs the return value will be the offset+1 in
                    692:  * argv[] of the file that caused a problem (i.e, argv[x]
                    693:  * returns x+1)
                    694:  * Otherwise, 0 is returned if all files retrieved successfully.
                    695:  */
                    696: int
1.22      lukem     697: auto_fetch(argc, argv, outfile)
1.1       lukem     698:        int argc;
                    699:        char *argv[];
1.22      lukem     700:        char *outfile;
1.1       lukem     701: {
                    702:        static char lasthost[MAXHOSTNAMELEN];
1.27      lukem     703:        char portnum[6];                /* large enough for "65535\0" */
1.1       lukem     704:        char *xargv[5];
1.27      lukem     705:        const char *line;
                    706:        char *cp, *host, *path, *dir, *file;
1.6       lukem     707:        char *user, *pass;
1.27      lukem     708:        in_port_t port;
1.5       lukem     709:        char *ftpproxy, *httpproxy;
1.12      lukem     710:        int rval, xargc;
                    711:        volatile int argpos;
1.3       lukem     712:        int dirhasglob, filehasglob;
                    713:        char rempath[MAXPATHLEN];
1.1       lukem     714:
1.22      lukem     715: #ifdef __GNUC__                        /* to shut up gcc warnings */
                    716:        (void)&outfile;
                    717: #endif
                    718:
1.2       lukem     719:        argpos = 0;
1.1       lukem     720:
1.2       lukem     721:        if (setjmp(toplevel)) {
                    722:                if (connected)
                    723:                        disconnect(0, NULL);
1.3       lukem     724:                return (argpos + 1);
1.2       lukem     725:        }
1.3       lukem     726:        (void)signal(SIGINT, (sig_t)intr);
                    727:        (void)signal(SIGPIPE, (sig_t)lostpeer);
1.1       lukem     728:
1.5       lukem     729:        ftpproxy = getenv(FTP_PROXY);
                    730:        httpproxy = getenv(HTTP_PROXY);
1.27      lukem     731:        host = path = dir = file = user = pass = NULL;
1.5       lukem     732:
1.1       lukem     733:        /*
                    734:         * Loop through as long as there's files to fetch.
                    735:         */
1.27      lukem     736:        for (rval = 0; (rval == 0) && (argpos < argc); argpos++) {
1.1       lukem     737:                if (strchr(argv[argpos], ':') == NULL)
                    738:                        break;
1.27      lukem     739:                host = path = dir = file = user = pass = NULL;
                    740:                line = argv[argpos];
1.1       lukem     741:
1.25      lukem     742: #ifndef SMALL
                    743:                /*
                    744:                 * Check for about:*
                    745:                 */
                    746:                if (strncasecmp(line, ABOUT_URL, sizeof(ABOUT_URL) - 1) == 0) {
1.27      lukem     747:                        line += sizeof(ABOUT_URL) -1;
                    748:                        if (strcasecmp(line, "ftp") == 0) {
1.25      lukem     749:                                fprintf(ttyout, "%s\n%s\n",
1.26      lukem     750: "This version of ftp has been enhanced by Luke Mewburn <lukem@netbsd.org>.",
1.25      lukem     751: "Execute 'man ftp' for more details");
1.27      lukem     752:                        } else if (strcasecmp(line, "netbsd") == 0) {
1.25      lukem     753:                                fprintf(ttyout, "%s\n%s\n",
                    754: "NetBSD is a freely available and redistributable UNIX-like operating system.",
                    755: "For more information, see http://www.netbsd.org/index.html");
                    756:                        } else {
                    757:                                fprintf(ttyout,
1.27      lukem     758:                                    "`%s' is an interesting topic.\n", line);
1.25      lukem     759:                        }
                    760:                        continue;
                    761:                }
                    762: #endif /* SMALL */
                    763:
1.1       lukem     764:                /*
1.25      lukem     765:                 * Check for file:// and http:// URLs.
1.1       lukem     766:                 */
1.25      lukem     767:                if (strncasecmp(line, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||
                    768:                    strncasecmp(line, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
1.22      lukem     769:                        if (url_get(line, httpproxy, outfile) == -1)
1.1       lukem     770:                                rval = argpos + 1;
                    771:                        continue;
                    772:                }
                    773:
                    774:                /*
1.5       lukem     775:                 * Try FTP URL-style arguments next. If ftpproxy is
                    776:                 * set, use url_get() instead of standard ftp.
                    777:                 * Finally, try host:file.
1.1       lukem     778:                 */
1.6       lukem     779:                if (strncasecmp(line, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
1.27      lukem     780:                        int urltype;
                    781:
1.5       lukem     782:                        if (ftpproxy) {
1.22      lukem     783:                                if (url_get(line, ftpproxy, outfile) == -1)
1.5       lukem     784:                                        rval = argpos + 1;
                    785:                                continue;
                    786:                        }
1.27      lukem     787:                        if ((parse_url(line, "URL", &urltype, &user, &pass,
                    788:                            &host, &port, &path) == -1) ||
                    789:                            (user != NULL && *user == '\0') ||
                    790:                            (pass != NULL && *pass == '\0') ||
                    791:                            EMPTYSTRING(host)) {
                    792:                                warnx("Invalid URL `%s'", argv[argpos]);
1.6       lukem     793:                                rval = argpos + 1;
1.27      lukem     794:                                break;
1.6       lukem     795:                        }
                    796:                } else {                        /* classic style `host:file' */
1.27      lukem     797:                        host = xstrdup(line);
                    798:                        cp = strchr(host, ':');
                    799:                        if (cp != NULL) {
                    800:                                *cp = '\0';
                    801:                                path = xstrdup(cp + 1);
                    802:                        }
1.6       lukem     803:                }
1.1       lukem     804:                if (EMPTYSTRING(host)) {
                    805:                        rval = argpos + 1;
1.27      lukem     806:                        break;
1.1       lukem     807:                }
                    808:
                    809:                /*
1.15      lukem     810:                 * If dir is NULL, the file wasn't specified
1.1       lukem     811:                 * (URL looked something like ftp://host)
                    812:                 */
1.27      lukem     813:                dir = path;
1.6       lukem     814:                if (dir != NULL)
                    815:                        *dir++ = '\0';
1.1       lukem     816:
                    817:                /*
                    818:                 * Extract the file and (if present) directory name.
                    819:                 */
                    820:                if (! EMPTYSTRING(dir)) {
1.6       lukem     821:                        cp = strrchr(dir, '/');
1.1       lukem     822:                        if (cp != NULL) {
                    823:                                *cp++ = '\0';
                    824:                                file = cp;
                    825:                        } else {
                    826:                                file = dir;
                    827:                                dir = NULL;
                    828:                        }
                    829:                }
                    830:                if (debug)
1.22      lukem     831:                        fprintf(ttyout,
1.27      lukem     832: "auto_fetch: user `%s', pass `%s', host %s:%d, path, `%s', dir `%s', file `%s'\n",
                    833:                            user ? user : "", pass ? pass : "",
                    834:                            host ? host : "", ntohs(port), path ? path : "",
                    835:                            dir ? dir : "", file ? file : "");
1.1       lukem     836:
                    837:                /*
                    838:                 * Set up the connection if we don't have one.
                    839:                 */
1.27      lukem     840:                if (strcasecmp(host, lasthost) != 0) {
1.6       lukem     841:                        int oautologin;
                    842:
1.4       lukem     843:                        (void)strcpy(lasthost, host);
1.1       lukem     844:                        if (connected)
                    845:                                disconnect(0, NULL);
                    846:                        xargv[0] = __progname;
                    847:                        xargv[1] = host;
                    848:                        xargv[2] = NULL;
                    849:                        xargc = 2;
1.27      lukem     850:                        if (port) {
                    851:                                snprintf(portnum, sizeof(portnum),
                    852:                                    "%d", (int)port);
1.1       lukem     853:                                xargv[2] = portnum;
                    854:                                xargv[3] = NULL;
                    855:                                xargc = 3;
                    856:                        }
1.6       lukem     857:                        oautologin = autologin;
                    858:                        if (user != NULL)
                    859:                                autologin = 0;
1.1       lukem     860:                        setpeer(xargc, xargv);
1.6       lukem     861:                        autologin = oautologin;
                    862:                        if ((connected == 0)
1.24      lukem     863:                         || ((connected == 1) &&
                    864:                             !ftp_login(host, user, pass)) ) {
1.6       lukem     865:                                warnx("Can't connect or login to host `%s'",
                    866:                                    host);
1.1       lukem     867:                                rval = argpos + 1;
1.27      lukem     868:                                break;
1.1       lukem     869:                        }
                    870:
                    871:                        /* Always use binary transfers. */
                    872:                        setbinary(0, NULL);
                    873:                }
1.27      lukem     874:                        /* cd back to `/' */
1.6       lukem     875:                xargv[0] = "cd";
                    876:                xargv[1] = "/";
                    877:                xargv[2] = NULL;
                    878:                cd(2, xargv);
                    879:                if (! dirchange) {
                    880:                        rval = argpos + 1;
1.27      lukem     881:                        break;
1.1       lukem     882:                }
                    883:
1.3       lukem     884:                dirhasglob = filehasglob = 0;
                    885:                if (doglob) {
                    886:                        if (! EMPTYSTRING(dir) &&
                    887:                            strpbrk(dir, "*?[]{}") != NULL)
                    888:                                dirhasglob = 1;
                    889:                        if (! EMPTYSTRING(file) &&
                    890:                            strpbrk(file, "*?[]{}") != NULL)
                    891:                                filehasglob = 1;
                    892:                }
                    893:
1.27      lukem     894:                                /* Change directories, if necessary. */
1.3       lukem     895:                if (! EMPTYSTRING(dir) && !dirhasglob) {
1.1       lukem     896:                        xargv[0] = "cd";
                    897:                        xargv[1] = dir;
                    898:                        xargv[2] = NULL;
                    899:                        cd(2, xargv);
                    900:                        if (! dirchange) {
                    901:                                rval = argpos + 1;
1.27      lukem     902:                                break;
1.1       lukem     903:                        }
                    904:                }
                    905:
                    906:                if (EMPTYSTRING(file)) {
                    907:                        rval = -1;
1.27      lukem     908:                        break;
1.1       lukem     909:                }
                    910:
1.2       lukem     911:                if (!verbose)
1.22      lukem     912:                        fprintf(ttyout, "Retrieving %s/%s\n", dir ? dir : "",
                    913:                            file);
1.2       lukem     914:
1.3       lukem     915:                if (dirhasglob) {
                    916:                        snprintf(rempath, sizeof(rempath), "%s/%s", dir, file);
                    917:                        file = rempath;
                    918:                }
                    919:
1.27      lukem     920:                                /* Fetch the file(s). */
1.22      lukem     921:                xargc = 2;
1.1       lukem     922:                xargv[0] = "get";
                    923:                xargv[1] = file;
                    924:                xargv[2] = NULL;
1.3       lukem     925:                if (dirhasglob || filehasglob) {
                    926:                        int ointeractive;
                    927:
                    928:                        ointeractive = interactive;
                    929:                        interactive = 0;
                    930:                        xargv[0] = "mget";
1.22      lukem     931:                        mget(xargc, xargv);
1.4       lukem     932:                        interactive = ointeractive;
1.22      lukem     933:                } else {
                    934:                        if (outfile != NULL) {
                    935:                                xargv[2] = outfile;
                    936:                                xargv[3] = NULL;
                    937:                                xargc++;
                    938:                        }
                    939:                        get(xargc, xargv);
                    940:                        if (outfile != NULL && strcmp(outfile, "-") != 0
                    941:                            && outfile[0] != '|')
                    942:                                outfile = NULL;
                    943:                }
1.2       lukem     944:
1.3       lukem     945:                if ((code / 100) != COMPLETE)
1.2       lukem     946:                        rval = argpos + 1;
1.1       lukem     947:        }
                    948:        if (connected && rval != -1)
                    949:                disconnect(0, NULL);
1.27      lukem     950:        FREEPTR(host);
                    951:        FREEPTR(path);
                    952:        FREEPTR(user);
                    953:        FREEPTR(pass);
1.1       lukem     954:        return (rval);
                    955: }

CVSweb <webmaster@jp.NetBSD.org>