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