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