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