1 /* $OpenBSD: cmds.c,v 1.70 2009/05/05 19:35:30 martynas Exp $ */ 2 /* $NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $ */ 3 4 /* 5 * Copyright (C) 1997 and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1985, 1989, 1993, 1994 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 */ 61 62 #ifndef SMALL 63 64 /* 65 * FTP User Program -- Command Routines. 66 */ 67 #include <sys/types.h> 68 #include <sys/socket.h> 69 #include <sys/stat.h> 70 #include <sys/wait.h> 71 #include <arpa/ftp.h> 72 73 #include <ctype.h> 74 #include <err.h> 75 #include <fnmatch.h> 76 #include <glob.h> 77 #include <netdb.h> 78 #include <stdio.h> 79 #include <stdlib.h> 80 #include <string.h> 81 #include <unistd.h> 82 83 #include "ftp_var.h" 84 #include "pathnames.h" 85 #include "cmds.h" 86 87 /* 88 * Set ascii transfer type. 89 */ 90 /*ARGSUSED*/ 91 void 92 setascii(int argc, char *argv[]) 93 { 94 95 stype[1] = "ascii"; 96 settype(2, stype); 97 } 98 99 /* 100 * Set tenex transfer type. 101 */ 102 /*ARGSUSED*/ 103 void 104 settenex(int argc, char *argv[]) 105 { 106 107 stype[1] = "tenex"; 108 settype(2, stype); 109 } 110 111 /* 112 * Set file transfer mode. 113 */ 114 /*ARGSUSED*/ 115 void 116 setftmode(int argc, char *argv[]) 117 { 118 119 fprintf(ttyout, "We only support %s mode, sorry.\n", modename); 120 code = -1; 121 } 122 123 /* 124 * Set file transfer format. 125 */ 126 /*ARGSUSED*/ 127 void 128 setform(int argc, char *argv[]) 129 { 130 131 fprintf(ttyout, "We only support %s format, sorry.\n", formname); 132 code = -1; 133 } 134 135 /* 136 * Set file transfer structure. 137 */ 138 /*ARGSUSED*/ 139 void 140 setstruct(int argc, char *argv[]) 141 { 142 143 fprintf(ttyout, "We only support %s structure, sorry.\n", structname); 144 code = -1; 145 } 146 147 void 148 reput(int argc, char *argv[]) 149 { 150 151 (void)putit(argc, argv, 1); 152 } 153 154 void 155 put(int argc, char *argv[]) 156 { 157 158 (void)putit(argc, argv, 0); 159 } 160 161 /* 162 * Send a single file. 163 */ 164 void 165 putit(int argc, char *argv[], int restartit) 166 { 167 char *cmd; 168 int loc = 0; 169 char *oldargv1, *oldargv2; 170 171 if (argc == 2) { 172 argc++; 173 argv[2] = argv[1]; 174 loc++; 175 } 176 if (argc < 2 && !another(&argc, &argv, "local-file")) 177 goto usage; 178 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 179 usage: 180 fprintf(ttyout, "usage: %s local-file [remote-file]\n", 181 argv[0]); 182 code = -1; 183 return; 184 } 185 oldargv1 = argv[1]; 186 oldargv2 = argv[2]; 187 if (!globulize(&argv[1])) { 188 code = -1; 189 return; 190 } 191 /* 192 * If "globulize" modifies argv[1], and argv[2] is a copy of 193 * the old argv[1], make it a copy of the new argv[1]. 194 */ 195 if (argv[1] != oldargv1 && argv[2] == oldargv1) { 196 argv[2] = argv[1]; 197 } 198 if (restartit == 1) { 199 if (curtype != type) 200 changetype(type, 0); 201 restart_point = remotesize(argv[2], 1); 202 if (restart_point < 0) { 203 restart_point = 0; 204 code = -1; 205 return; 206 } 207 } 208 if (strcmp(argv[0], "append") == 0) { 209 restartit = 1; 210 } 211 cmd = restartit ? "APPE" : ((sunique) ? "STOU" : "STOR"); 212 if (loc && ntflag) { 213 argv[2] = dotrans(argv[2]); 214 } 215 if (loc && mapflag) { 216 argv[2] = domap(argv[2]); 217 } 218 sendrequest(cmd, argv[1], argv[2], 219 argv[1] != oldargv1 || argv[2] != oldargv2); 220 restart_point = 0; 221 if (oldargv1 != argv[1]) /* free up after globulize() */ 222 free(argv[1]); 223 } 224 225 /* 226 * Send multiple files. 227 */ 228 void 229 mput(int argc, char *argv[]) 230 { 231 extern int optind, optreset; 232 int ch, i, restartit = 0; 233 sig_t oldintr; 234 char *cmd, *tp; 235 236 optind = optreset = 1; 237 238 while ((ch = getopt(argc, argv, "c")) != -1) { 239 switch(ch) { 240 case 'c': 241 restartit = 1; 242 break; 243 default: 244 goto usage; 245 } 246 } 247 248 if (argc - optind < 1 && !another(&argc, &argv, "local-files")) { 249 usage: 250 fprintf(ttyout, "usage: %s [-c] local-files\n", argv[0]); 251 code = -1; 252 return; 253 } 254 255 argv[optind - 1] = argv[0]; 256 argc -= optind - 1; 257 argv += optind - 1; 258 259 mname = argv[0]; 260 mflag = 1; 261 262 oldintr = signal(SIGINT, mabort); 263 (void)setjmp(jabort); 264 if (proxy) { 265 char *cp, *tp2, tmpbuf[MAXPATHLEN]; 266 267 while ((cp = remglob(argv, 0, NULL)) != NULL) { 268 if (*cp == '\0') { 269 mflag = 0; 270 continue; 271 } 272 if (mflag && confirm(argv[0], cp)) { 273 tp = cp; 274 if (mcase) { 275 while (*tp && !islower(*tp)) { 276 tp++; 277 } 278 if (!*tp) { 279 tp = cp; 280 tp2 = tmpbuf; 281 while ((*tp2 = *tp) != '\0') { 282 if (isupper(*tp2)) { 283 *tp2 = 284 tolower(*tp2); 285 } 286 tp++; 287 tp2++; 288 } 289 } 290 tp = tmpbuf; 291 } 292 if (ntflag) { 293 tp = dotrans(tp); 294 } 295 if (mapflag) { 296 tp = domap(tp); 297 } 298 if (restartit == 1) { 299 off_t ret; 300 301 if (curtype != type) 302 changetype(type, 0); 303 ret = remotesize(tp, 0); 304 restart_point = (ret < 0) ? 0 : ret; 305 } 306 cmd = restartit ? "APPE" : ((sunique) ? 307 "STOU" : "STOR"); 308 sendrequest(cmd, cp, tp, 309 cp != tp || !interactive); 310 restart_point = 0; 311 if (!mflag && fromatty) { 312 if (confirm(argv[0], NULL)) 313 mflag = 1; 314 } 315 } 316 } 317 (void)signal(SIGINT, oldintr); 318 mflag = 0; 319 return; 320 } 321 for (i = 1; i < argc; i++) { 322 char **cpp; 323 glob_t gl; 324 int flags; 325 326 if (!doglob) { 327 if (mflag && confirm(argv[0], argv[i])) { 328 tp = (ntflag) ? dotrans(argv[i]) : argv[i]; 329 tp = (mapflag) ? domap(tp) : tp; 330 if (restartit == 1) { 331 off_t ret; 332 333 if (curtype != type) 334 changetype(type, 0); 335 ret = remotesize(tp, 0); 336 restart_point = (ret < 0) ? 0 : ret; 337 } 338 cmd = restartit ? "APPE" : ((sunique) ? 339 "STOU" : "STOR"); 340 sendrequest(cmd, argv[i], tp, 341 tp != argv[i] || !interactive); 342 restart_point = 0; 343 if (!mflag && fromatty) { 344 if (confirm(argv[0], NULL)) 345 mflag = 1; 346 } 347 } 348 continue; 349 } 350 351 memset(&gl, 0, sizeof(gl)); 352 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 353 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { 354 warnx("%s: not found", argv[i]); 355 globfree(&gl); 356 continue; 357 } 358 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) { 359 if (mflag && confirm(argv[0], *cpp)) { 360 tp = (ntflag) ? dotrans(*cpp) : *cpp; 361 tp = (mapflag) ? domap(tp) : tp; 362 if (restartit == 1) { 363 off_t ret; 364 365 if (curtype != type) 366 changetype(type, 0); 367 ret = remotesize(tp, 0); 368 restart_point = (ret < 0) ? 0 : ret; 369 } 370 cmd = restartit ? "APPE" : ((sunique) ? 371 "STOU" : "STOR"); 372 sendrequest(cmd, *cpp, tp, 373 *cpp != tp || !interactive); 374 restart_point = 0; 375 if (!mflag && fromatty) { 376 if (confirm(argv[0], NULL)) 377 mflag = 1; 378 } 379 } 380 } 381 globfree(&gl); 382 } 383 (void)signal(SIGINT, oldintr); 384 mflag = 0; 385 } 386 387 void 388 reget(int argc, char *argv[]) 389 { 390 391 (void)getit(argc, argv, 1, "a+w"); 392 } 393 394 char * 395 onoff(int bool) 396 { 397 398 return (bool ? "on" : "off"); 399 } 400 401 /* 402 * Show status. 403 */ 404 /*ARGSUSED*/ 405 void 406 status(int argc, char *argv[]) 407 { 408 int i; 409 410 if (connected) 411 fprintf(ttyout, "Connected %sto %s.\n", 412 connected == -1 ? "and logged in" : "", hostname); 413 else 414 fputs("Not connected.\n", ttyout); 415 if (!proxy) { 416 pswitch(1); 417 if (connected) { 418 fprintf(ttyout, "Connected for proxy commands to %s.\n", 419 hostname); 420 } 421 else { 422 fputs("No proxy connection.\n", ttyout); 423 } 424 pswitch(0); 425 } 426 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode), 427 *gateserver ? gateserver : "(none)", gateport); 428 fprintf(ttyout, "Passive mode: %s.\n", onoff(passivemode)); 429 fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n", 430 modename, typename, formname, structname); 431 fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n", 432 onoff(verbose), onoff(bell), onoff(interactive), 433 onoff(doglob)); 434 fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", onoff(sunique), 435 onoff(runique)); 436 fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve)); 437 fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag)); 438 if (ntflag) { 439 fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout); 440 } 441 else { 442 fputs("Ntrans: off.\n", ttyout); 443 } 444 if (mapflag) { 445 fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout); 446 } 447 else { 448 fputs("Nmap: off.\n", ttyout); 449 } 450 fprintf(ttyout, "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n", 451 onoff(hash), mark, onoff(progress)); 452 fprintf(ttyout, "Use of PORT/LPRT cmds: %s.\n", onoff(sendport)); 453 fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4), 454 epsv4bad ? " (disabled for this connection)" : ""); 455 fprintf(ttyout, "Command line editing: %s.\n", onoff(editing)); 456 if (macnum > 0) { 457 fputs("Macros:\n", ttyout); 458 for (i=0; i<macnum; i++) { 459 fprintf(ttyout, "\t%s\n", macros[i].mac_name); 460 } 461 } 462 code = 0; 463 } 464 465 /* 466 * Toggle a variable 467 */ 468 int 469 togglevar(int argc, char *argv[], int *var, const char *mesg) 470 { 471 if (argc < 2) { 472 *var = !*var; 473 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) { 474 *var = 1; 475 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) { 476 *var = 0; 477 } else { 478 fprintf(ttyout, "usage: %s [on | off]\n", argv[0]); 479 return (-1); 480 } 481 if (mesg) 482 fprintf(ttyout, "%s %s.\n", mesg, onoff(*var)); 483 return (*var); 484 } 485 486 /* 487 * Set beep on cmd completed mode. 488 */ 489 /*ARGSUSED*/ 490 void 491 setbell(int argc, char *argv[]) 492 { 493 494 code = togglevar(argc, argv, &bell, "Bell mode"); 495 } 496 497 /* 498 * Set command line editing 499 */ 500 /*ARGSUSED*/ 501 void 502 setedit(int argc, char *argv[]) 503 { 504 505 code = togglevar(argc, argv, &editing, "Editing mode"); 506 controlediting(); 507 } 508 509 /* 510 * Toggle use of IPv4 EPSV/EPRT 511 */ 512 /*ARGSUSED*/ 513 void 514 setepsv4(int argc, char *argv[]) 515 { 516 517 code = togglevar(argc, argv, &epsv4, "EPSV/EPRT on IPv4"); 518 epsv4bad = 0; 519 } 520 521 /* 522 * Turn on packet tracing. 523 */ 524 /*ARGSUSED*/ 525 void 526 settrace(int argc, char *argv[]) 527 { 528 529 code = togglevar(argc, argv, &trace, "Packet tracing"); 530 } 531 532 /* 533 * Toggle hash mark printing during transfers, or set hash mark bytecount. 534 */ 535 /*ARGSUSED*/ 536 void 537 sethash(int argc, char *argv[]) 538 { 539 if (argc == 1) 540 hash = !hash; 541 else if (argc != 2) { 542 fprintf(ttyout, "usage: %s [on | off | size]\n", argv[0]); 543 code = -1; 544 return; 545 } else if (strcasecmp(argv[1], "on") == 0) 546 hash = 1; 547 else if (strcasecmp(argv[1], "off") == 0) 548 hash = 0; 549 else { 550 int nmark; 551 const char *errstr; 552 553 nmark = strtonum(argv[1], 1, INT_MAX, &errstr); 554 if (errstr) { 555 fprintf(ttyout, "bytecount value is %s: %s\n", 556 errstr, argv[1]); 557 code = -1; 558 return; 559 } 560 mark = nmark; 561 hash = 1; 562 } 563 fprintf(ttyout, "Hash mark printing %s", onoff(hash)); 564 if (hash) 565 fprintf(ttyout, " (%d bytes/hash mark)", mark); 566 fputs(".\n", ttyout); 567 code = hash; 568 } 569 570 /* 571 * Turn on printing of server echo's. 572 */ 573 /*ARGSUSED*/ 574 void 575 setverbose(int argc, char *argv[]) 576 { 577 578 code = togglevar(argc, argv, &verbose, "Verbose mode"); 579 } 580 581 /* 582 * Toggle PORT/LPRT cmd use before each data connection. 583 */ 584 /*ARGSUSED*/ 585 void 586 setport(int argc, char *argv[]) 587 { 588 589 code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds"); 590 } 591 592 /* 593 * Toggle transfer progress bar. 594 */ 595 /*ARGSUSED*/ 596 void 597 setprogress(int argc, char *argv[]) 598 { 599 600 code = togglevar(argc, argv, &progress, "Progress bar"); 601 } 602 603 /* 604 * Turn on interactive prompting during mget, mput, and mdelete. 605 */ 606 /*ARGSUSED*/ 607 void 608 setprompt(int argc, char *argv[]) 609 { 610 611 code = togglevar(argc, argv, &interactive, "Interactive mode"); 612 } 613 614 /* 615 * Toggle gate-ftp mode, or set gate-ftp server 616 */ 617 /*ARGSUSED*/ 618 void 619 setgate(int argc, char *argv[]) 620 { 621 static char gsbuf[MAXHOSTNAMELEN]; 622 623 if (argc > 3) { 624 fprintf(ttyout, "usage: %s [on | off | host [port]]\n", 625 argv[0]); 626 code = -1; 627 return; 628 } else if (argc < 2) { 629 gatemode = !gatemode; 630 } else { 631 if (argc == 2 && strcasecmp(argv[1], "on") == 0) 632 gatemode = 1; 633 else if (argc == 2 && strcasecmp(argv[1], "off") == 0) 634 gatemode = 0; 635 else { 636 if (argc == 3) { 637 gateport = strdup(argv[2]); 638 if (gateport == NULL) 639 err(1, NULL); 640 } 641 strlcpy(gsbuf, argv[1], sizeof(gsbuf)); 642 gateserver = gsbuf; 643 gatemode = 1; 644 } 645 } 646 if (gatemode && (gateserver == NULL || *gateserver == '\0')) { 647 fprintf(ttyout, 648 "Disabling gate-ftp mode - no gate-ftp server defined.\n"); 649 gatemode = 0; 650 } else { 651 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", 652 onoff(gatemode), 653 *gateserver ? gateserver : "(none)", gateport); 654 } 655 code = gatemode; 656 } 657 658 /* 659 * Toggle metacharacter interpretation on local file names. 660 */ 661 /*ARGSUSED*/ 662 void 663 setglob(int argc, char *argv[]) 664 { 665 666 code = togglevar(argc, argv, &doglob, "Globbing"); 667 } 668 669 /* 670 * Toggle preserving modification times on retrieved files. 671 */ 672 /*ARGSUSED*/ 673 void 674 setpreserve(int argc, char *argv[]) 675 { 676 677 code = togglevar(argc, argv, &preserve, "Preserve modification times"); 678 } 679 680 /* 681 * Set debugging mode on/off and/or set level of debugging. 682 */ 683 /*ARGSUSED*/ 684 void 685 setdebug(int argc, char *argv[]) 686 { 687 if (argc > 2) { 688 fprintf(ttyout, "usage: %s [on | off | debuglevel]\n", argv[0]); 689 code = -1; 690 return; 691 } else if (argc == 2) { 692 if (strcasecmp(argv[1], "on") == 0) 693 debug = 1; 694 else if (strcasecmp(argv[1], "off") == 0) 695 debug = 0; 696 else { 697 const char *errstr; 698 int val; 699 700 val = strtonum(argv[1], 0, INT_MAX, &errstr); 701 if (errstr) { 702 fprintf(ttyout, "debugging value is %s: %s\n", 703 errstr, argv[1]); 704 code = -1; 705 return; 706 } 707 debug = val; 708 } 709 } else 710 debug = !debug; 711 if (debug) 712 options |= SO_DEBUG; 713 else 714 options &= ~SO_DEBUG; 715 fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug); 716 code = debug > 0; 717 } 718 719 /* 720 * Set current working directory on local machine. 721 */ 722 void 723 lcd(int argc, char *argv[]) 724 { 725 char buf[MAXPATHLEN]; 726 char *oldargv1; 727 728 if (argc < 2) 729 argc++, argv[1] = home; 730 if (argc != 2) { 731 fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]); 732 code = -1; 733 return; 734 } 735 oldargv1 = argv[1]; 736 if (!globulize(&argv[1])) { 737 code = -1; 738 return; 739 } 740 if (chdir(argv[1]) < 0) { 741 warn("local: %s", argv[1]); 742 code = -1; 743 } else { 744 if (getcwd(buf, sizeof(buf)) != NULL) 745 fprintf(ttyout, "Local directory now %s\n", buf); 746 else 747 warn("getcwd: %s", argv[1]); 748 code = 0; 749 } 750 if (oldargv1 != argv[1]) /* free up after globulize() */ 751 free(argv[1]); 752 } 753 754 /* 755 * Delete a single file. 756 */ 757 void 758 deletecmd(int argc, char *argv[]) 759 { 760 761 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) { 762 fprintf(ttyout, "usage: %s remote-file\n", argv[0]); 763 code = -1; 764 return; 765 } 766 (void)command("DELE %s", argv[1]); 767 } 768 769 /* 770 * Delete multiple files. 771 */ 772 void 773 mdelete(int argc, char *argv[]) 774 { 775 sig_t oldintr; 776 char *cp; 777 778 if (argc < 2 && !another(&argc, &argv, "remote-files")) { 779 fprintf(ttyout, "usage: %s remote-files\n", argv[0]); 780 code = -1; 781 return; 782 } 783 mname = argv[0]; 784 mflag = 1; 785 oldintr = signal(SIGINT, mabort); 786 (void)setjmp(jabort); 787 while ((cp = remglob(argv, 0, NULL)) != NULL) { 788 if (*cp == '\0') { 789 mflag = 0; 790 continue; 791 } 792 if (mflag && confirm(argv[0], cp)) { 793 (void)command("DELE %s", cp); 794 if (!mflag && fromatty) { 795 if (confirm(argv[0], NULL)) 796 mflag = 1; 797 } 798 } 799 } 800 (void)signal(SIGINT, oldintr); 801 mflag = 0; 802 } 803 804 /* 805 * Rename a remote file. 806 */ 807 void 808 renamefile(int argc, char *argv[]) 809 { 810 811 if (argc < 2 && !another(&argc, &argv, "from-name")) 812 goto usage; 813 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) { 814 usage: 815 fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]); 816 code = -1; 817 return; 818 } 819 if (command("RNFR %s", argv[1]) == CONTINUE) 820 (void)command("RNTO %s", argv[2]); 821 } 822 823 /* 824 * Get a directory listing of remote files. 825 */ 826 void 827 ls(int argc, char *argv[]) 828 { 829 const char *cmd; 830 char *oldargv2, *globargv2; 831 832 if (argc < 2) 833 argc++, argv[1] = NULL; 834 if (argc < 3) 835 argc++, argv[2] = "-"; 836 if (argc > 3) { 837 fprintf(ttyout, "usage: %s [remote-directory [local-file]]\n", 838 argv[0]); 839 code = -1; 840 return; 841 } 842 cmd = strcmp(argv[0], "nlist") == 0 ? "NLST" : "LIST"; 843 oldargv2 = argv[2]; 844 if (strcmp(argv[2], "-") && !globulize(&argv[2])) { 845 code = -1; 846 return; 847 } 848 globargv2 = argv[2]; 849 if (strcmp(argv[2], "-") && *argv[2] != '|' && (!globulize(&argv[2]) || 850 !confirm("output to local-file:", argv[2]))) { 851 code = -1; 852 goto freels; 853 } 854 recvrequest(cmd, argv[2], argv[1], "w", 0, 0); 855 856 /* flush results in case commands are coming from a pipe */ 857 fflush(ttyout); 858 freels: 859 if (argv[2] != globargv2) /* free up after globulize() */ 860 free(argv[2]); 861 if (globargv2 != oldargv2) 862 free(globargv2); 863 } 864 865 /* 866 * Get a directory listing of multiple remote files. 867 */ 868 void 869 mls(int argc, char *argv[]) 870 { 871 sig_t oldintr; 872 int i; 873 char lmode[1], *dest, *odest; 874 875 if (argc < 2 && !another(&argc, &argv, "remote-files")) 876 goto usage; 877 if (argc < 3 && !another(&argc, &argv, "local-file")) { 878 usage: 879 fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]); 880 code = -1; 881 return; 882 } 883 odest = dest = argv[argc - 1]; 884 argv[argc - 1] = NULL; 885 if (strcmp(dest, "-") && *dest != '|') 886 if (!globulize(&dest) || 887 !confirm("output to local-file:", dest)) { 888 code = -1; 889 return; 890 } 891 mname = argv[0]; 892 mflag = 1; 893 oldintr = signal(SIGINT, mabort); 894 (void)setjmp(jabort); 895 for (i = 1; mflag && i < argc-1; ++i) { 896 *lmode = (i == 1) ? 'w' : 'a'; 897 recvrequest("LIST", dest, argv[i], lmode, 0, 0); 898 if (!mflag && fromatty) { 899 if (confirm(argv[0], NULL)) 900 mflag ++; 901 } 902 } 903 (void)signal(SIGINT, oldintr); 904 mflag = 0; 905 if (dest != odest) /* free up after globulize() */ 906 free(dest); 907 } 908 909 /* 910 * Do a shell escape 911 */ 912 /*ARGSUSED*/ 913 void 914 shell(int argc, char *argv[]) 915 { 916 pid_t pid; 917 sig_t old1, old2; 918 char shellnam[MAXPATHLEN], *shellp, *namep; 919 int wait_status; 920 921 old1 = signal (SIGINT, SIG_IGN); 922 old2 = signal (SIGQUIT, SIG_IGN); 923 if ((pid = fork()) == 0) { 924 for (pid = 3; pid < 20; pid++) 925 (void)close(pid); 926 (void)signal(SIGINT, SIG_DFL); 927 (void)signal(SIGQUIT, SIG_DFL); 928 shellp = getenv("SHELL"); 929 if (shellp == NULL || *shellp == '\0') 930 shellp = _PATH_BSHELL; 931 namep = strrchr(shellp, '/'); 932 if (namep == NULL) 933 namep = shellp; 934 shellnam[0] = '-'; 935 (void)strlcpy(shellnam + 1, ++namep, sizeof(shellnam) - 1); 936 if (strcmp(namep, "sh") != 0) 937 shellnam[0] = '+'; 938 if (debug) { 939 fputs(shellp, ttyout); 940 fputc('\n', ttyout); 941 (void)fflush(ttyout); 942 } 943 if (argc > 1) { 944 execl(shellp, shellnam, "-c", altarg, (char *)0); 945 } 946 else { 947 execl(shellp, shellnam, (char *)0); 948 } 949 warn("%s", shellp); 950 code = -1; 951 exit(1); 952 } 953 if (pid > 0) 954 while (wait(&wait_status) != pid) 955 ; 956 (void)signal(SIGINT, old1); 957 (void)signal(SIGQUIT, old2); 958 if (pid == -1) { 959 warn("Try again later"); 960 code = -1; 961 } 962 else { 963 code = 0; 964 } 965 } 966 967 /* 968 * Send new user information (re-login) 969 */ 970 void 971 user(int argc, char *argv[]) 972 { 973 char acctname[80]; 974 int n, aflag = 0; 975 976 if (argc < 2) 977 (void)another(&argc, &argv, "username"); 978 if (argc < 2 || argc > 4) { 979 fprintf(ttyout, "usage: %s username [password [account]]\n", 980 argv[0]); 981 code = -1; 982 return; 983 } 984 n = command("USER %s", argv[1]); 985 if (n == CONTINUE) { 986 if (argc < 3 ) 987 argv[2] = getpass("Password:"), argc++; 988 n = command("PASS %s", argv[2]); 989 } 990 if (n == CONTINUE) { 991 if (argc < 4) { 992 (void)fputs("Account: ", ttyout); 993 (void)fflush(ttyout); 994 if (fgets(acctname, sizeof(acctname), stdin) == NULL) { 995 clearerr(stdin); 996 goto fail; 997 } 998 999 acctname[strcspn(acctname, "\n")] = '\0'; 1000 1001 argv[3] = acctname; 1002 argc++; 1003 } 1004 n = command("ACCT %s", argv[3]); 1005 aflag++; 1006 } 1007 if (n != COMPLETE) { 1008 fail: 1009 fputs("Login failed.\n", ttyout); 1010 return; 1011 } 1012 if (!aflag && argc == 4) { 1013 (void)command("ACCT %s", argv[3]); 1014 } 1015 connected = -1; 1016 } 1017 1018 /* 1019 * Print working directory on remote machine. 1020 */ 1021 /*ARGSUSED*/ 1022 void 1023 pwd(int argc, char *argv[]) 1024 { 1025 int oldverbose = verbose; 1026 1027 /* 1028 * If we aren't verbose, this doesn't do anything! 1029 */ 1030 verbose = 1; 1031 if (command("PWD") == ERROR && code == 500) { 1032 fputs("PWD command not recognized, trying XPWD.\n", ttyout); 1033 (void)command("XPWD"); 1034 } 1035 verbose = oldverbose; 1036 } 1037 1038 /* 1039 * Print working directory on local machine. 1040 */ 1041 /* ARGSUSED */ 1042 void 1043 lpwd(int argc, char *argv[]) 1044 { 1045 char buf[MAXPATHLEN]; 1046 1047 if (getcwd(buf, sizeof(buf)) != NULL) 1048 fprintf(ttyout, "Local directory %s\n", buf); 1049 else 1050 warn("getcwd"); 1051 code = 0; 1052 } 1053 1054 /* 1055 * Make a directory. 1056 */ 1057 void 1058 makedir(int argc, char *argv[]) 1059 { 1060 1061 if ((argc < 2 && !another(&argc, &argv, "directory-name")) || 1062 argc > 2) { 1063 fprintf(ttyout, "usage: %s directory-name\n", argv[0]); 1064 code = -1; 1065 return; 1066 } 1067 if (command("MKD %s", argv[1]) == ERROR && code == 500) { 1068 if (verbose) 1069 fputs("MKD command not recognized, trying XMKD.\n", ttyout); 1070 (void)command("XMKD %s", argv[1]); 1071 } 1072 } 1073 1074 /* 1075 * Remove a directory. 1076 */ 1077 void 1078 removedir(int argc, char *argv[]) 1079 { 1080 1081 if ((argc < 2 && !another(&argc, &argv, "directory-name")) || 1082 argc > 2) { 1083 fprintf(ttyout, "usage: %s directory-name\n", argv[0]); 1084 code = -1; 1085 return; 1086 } 1087 if (command("RMD %s", argv[1]) == ERROR && code == 500) { 1088 if (verbose) 1089 fputs("RMD command not recognized, trying XRMD.\n", ttyout); 1090 (void)command("XRMD %s", argv[1]); 1091 } 1092 } 1093 1094 /* 1095 * Send a line, verbatim, to the remote machine. 1096 */ 1097 void 1098 quote(int argc, char *argv[]) 1099 { 1100 1101 if (argc < 2 && !another(&argc, &argv, "command line to send")) { 1102 fprintf(ttyout, "usage: %s arg ...\n", argv[0]); 1103 code = -1; 1104 return; 1105 } 1106 quote1("", argc, argv); 1107 } 1108 1109 /* 1110 * Send a SITE command to the remote machine. The line 1111 * is sent verbatim to the remote machine, except that the 1112 * word "SITE" is added at the front. 1113 */ 1114 void 1115 site(int argc, char *argv[]) 1116 { 1117 1118 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { 1119 fprintf(ttyout, "usage: %s arg ...\n", argv[0]); 1120 code = -1; 1121 return; 1122 } 1123 quote1("SITE", argc, argv); 1124 } 1125 1126 /* 1127 * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1128 * Send the result as a one-line command and get response. 1129 */ 1130 void 1131 quote1(const char *initial, int argc, char *argv[]) 1132 { 1133 int i, len; 1134 char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1135 1136 (void)strlcpy(buf, initial, sizeof(buf)); 1137 if (argc > 1) { 1138 for (i = 1, len = strlen(buf); i < argc && len < sizeof(buf)-1; i++) { 1139 /* Space for next arg */ 1140 if (len > 1) 1141 buf[len++] = ' '; 1142 1143 /* Sanity check */ 1144 if (len >= sizeof(buf) - 1) 1145 break; 1146 1147 /* Copy next argument, NUL terminate always */ 1148 strlcpy(&buf[len], argv[i], sizeof(buf) - len); 1149 1150 /* Update string length */ 1151 len = strlen(buf); 1152 } 1153 } 1154 1155 /* Make double (triple?) sure the sucker is NUL terminated */ 1156 buf[sizeof(buf) - 1] = '\0'; 1157 1158 if (command("%s", buf) == PRELIM) { 1159 while (getreply(0) == PRELIM) 1160 continue; 1161 } 1162 } 1163 1164 void 1165 do_chmod(int argc, char *argv[]) 1166 { 1167 1168 if (argc < 2 && !another(&argc, &argv, "mode")) 1169 goto usage; 1170 if ((argc < 3 && !another(&argc, &argv, "file")) || argc > 3) { 1171 usage: 1172 fprintf(ttyout, "usage: %s mode file\n", argv[0]); 1173 code = -1; 1174 return; 1175 } 1176 (void)command("SITE CHMOD %s %s", argv[1], argv[2]); 1177 } 1178 1179 void 1180 do_umask(int argc, char *argv[]) 1181 { 1182 int oldverbose = verbose; 1183 1184 verbose = 1; 1185 (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); 1186 verbose = oldverbose; 1187 } 1188 1189 void 1190 idle(int argc, char *argv[]) 1191 { 1192 int oldverbose = verbose; 1193 1194 verbose = 1; 1195 (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); 1196 verbose = oldverbose; 1197 } 1198 1199 /* 1200 * Ask the other side for help. 1201 */ 1202 void 1203 rmthelp(int argc, char *argv[]) 1204 { 1205 int oldverbose = verbose; 1206 1207 verbose = 1; 1208 (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 1209 verbose = oldverbose; 1210 } 1211 1212 /* 1213 * Terminate session and exit. 1214 */ 1215 /*ARGSUSED*/ 1216 void 1217 quit(int argc, char *argv[]) 1218 { 1219 1220 if (connected) 1221 disconnect(0, 0); 1222 pswitch(1); 1223 if (connected) { 1224 disconnect(0, 0); 1225 } 1226 exit(0); 1227 } 1228 1229 void 1230 account(int argc, char *argv[]) 1231 { 1232 char *ap; 1233 1234 if (argc > 2) { 1235 fprintf(ttyout, "usage: %s [password]\n", argv[0]); 1236 code = -1; 1237 return; 1238 } 1239 else if (argc == 2) 1240 ap = argv[1]; 1241 else 1242 ap = getpass("Account:"); 1243 (void)command("ACCT %s", ap); 1244 } 1245 1246 jmp_buf abortprox; 1247 1248 /* ARGSUSED */ 1249 void 1250 proxabort(int signo) 1251 { 1252 1253 alarmtimer(0); 1254 if (!proxy) { 1255 pswitch(1); 1256 } 1257 if (connected) { 1258 proxflag = 1; 1259 } 1260 else { 1261 proxflag = 0; 1262 } 1263 pswitch(0); 1264 longjmp(abortprox, 1); 1265 } 1266 1267 void 1268 doproxy(int argc, char *argv[]) 1269 { 1270 struct cmd *c; 1271 int cmdpos; 1272 sig_t oldintr; 1273 1274 if (argc < 2 && !another(&argc, &argv, "command")) { 1275 fprintf(ttyout, "usage: %s command\n", argv[0]); 1276 code = -1; 1277 return; 1278 } 1279 c = getcmd(argv[1]); 1280 if (c == (struct cmd *) -1) { 1281 fputs("?Ambiguous command.\n", ttyout); 1282 (void)fflush(ttyout); 1283 code = -1; 1284 return; 1285 } 1286 if (c == 0) { 1287 fputs("?Invalid command.\n", ttyout); 1288 (void)fflush(ttyout); 1289 code = -1; 1290 return; 1291 } 1292 if (!c->c_proxy) { 1293 fputs("?Invalid proxy command.\n", ttyout); 1294 (void)fflush(ttyout); 1295 code = -1; 1296 return; 1297 } 1298 if (setjmp(abortprox)) { 1299 code = -1; 1300 return; 1301 } 1302 oldintr = signal(SIGINT, proxabort); 1303 pswitch(1); 1304 if (c->c_conn && !connected) { 1305 fputs("Not connected.\n", ttyout); 1306 (void)fflush(ttyout); 1307 pswitch(0); 1308 (void)signal(SIGINT, oldintr); 1309 code = -1; 1310 return; 1311 } 1312 cmdpos = strcspn(line, " \t"); 1313 if (cmdpos > 0) /* remove leading "proxy " from input buffer */ 1314 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1); 1315 (*c->c_handler)(argc-1, argv+1); 1316 if (connected) { 1317 proxflag = 1; 1318 } 1319 else { 1320 proxflag = 0; 1321 } 1322 pswitch(0); 1323 (void)signal(SIGINT, oldintr); 1324 } 1325 1326 void 1327 setcase(int argc, char *argv[]) 1328 { 1329 1330 code = togglevar(argc, argv, &mcase, "Case mapping"); 1331 } 1332 1333 void 1334 setcr(int argc, char *argv[]) 1335 { 1336 1337 code = togglevar(argc, argv, &crflag, "Carriage Return stripping"); 1338 } 1339 1340 void 1341 setntrans(int argc, char *argv[]) 1342 { 1343 if (argc == 1) { 1344 ntflag = 0; 1345 fputs("Ntrans off.\n", ttyout); 1346 code = ntflag; 1347 return; 1348 } 1349 ntflag++; 1350 code = ntflag; 1351 (void)strlcpy(ntin, argv[1], sizeof(ntin)); 1352 if (argc == 2) { 1353 ntout[0] = '\0'; 1354 return; 1355 } 1356 (void)strlcpy(ntout, argv[2], sizeof(ntout)); 1357 } 1358 1359 void 1360 setnmap(int argc, char *argv[]) 1361 { 1362 char *cp; 1363 1364 if (argc == 1) { 1365 mapflag = 0; 1366 fputs("Nmap off.\n", ttyout); 1367 code = mapflag; 1368 return; 1369 } 1370 if ((argc < 3 && !another(&argc, &argv, "outpattern")) || argc > 3) { 1371 fprintf(ttyout, "usage: %s [inpattern outpattern]\n", argv[0]); 1372 code = -1; 1373 return; 1374 } 1375 mapflag = 1; 1376 code = 1; 1377 cp = strchr(altarg, ' '); 1378 if (proxy) { 1379 while(*++cp == ' ') 1380 continue; 1381 altarg = cp; 1382 cp = strchr(altarg, ' '); 1383 } 1384 *cp = '\0'; 1385 (void)strncpy(mapin, altarg, MAXPATHLEN - 1); 1386 while (*++cp == ' ') 1387 continue; 1388 (void)strncpy(mapout, cp, MAXPATHLEN - 1); 1389 } 1390 1391 void 1392 setpassive(int argc, char *argv[]) 1393 { 1394 1395 code = togglevar(argc, argv, &passivemode, 1396 verbose ? "Passive mode" : NULL); 1397 } 1398 1399 void 1400 setsunique(int argc, char *argv[]) 1401 { 1402 1403 code = togglevar(argc, argv, &sunique, "Store unique"); 1404 } 1405 1406 void 1407 setrunique(int argc, char *argv[]) 1408 { 1409 1410 code = togglevar(argc, argv, &runique, "Receive unique"); 1411 } 1412 1413 /* change directory to parent directory */ 1414 /* ARGSUSED */ 1415 void 1416 cdup(int argc, char *argv[]) 1417 { 1418 int r; 1419 1420 r = command("CDUP"); 1421 if (r == ERROR && code == 500) { 1422 if (verbose) 1423 fputs("CDUP command not recognized, trying XCUP.\n", ttyout); 1424 r = command("XCUP"); 1425 } 1426 if (r == COMPLETE) 1427 dirchange = 1; 1428 } 1429 1430 /* 1431 * Restart transfer at specific point 1432 */ 1433 void 1434 restart(int argc, char *argv[]) 1435 { 1436 quad_t nrestart_point; 1437 char *ep; 1438 1439 if (argc != 2) 1440 fputs("restart: offset not specified.\n", ttyout); 1441 else { 1442 nrestart_point = strtoq(argv[1], &ep, 10); 1443 if (nrestart_point == QUAD_MAX || *ep != '\0') 1444 fputs("restart: invalid offset.\n", ttyout); 1445 else { 1446 fprintf(ttyout, "Restarting at %lld. Execute get, put " 1447 "or append to initiate transfer\n", 1448 (long long)nrestart_point); 1449 restart_point = nrestart_point; 1450 } 1451 } 1452 } 1453 1454 /* 1455 * Show remote system type 1456 */ 1457 /* ARGSUSED */ 1458 void 1459 syst(int argc, char *argv[]) 1460 { 1461 1462 (void)command("SYST"); 1463 } 1464 1465 void 1466 macdef(int argc, char *argv[]) 1467 { 1468 char *tmp; 1469 int c; 1470 1471 if (macnum == 16) { 1472 fputs("Limit of 16 macros have already been defined.\n", ttyout); 1473 code = -1; 1474 return; 1475 } 1476 if ((argc < 2 && !another(&argc, &argv, "macro-name")) || argc > 2) { 1477 fprintf(ttyout, "usage: %s macro-name\n", argv[0]); 1478 code = -1; 1479 return; 1480 } 1481 if (interactive) 1482 fputs( 1483 "Enter macro line by line, terminating it with a null line.\n", ttyout); 1484 (void)strlcpy(macros[macnum].mac_name, argv[1], 1485 sizeof(macros[macnum].mac_name)); 1486 if (macnum == 0) 1487 macros[macnum].mac_start = macbuf; 1488 else 1489 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 1490 tmp = macros[macnum].mac_start; 1491 while (tmp != macbuf+4096) { 1492 if ((c = getchar()) == EOF) { 1493 fputs("macdef: end of file encountered.\n", ttyout); 1494 code = -1; 1495 return; 1496 } 1497 if ((*tmp = c) == '\n') { 1498 if (tmp == macros[macnum].mac_start) { 1499 macros[macnum++].mac_end = tmp; 1500 code = 0; 1501 return; 1502 } 1503 if (*(tmp-1) == '\0') { 1504 macros[macnum++].mac_end = tmp - 1; 1505 code = 0; 1506 return; 1507 } 1508 *tmp = '\0'; 1509 } 1510 tmp++; 1511 } 1512 while (1) { 1513 while ((c = getchar()) != '\n' && c != EOF) 1514 /* LOOP */; 1515 if (c == EOF || getchar() == '\n') { 1516 fputs("Macro not defined - 4K buffer exceeded.\n", ttyout); 1517 code = -1; 1518 return; 1519 } 1520 } 1521 } 1522 1523 /* 1524 * Get size of file on remote machine 1525 */ 1526 void 1527 sizecmd(int argc, char *argv[]) 1528 { 1529 off_t size; 1530 1531 if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) { 1532 fprintf(ttyout, "usage: %s file\n", argv[0]); 1533 code = -1; 1534 return; 1535 } 1536 size = remotesize(argv[1], 1); 1537 if (size != -1) 1538 fprintf(ttyout, "%s\t%lld\n", argv[1], (long long)size); 1539 code = size; 1540 } 1541 1542 /* 1543 * Get last modification time of file on remote machine 1544 */ 1545 void 1546 modtime(int argc, char *argv[]) 1547 { 1548 time_t mtime; 1549 1550 if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) { 1551 fprintf(ttyout, "usage: %s file\n", argv[0]); 1552 code = -1; 1553 return; 1554 } 1555 mtime = remotemodtime(argv[1], 1); 1556 if (mtime != -1) 1557 fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime))); 1558 code = mtime; 1559 } 1560 1561 /* 1562 * Show status on remote machine 1563 */ 1564 void 1565 rmtstatus(int argc, char *argv[]) 1566 { 1567 1568 (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); 1569 } 1570 1571 /* 1572 * Get file if modtime is more recent than current file 1573 */ 1574 void 1575 newer(int argc, char *argv[]) 1576 { 1577 1578 if (getit(argc, argv, -1, "w")) 1579 fprintf(ttyout, "Local file \"%s\" is newer than remote file \"%s\".\n", 1580 argv[2], argv[1]); 1581 } 1582 1583 /* 1584 * Display one file through $PAGER (defaults to "more"). 1585 */ 1586 void 1587 page(int argc, char *argv[]) 1588 { 1589 int orestart_point, ohash, overbose; 1590 char *p, *pager, *oldargv1; 1591 1592 if ((argc < 2 && !another(&argc, &argv, "file")) || argc > 2) { 1593 fprintf(ttyout, "usage: %s file\n", argv[0]); 1594 code = -1; 1595 return; 1596 } 1597 oldargv1 = argv[1]; 1598 if (!globulize(&argv[1])) { 1599 code = -1; 1600 return; 1601 } 1602 p = getenv("PAGER"); 1603 if (p == NULL || (*p == '\0')) 1604 p = PAGER; 1605 if (asprintf(&pager, "|%s", p) == -1) 1606 errx(1, "Can't allocate memory for $PAGER"); 1607 1608 orestart_point = restart_point; 1609 ohash = hash; 1610 overbose = verbose; 1611 restart_point = hash = verbose = 0; 1612 recvrequest("RETR", pager, argv[1], "r+w", 1, 0); 1613 (void)free(pager); 1614 restart_point = orestart_point; 1615 hash = ohash; 1616 verbose = overbose; 1617 if (oldargv1 != argv[1]) /* free up after globulize() */ 1618 free(argv[1]); 1619 } 1620 1621 #endif /* !SMALL */ 1622 1623