1 /* $OpenBSD: fetch.c,v 1.34 2001/06/23 22:48:44 millert Exp $ */ 2 /* $NetBSD: fetch.c,v 1.14 1997/08/18 10:20:20 lukem Exp $ */ 3 4 /*- 5 * Copyright (c) 1997 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jason Thorpe and Luke Mewburn. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #ifndef lint 41 static char rcsid[] = "$OpenBSD: fetch.c,v 1.34 2001/06/23 22:48:44 millert Exp $"; 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> 51 #include <sys/stat.h> 52 53 #include <netinet/in.h> 54 55 #include <arpa/ftp.h> 56 #include <arpa/inet.h> 57 58 #include <ctype.h> 59 #include <err.h> 60 #include <libgen.h> 61 #include <netdb.h> 62 #include <fcntl.h> 63 #include <signal.h> 64 #include <stdio.h> 65 #include <errno.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <unistd.h> 69 70 #include "ftp_var.h" 71 72 static int url_get __P((const char *, const char *, const char *)); 73 void aborthttp __P((int)); 74 void abortfile __P((int)); 75 76 77 #define FTP_URL "ftp://" /* ftp URL prefix */ 78 #define HTTP_URL "http://" /* http URL prefix */ 79 #define FILE_URL "file:" /* file URL prefix */ 80 #define FTP_PROXY "ftp_proxy" /* env var with ftp proxy location */ 81 #define HTTP_PROXY "http_proxy" /* env var with http proxy location */ 82 83 84 #define EMPTYSTRING(x) ((x) == NULL || (*(x) == '\0')) 85 86 jmp_buf httpabort; 87 88 /* 89 * Retrieve URL, via the proxy in $proxyvar if necessary. 90 * Modifies the string argument given. 91 * Returns -1 on failure, 0 on success 92 */ 93 static int 94 url_get(origline, proxyenv, outfile) 95 const char *origline; 96 const char *proxyenv; 97 const char *outfile; 98 { 99 struct addrinfo hints, *res0, *res; 100 int error; 101 int i, isftpurl, isfileurl; 102 volatile int s, out; 103 size_t len; 104 char c, *cp, *ep, *portnum, *path, buf[4096]; 105 char pbuf[NI_MAXSERV]; 106 const char * volatile savefile; 107 char *line, *host, *port; 108 char * volatile proxy; 109 char *hosttail; 110 volatile sig_t oldintr; 111 off_t hashbytes; 112 char *cause = "unknown"; 113 114 s = -1; 115 proxy = NULL; 116 isftpurl = 0; 117 isfileurl = 0; 118 119 line = strdup(origline); 120 if (line == NULL) 121 errx(1, "Can't allocate memory to parse URL"); 122 if (strncasecmp(line, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) 123 host = line + sizeof(HTTP_URL) - 1; 124 else if (strncasecmp(line, FTP_URL, sizeof(FTP_URL) - 1) == 0) { 125 host = line + sizeof(FTP_URL) - 1; 126 isftpurl = 1; 127 } else if (strncasecmp(line, FILE_URL, sizeof(FILE_URL) - 1) == 0) { 128 host = line + sizeof(FILE_URL) - 1; 129 isfileurl = 1; 130 } else 131 errx(1, "url_get: Invalid URL '%s'", line); 132 133 if (isfileurl) { 134 path = host; 135 } else { 136 path = strchr(host, '/'); /* find path */ 137 if (EMPTYSTRING(path)) { 138 if (isftpurl) 139 goto noftpautologin; 140 warnx("Invalid URL (no `/' after host): %s", origline); 141 goto cleanup_url_get; 142 } 143 *path++ = '\0'; 144 if (EMPTYSTRING(path)) { 145 if (isftpurl) 146 goto noftpautologin; 147 warnx("Invalid URL (no file after host): %s", origline); 148 goto cleanup_url_get; 149 } 150 } 151 152 if (outfile) 153 savefile = outfile; 154 else 155 savefile = basename(path); 156 157 if (EMPTYSTRING(savefile)) { 158 if (isftpurl) 159 goto noftpautologin; 160 warnx("Invalid URL (no file after directory): %s", origline); 161 goto cleanup_url_get; 162 } 163 164 if (proxyenv != NULL) { /* use proxy */ 165 proxy = strdup(proxyenv); 166 if (proxy == NULL) 167 errx(1, "Can't allocate memory for proxy URL."); 168 if (strncasecmp(proxy, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) 169 host = proxy + sizeof(HTTP_URL) - 1; 170 else if (strncasecmp(proxy, FTP_URL, sizeof(FTP_URL) - 1) == 0) 171 host = proxy + sizeof(FTP_URL) - 1; 172 else { 173 warnx("Malformed proxy URL: %s", proxyenv); 174 goto cleanup_url_get; 175 } 176 if (EMPTYSTRING(host)) { 177 warnx("Malformed proxy URL: %s", proxyenv); 178 goto cleanup_url_get; 179 } 180 *--path = '/'; /* add / back to real path */ 181 path = strchr(host, '/'); /* remove trailing / on host */ 182 if (! EMPTYSTRING(path)) 183 *path++ = '\0'; 184 path = line; 185 } 186 187 if (isfileurl) { 188 struct stat st; 189 190 s = open(path, O_RDONLY); 191 if (s == -1) { 192 warn("Can't open file %s", path); 193 goto cleanup_url_get; 194 } 195 196 if (fstat(s, &st) == -1) 197 filesize = -1; 198 else 199 filesize = st.st_size; 200 201 /* Open the output file. */ 202 if (strcmp(savefile, "-") != 0) { 203 out = open(savefile, O_CREAT | O_WRONLY | O_TRUNC, 0666); 204 if (out < 0) { 205 warn("Can't open %s", savefile); 206 goto cleanup_url_get; 207 } 208 } else 209 out = fileno(stdout); 210 211 /* Trap signals */ 212 oldintr = NULL; 213 if (setjmp(httpabort)) { 214 if (oldintr) 215 (void)signal(SIGINT, oldintr); 216 goto cleanup_url_get; 217 } 218 oldintr = signal(SIGINT, abortfile); 219 220 bytes = 0; 221 hashbytes = mark; 222 progressmeter(-1); 223 224 /* Finally, suck down the file. */ 225 i = 0; 226 while ((len = read(s, buf, sizeof(buf))) > 0) { 227 bytes += len; 228 for (cp = buf; len > 0; len -= i, cp += i) { 229 if ((i = write(out, cp, len)) == -1) { 230 warn("Writing %s", savefile); 231 goto cleanup_url_get; 232 } 233 else if (i == 0) 234 break; 235 } 236 if (hash && !progress) { 237 while (bytes >= hashbytes) { 238 (void)putc('#', ttyout); 239 hashbytes += mark; 240 } 241 (void)fflush(ttyout); 242 } 243 } 244 if (hash && !progress && bytes > 0) { 245 if (bytes < mark) 246 (void)putc('#', ttyout); 247 (void)putc('\n', ttyout); 248 (void)fflush(ttyout); 249 } 250 if (len != 0) { 251 warn("Reading from file"); 252 goto cleanup_url_get; 253 } 254 progressmeter(1); 255 if (verbose) 256 fputs("Successfully retrieved file.\n", ttyout); 257 (void)signal(SIGINT, oldintr); 258 259 close(s); 260 if (out != fileno(stdout)) 261 close(out); 262 if (proxy) 263 free(proxy); 264 free(line); 265 return (0); 266 } 267 268 if (*host == '[' && (hosttail = strrchr(host, ']')) != NULL && 269 (hosttail[1] == '\0' || hosttail[1] == ':')) { 270 host++; 271 *hosttail++ = '\0'; 272 } else 273 hosttail = host; 274 275 portnum = strrchr(hosttail, ':'); /* find portnum */ 276 if (portnum != NULL) 277 *portnum++ = '\0'; 278 279 if (debug) 280 fprintf(ttyout, "host %s, port %s, path %s, save as %s.\n", 281 host, portnum, path, savefile); 282 283 memset(&hints, 0, sizeof(hints)); 284 hints.ai_family = PF_UNSPEC; 285 hints.ai_socktype = SOCK_STREAM; 286 port = portnum ? portnum : httpport; 287 error = getaddrinfo(host, port, &hints, &res0); 288 if (error == EAI_SERVICE && port == httpport) { 289 /* 290 * If the services file is corrupt/missing, fall back 291 * on our hard-coded defines. 292 */ 293 char pbuf[NI_MAXSERV]; 294 295 snprintf(pbuf, sizeof(pbuf), "%d", HTTP_PORT); 296 error = getaddrinfo(host, pbuf, &hints, &res0); 297 } 298 if (error) { 299 warnx("%s: %s", gai_strerror(error), host); 300 goto cleanup_url_get; 301 } 302 303 s = -1; 304 for (res = res0; res; res = res->ai_next) { 305 getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof(buf), 306 NULL, 0, NI_NUMERICHOST); 307 fprintf(ttyout, "Trying %s...\n", buf); 308 309 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 310 if (s == -1) { 311 cause = "socket"; 312 continue; 313 } 314 315 again: 316 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { 317 if (errno == EINTR) 318 goto again; 319 close(s); 320 s = -1; 321 cause = "connect"; 322 continue; 323 } 324 325 /* get port in numeric */ 326 if (getnameinfo(res->ai_addr, res->ai_addrlen, NULL, 0, 327 pbuf, sizeof(pbuf), NI_NUMERICSERV) == 0) 328 port = pbuf; 329 else 330 port = NULL; 331 332 break; 333 } 334 freeaddrinfo(res0); 335 if (s < 0) { 336 warn("%s", cause); 337 goto cleanup_url_get; 338 } 339 340 /* 341 * Construct and send the request. We're expecting a return 342 * status of "200". Proxy requests don't want leading /. 343 */ 344 if (proxy) { 345 /* 346 * Host: directive must use the destination host address for 347 * the original URI (path). We do not attach it at this moment. 348 */ 349 if (verbose) 350 fprintf(ttyout, "Requesting %s (via %s)\n", 351 origline, proxyenv); 352 snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n", path); 353 } else { 354 if (verbose) 355 fprintf(ttyout, "Requesting %s\n", origline); 356 if (strchr(host, ':')) { 357 char *h, *p; 358 359 /* strip off scoped address portion, since it's local to node */ 360 h = strdup(host); 361 if (h == NULL) 362 errx(1, "Can't allocate memory."); 363 if ((p = strchr(h, '%')) != NULL) 364 *p = '\0'; 365 snprintf(buf, sizeof(buf), 366 "GET /%s HTTP/1.0\r\nHost: [%s]%s%s\r\n\r\n", 367 path, h, port ? ":" : "", port ? port : ""); 368 free(h); 369 } else { 370 snprintf(buf, sizeof(buf), 371 "GET /%s HTTP/1.0\r\nHost: %s%s%s\r\n\r\n", 372 path, host, port ? ":" : "", port ? port : ""); 373 } 374 } 375 len = strlen(buf); 376 if (write(s, buf, len) < len) { 377 warn("Writing HTTP request"); 378 goto cleanup_url_get; 379 } 380 memset(buf, 0, sizeof(buf)); 381 for (cp = buf; cp < buf + sizeof(buf); ) { 382 if (read(s, cp, 1) != 1) 383 goto improper; 384 if (*cp == '\r') 385 continue; 386 if (*cp == '\n') 387 break; 388 cp++; 389 } 390 buf[sizeof(buf) - 1] = '\0'; /* sanity */ 391 cp = strchr(buf, ' '); 392 if (cp == NULL) 393 goto improper; 394 else 395 cp++; 396 if (strncmp(cp, "200", 3)) { 397 warnx("Error retrieving file: %s", cp); 398 goto cleanup_url_get; 399 } 400 401 /* 402 * Read the rest of the header. 403 */ 404 memset(buf, 0, sizeof(buf)); 405 c = '\0'; 406 for (cp = buf; cp < buf + sizeof(buf); ) { 407 if (read(s, cp, 1) != 1) 408 goto improper; 409 if (*cp == '\r') 410 continue; 411 if (*cp == '\n' && c == '\n') 412 break; 413 c = *cp; 414 cp++; 415 } 416 buf[sizeof(buf) - 1] = '\0'; /* sanity */ 417 418 /* Look for the "Content-length: " header. */ 419 #define CONTENTLEN "Content-Length: " 420 for (cp = buf; *cp != '\0'; cp++) { 421 if (tolower(*cp) == 'c' && 422 strncasecmp(cp, CONTENTLEN, sizeof(CONTENTLEN) - 1) == 0) 423 break; 424 } 425 if (*cp != '\0') { 426 cp += sizeof(CONTENTLEN) - 1; 427 ep = strchr(cp, '\n'); 428 if (ep == NULL) 429 goto improper; 430 else 431 *ep = '\0'; 432 filesize = strtol(cp, &ep, 10); 433 if (filesize < 1 || *ep != '\0') 434 goto improper; 435 } else 436 filesize = -1; 437 438 /* Open the output file. */ 439 if (strcmp(savefile, "-") != 0) { 440 out = open(savefile, O_CREAT | O_WRONLY | O_TRUNC, 0666); 441 if (out < 0) { 442 warn("Can't open %s", savefile); 443 goto cleanup_url_get; 444 } 445 } else 446 out = fileno(stdout); 447 448 /* Trap signals */ 449 oldintr = NULL; 450 if (setjmp(httpabort)) { 451 if (oldintr) 452 (void)signal(SIGINT, oldintr); 453 goto cleanup_url_get; 454 } 455 oldintr = signal(SIGINT, aborthttp); 456 457 bytes = 0; 458 hashbytes = mark; 459 progressmeter(-1); 460 461 /* Finally, suck down the file. */ 462 i = 0; 463 while ((len = read(s, buf, sizeof(buf))) > 0) { 464 bytes += len; 465 for (cp = buf; len > 0; len -= i, cp += i) { 466 if ((i = write(out, cp, len)) == -1) { 467 warn("Writing %s", savefile); 468 goto cleanup_url_get; 469 } 470 else if (i == 0) 471 break; 472 } 473 if (hash && !progress) { 474 while (bytes >= hashbytes) { 475 (void)putc('#', ttyout); 476 hashbytes += mark; 477 } 478 (void)fflush(ttyout); 479 } 480 } 481 if (hash && !progress && bytes > 0) { 482 if (bytes < mark) 483 (void)putc('#', ttyout); 484 (void)putc('\n', ttyout); 485 (void)fflush(ttyout); 486 } 487 if (len != 0) { 488 warn("Reading from socket"); 489 goto cleanup_url_get; 490 } 491 progressmeter(1); 492 if (filesize != -1 && len == 0 && bytes != filesize) { 493 if (verbose) 494 fputs("Read short file.\n", ttyout); 495 goto cleanup_url_get; 496 } 497 498 if (verbose) 499 fputs("Successfully retrieved file.\n", ttyout); 500 (void)signal(SIGINT, oldintr); 501 502 close(s); 503 if (out != fileno(stdout)) 504 close(out); 505 if (proxy) 506 free(proxy); 507 free(line); 508 return (0); 509 510 noftpautologin: 511 warnx( 512 "Auto-login using ftp URLs isn't supported when using $ftp_proxy"); 513 goto cleanup_url_get; 514 515 improper: 516 warnx("Improper response from %s", host); 517 518 cleanup_url_get: 519 if (s != -1) 520 close(s); 521 if (proxy) 522 free(proxy); 523 free(line); 524 return (-1); 525 } 526 527 /* 528 * Abort a http retrieval 529 */ 530 void 531 aborthttp(notused) 532 int notused; 533 { 534 535 alarmtimer(0); 536 fputs("\nhttp fetch aborted.\n", ttyout); 537 (void)fflush(ttyout); 538 longjmp(httpabort, 1); 539 } 540 541 /* 542 * Abort a http retrieval 543 */ 544 void 545 abortfile(notused) 546 int notused; 547 { 548 549 alarmtimer(0); 550 fputs("\nfile fetch aborted.\n", ttyout); 551 (void)fflush(ttyout); 552 longjmp(httpabort, 1); 553 } 554 555 /* 556 * Retrieve multiple files from the command line, transferring 557 * files of the form "host:path", "ftp://host/path" using the 558 * ftp protocol, and files of the form "http://host/path" using 559 * the http protocol. 560 * If path has a trailing "/", then return (-1); 561 * the path will be cd-ed into and the connection remains open, 562 * and the function will return -1 (to indicate the connection 563 * is alive). 564 * If an error occurs the return value will be the offset+1 in 565 * argv[] of the file that caused a problem (i.e, argv[x] 566 * returns x+1) 567 * Otherwise, 0 is returned if all files retrieved successfully. 568 */ 569 int 570 auto_fetch(argc, argv, outfile) 571 int argc; 572 char *argv[]; 573 char *outfile; 574 { 575 static char lasthost[MAXHOSTNAMELEN]; 576 char *xargv[5]; 577 char *cp, *line, *host, *dir, *file, *portnum; 578 char *user, *pass; 579 char *ftpproxy, *httpproxy; 580 int rval, xargc; 581 volatile int argpos; 582 int dirhasglob, filehasglob; 583 char rempath[MAXPATHLEN]; 584 585 argpos = 0; 586 587 if (setjmp(toplevel)) { 588 if (connected) 589 disconnect(0, NULL); 590 return (argpos + 1); 591 } 592 (void)signal(SIGINT, (sig_t)intr); 593 (void)signal(SIGPIPE, (sig_t)lostpeer); 594 595 ftpproxy = getenv(FTP_PROXY); 596 httpproxy = getenv(HTTP_PROXY); 597 598 /* 599 * Loop through as long as there's files to fetch. 600 */ 601 for (rval = 0; (rval == 0) && (argpos < argc); free(line), argpos++) { 602 if (strchr(argv[argpos], ':') == NULL) 603 break; 604 host = dir = file = portnum = user = pass = NULL; 605 606 /* 607 * We muck with the string, so we make a copy. 608 */ 609 line = strdup(argv[argpos]); 610 if (line == NULL) 611 errx(1, "Can't allocate memory for auto-fetch."); 612 613 /* 614 * Try HTTP URL-style arguments first. 615 */ 616 if (strncasecmp(line, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 || 617 strncasecmp(line, FILE_URL, sizeof(FILE_URL) - 1) == 0) { 618 if (url_get(line, httpproxy, outfile) == -1) 619 rval = argpos + 1; 620 continue; 621 } 622 623 /* 624 * Try FTP URL-style arguments next. If ftpproxy is 625 * set, use url_get() instead of standard ftp. 626 * Finally, try host:file. 627 */ 628 host = line; 629 if (strncasecmp(line, FTP_URL, sizeof(FTP_URL) - 1) == 0) { 630 char *passend, *userend; 631 632 if (ftpproxy) { 633 if (url_get(line, ftpproxy, outfile) == -1) 634 rval = argpos + 1; 635 continue; 636 } 637 host += sizeof(FTP_URL) - 1; 638 dir = strchr(host, '/'); 639 640 /* Look for [user:pass@]host[:port] */ 641 642 /* check if we have "user:pass@" */ 643 passend = strchr(host, '@'); 644 userend = strchr(host, ':'); 645 if (passend && userend && userend < passend && 646 (!dir || passend < dir)) { 647 user = host; 648 pass = userend + 1; 649 host = passend + 1; 650 *userend = *passend = '\0'; 651 652 if (EMPTYSTRING(user) || EMPTYSTRING(pass)) { 653 bad_ftp_url: 654 warnx("Invalid URL: %s", argv[argpos]); 655 rval = argpos + 1; 656 continue; 657 } 658 } 659 660 #ifdef INET6 661 /* check [host]:port, or [host] */ 662 if (host[0] == '[') { 663 cp = strchr(host, ']'); 664 if (cp && (!dir || cp < dir)) { 665 if (cp + 1 == dir || cp[1] == ':') { 666 host++; 667 *cp++ = '\0'; 668 } else 669 cp = NULL; 670 } else 671 cp = host; 672 } else 673 cp = host; 674 #else 675 cp = host; 676 #endif 677 678 /* split off host[:port] if there is */ 679 if (cp) { 680 portnum = strchr(cp, ':'); 681 if (!portnum) 682 ; 683 else { 684 if (!dir) 685 ; 686 else if (portnum + 1 < dir) { 687 *portnum++ = '\0'; 688 /* 689 * XXX should check if portnum 690 * is decimal number 691 */ 692 } else { 693 /* empty portnum */ 694 goto bad_ftp_url; 695 } 696 } 697 } else 698 portnum = NULL; 699 } else { /* classic style `host:file' */ 700 dir = strchr(host, ':'); 701 } 702 if (EMPTYSTRING(host)) { 703 rval = argpos + 1; 704 continue; 705 } 706 707 /* 708 * If dir is NULL, the file wasn't specified 709 * (URL looked something like ftp://host) 710 */ 711 if (dir != NULL) 712 *dir++ = '\0'; 713 714 /* 715 * Extract the file and (if present) directory name. 716 */ 717 if (! EMPTYSTRING(dir)) { 718 cp = strrchr(dir, '/'); 719 if (cp != NULL) { 720 *cp++ = '\0'; 721 file = cp; 722 } else { 723 file = dir; 724 dir = NULL; 725 } 726 } 727 if (debug) 728 fprintf(ttyout, "user %s:%s host %s port %s dir %s file %s\n", 729 user, pass, host, portnum, dir, file); 730 731 /* 732 * Set up the connection if we don't have one. 733 */ 734 if (strcmp(host, lasthost) != 0) { 735 int oautologin; 736 737 (void)strcpy(lasthost, host); 738 if (connected) 739 disconnect(0, NULL); 740 xargv[0] = __progname; 741 xargv[1] = host; 742 xargv[2] = NULL; 743 xargc = 2; 744 if (! EMPTYSTRING(portnum)) { 745 xargv[2] = portnum; 746 xargv[3] = NULL; 747 xargc = 3; 748 } 749 oautologin = autologin; 750 if (user != NULL) 751 autologin = 0; 752 setpeer(xargc, xargv); 753 autologin = oautologin; 754 if ((connected == 0) || 755 ((connected == 1) && !login(host, user, pass))) { 756 warnx("Can't connect or login to host `%s'", 757 host); 758 rval = argpos + 1; 759 continue; 760 } 761 762 /* Always use binary transfers. */ 763 setbinary(0, NULL); 764 } 765 /* cd back to '/' */ 766 xargv[0] = "cd"; 767 xargv[1] = "/"; 768 xargv[2] = NULL; 769 cd(2, xargv); 770 if (! dirchange) { 771 rval = argpos + 1; 772 continue; 773 } 774 775 dirhasglob = filehasglob = 0; 776 if (doglob) { 777 if (! EMPTYSTRING(dir) && 778 strpbrk(dir, "*?[]{}") != NULL) 779 dirhasglob = 1; 780 if (! EMPTYSTRING(file) && 781 strpbrk(file, "*?[]{}") != NULL) 782 filehasglob = 1; 783 } 784 785 /* Change directories, if necessary. */ 786 if (! EMPTYSTRING(dir) && !dirhasglob) { 787 xargv[0] = "cd"; 788 xargv[1] = dir; 789 xargv[2] = NULL; 790 cd(2, xargv); 791 if (! dirchange) { 792 rval = argpos + 1; 793 continue; 794 } 795 } 796 797 if (EMPTYSTRING(file)) { 798 rval = -1; 799 continue; 800 } 801 802 if (verbose) 803 fprintf(ttyout, "Retrieving %s/%s\n", dir ? dir : "", file); 804 805 if (dirhasglob) { 806 snprintf(rempath, sizeof(rempath), "%s/%s", dir, file); 807 file = rempath; 808 } 809 810 /* Fetch the file(s). */ 811 xargc = 2; 812 xargv[0] = "get"; 813 xargv[1] = file; 814 xargv[2] = NULL; 815 if (dirhasglob || filehasglob) { 816 int ointeractive; 817 818 ointeractive = interactive; 819 interactive = 0; 820 xargv[0] = "mget"; 821 mget(xargc, xargv); 822 interactive = ointeractive; 823 } else { 824 if (outfile != NULL) { 825 xargv[2] = outfile; 826 xargv[3] = NULL; 827 xargc++; 828 } 829 get(xargc, xargv); 830 } 831 832 if ((code / 100) != COMPLETE) 833 rval = argpos + 1; 834 } 835 if (connected && rval != -1) 836 disconnect(0, NULL); 837 return (rval); 838 } 839 840 int 841 isurl(p) 842 const char *p; 843 { 844 845 if (strncasecmp(p, FTP_URL, sizeof(FTP_URL) - 1) == 0 || 846 strncasecmp(p, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 || 847 strncasecmp(p, FILE_URL, sizeof(FILE_URL) - 1) == 0 || 848 strstr(p, ":/")) 849 return (1); 850 return (0); 851 } 852