home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / ftp / cmds.c next >
Encoding:
C/C++ Source or Header  |  1996-07-22  |  41.6 KB  |  2,385 lines

  1. /*
  2.  * Copyright (c) 1985, 1989, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)cmds.c    8.6 (Berkeley) 10/9/94";
  36. #endif /* not lint */
  37.  
  38. /*
  39.  * FTP User Program -- Command Routines.
  40.  */
  41. #ifdef HAVE_CONFIG_H
  42. #include <config.h>
  43. #endif
  44.  
  45. #include <sys/param.h>
  46. #include <sys/wait.h>
  47. #include <sys/stat.h>
  48. #include <sys/socket.h>
  49. #include <netinet/in.h>
  50. #include <arpa/ftp.h>
  51.  
  52. #include <ctype.h>
  53. #include <err.h>
  54. #include <errno.h>
  55. #include <glob.h>
  56. #include <netdb.h>
  57. #include <signal.h>
  58. #include <stdio.h>
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <time.h>
  62. #include <unistd.h>
  63. #include <paths.h>
  64.  
  65. #include "ftp_var.h"
  66.  
  67. #ifndef HAVE_STRDUP
  68. static char *
  69. strdup (str)
  70.     char *str;
  71. {
  72.     char *dup;
  73.     if (str) {
  74.         dup = malloc (strlen (str) + 1);
  75.         if (dup)
  76.             strcpy (dup, str);
  77.     } else
  78.         dup = 0;
  79.     return dup;
  80. }
  81. #endif
  82.  
  83. /* Returns true if STR is entirely lower case.  */
  84. static int
  85. all_lower (str)
  86.     char *str;
  87. {
  88.     while (*str)
  89.         if (isupper (*str++))
  90.             return 0;
  91.     return 1;
  92. }
  93.  
  94. /* Returns true if STR is entirely upper case.  */
  95. static int
  96. all_upper (str)
  97.     char *str;
  98. {
  99.     while (*str)
  100.         if (islower (*str++))
  101.             return 0;
  102.     return 1;
  103. }
  104.  
  105. /* Destructively converts STR to upper case.  */
  106. static char *
  107. strup (str)
  108.     char *str;
  109. {
  110.     char *p;
  111.     for (p = str; *p; p++)
  112.         if (islower (*p))
  113.             *p = toupper (*p);
  114.     return str;
  115. }
  116.  
  117. /* Destructively converts STR to lower case.  */
  118. static char *
  119. strdown (str)
  120.     char *str;
  121. {
  122.     char *p;
  123.     for (p = str; *p; p++)
  124.         if (isupper (*p))
  125.             *p = tolower (*p);
  126.     return str;
  127. }
  128.  
  129. jmp_buf    jabort;
  130. char   *mname;
  131. char   *home = "/";
  132.  
  133. char *mapin = 0;
  134. char *mapout = 0;
  135.  
  136. /*
  137.  * `Another' gets another argument, and stores the new argc and argv.
  138.  * It reverts to the top level (via main.c's intr()) on EOF/error.
  139.  *
  140.  * Returns false if no new arguments have been added.
  141.  */
  142. int
  143. another(pargc, pargv, prompt)
  144.     int *pargc;
  145.     char ***pargv;
  146.     char *prompt;
  147. {
  148.     int len = strlen(line), ret;
  149.  
  150.     if (len >= sizeof(line) - 3) {
  151.         printf("sorry, arguments too long\n");
  152.         intr();
  153.     }
  154.     printf("(%s) ", prompt);
  155.     line[len++] = ' ';
  156.     if (fgets(&line[len], sizeof(line) - len, stdin) == NULL)
  157.         intr();
  158.     len += strlen(&line[len]);
  159.     if (len > 0 && line[len - 1] == '\n')
  160.         line[len - 1] = '\0';
  161.     makeargv();
  162.     ret = margc > *pargc;
  163.     *pargc = margc;
  164.     *pargv = margv;
  165.     return (ret);
  166. }
  167.  
  168. /*
  169.  * Connect to peer server and
  170.  * auto-login, if possible.
  171.  */
  172. void
  173. setpeer(argc, argv)
  174.     int argc;
  175.     char *argv[];
  176. {
  177.     char *host;
  178.     short port;
  179.  
  180.     if (connected) {
  181.         printf("Already connected to %s, use close first.\n",
  182.             hostname);
  183.         code = -1;
  184.         return;
  185.     }
  186.     if (argc < 2)
  187.         (void) another(&argc, &argv, "to");
  188.     if (argc < 2 || argc > 3) {
  189.         printf("usage: %s host-name [port]\n", argv[0]);
  190.         code = -1;
  191.         return;
  192.     }
  193.     port = sp->s_port;
  194.     if (argc > 2) {
  195.         port = atoi(argv[2]);
  196.         if (port <= 0) {
  197.             printf("%s: bad port number-- %s\n", argv[1], argv[2]);
  198.             printf ("usage: %s host-name [port]\n", argv[0]);
  199.             code = -1;
  200.             return;
  201.         }
  202.         port = htons(port);
  203.     }
  204.     host = hookup(argv[1], port);
  205.     if (host) {
  206.         int overbose;
  207.  
  208.         connected = 1;
  209.         /*
  210.          * Set up defaults for FTP.
  211.          */
  212.         (void) strcpy(typename, "ascii"), type = TYPE_A;
  213.         curtype = TYPE_A;
  214.         (void) strcpy(formname, "non-print"), form = FORM_N;
  215.         (void) strcpy(modename, "stream"), mode = MODE_S;
  216.         (void) strcpy(structname, "file"), stru = STRU_F;
  217.         (void) strcpy(bytename, "8"), bytesize = 8;
  218.         if (autologin)
  219.             (void) login(argv[1]);
  220.  
  221. #if defined(unix) && NBBY == 8
  222. /*
  223.  * this ifdef is to keep someone form "porting" this to an incompatible
  224.  * system and not checking this out. This way they have to think about it.
  225.  */
  226.         overbose = verbose;
  227.         if (debug == 0)
  228.             verbose = -1;
  229.         if (command("SYST") == COMPLETE && overbose) {
  230.             char *cp, c;
  231.             cp = strchr(reply_string+4, ' ');
  232.             if (cp == NULL)
  233.                 cp = strchr(reply_string+4, '\r');
  234.             if (cp) {
  235.                 if (cp[-1] == '.')
  236.                     cp--;
  237.                 c = *cp;
  238.                 *cp = '\0';
  239.             }
  240.  
  241.             printf("Remote system type is %s.\n",
  242.                 reply_string+4);
  243.             if (cp)
  244.                 *cp = c;
  245.         }
  246.         if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
  247.             if (proxy)
  248.                 unix_proxy = 1;
  249.             else
  250.                 unix_server = 1;
  251.             /*
  252.              * Set type to 0 (not specified by user),
  253.              * meaning binary by default, but don't bother
  254.              * telling server.  We can use binary
  255.              * for text files unless changed by the user.
  256.              */
  257.             type = 0;
  258.             (void) strcpy(typename, "binary");
  259.             if (overbose)
  260.                 printf("Using %s mode to transfer files.\n",
  261.                 typename);
  262.         } else {
  263.             if (proxy)
  264.                 unix_proxy = 0;
  265.             else
  266.                 unix_server = 0;
  267.             if (overbose &&
  268.                 !strncmp(reply_string, "215 TOPS20", 10))
  269.                 printf(
  270. "Remember to set tenex mode when transfering binary files from this machine.\n");
  271.         }
  272.         verbose = overbose;
  273. #endif /* unix */
  274.     }
  275. }
  276.  
  277. struct    types {
  278.     char    *t_name;
  279.     char    *t_mode;
  280.     int    t_type;
  281.     char    *t_arg;
  282. } types[] = {
  283.     { "ascii",    "A",    TYPE_A,    0 },
  284.     { "binary",    "I",    TYPE_I,    0 },
  285.     { "image",    "I",    TYPE_I,    0 },
  286.     { "ebcdic",    "E",    TYPE_E,    0 },
  287.     { "tenex",    "L",    TYPE_L,    bytename },
  288.     { NULL }
  289. };
  290.  
  291. /*
  292.  * Set transfer type.
  293.  */
  294. void
  295. settype(argc, argv)
  296.     int argc;
  297.     char *argv[];
  298. {
  299.     struct types *p;
  300.     int comret;
  301.  
  302.     if (argc > 2) {
  303.         char *sep;
  304.  
  305.         printf("usage: %s [", argv[0]);
  306.         sep = " ";
  307.         for (p = types; p->t_name; p++) {
  308.             printf("%s%s", sep, p->t_name);
  309.             sep = " | ";
  310.         }
  311.         printf(" ]\n");
  312.         code = -1;
  313.         return;
  314.     }
  315.     if (argc < 2) {
  316.         printf("Using %s mode to transfer files.\n", typename);
  317.         code = 0;
  318.         return;
  319.     }
  320.     for (p = types; p->t_name; p++)
  321.         if (strcmp(argv[1], p->t_name) == 0)
  322.             break;
  323.     if (p->t_name == 0) {
  324.         printf("%s: unknown mode\n", argv[1]);
  325.         code = -1;
  326.         return;
  327.     }
  328.     if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
  329.         comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
  330.     else
  331.         comret = command("TYPE %s", p->t_mode);
  332.     if (comret == COMPLETE) {
  333.         (void) strcpy(typename, p->t_name);
  334.         curtype = type = p->t_type;
  335.     }
  336. }
  337.  
  338. /*
  339.  * Internal form of settype; changes current type in use with server
  340.  * without changing our notion of the type for data transfers.
  341.  * Used to change to and from ascii for listings.
  342.  */
  343. void
  344. changetype(newtype, show)
  345.     int newtype, show;
  346. {
  347.     struct types *p;
  348.     int comret, oldverbose = verbose;
  349.  
  350.     if (newtype == 0)
  351.         newtype = TYPE_I;
  352.     if (newtype == curtype)
  353.         return;
  354.     if (debug == 0 && show == 0)
  355.         verbose = 0;
  356.     for (p = types; p->t_name; p++)
  357.         if (newtype == p->t_type)
  358.             break;
  359.     if (p->t_name == 0) {
  360.         printf("ftp: internal error: unknown type %d\n", newtype);
  361.         return;
  362.     }
  363.     if (newtype == TYPE_L && bytename[0] != '\0')
  364.         comret = command("TYPE %s %s", p->t_mode, bytename);
  365.     else
  366.         comret = command("TYPE %s", p->t_mode);
  367.     if (comret == COMPLETE)
  368.         curtype = newtype;
  369.     verbose = oldverbose;
  370. }
  371.  
  372. char *stype[] = {
  373.     "type",
  374.     "",
  375.     0
  376. };
  377.  
  378. /*
  379.  * Set binary transfer type.
  380.  */
  381. /*VARARGS*/
  382. void
  383. setbinary(argc, argv)
  384.     int argc;
  385.     char **argv;
  386. {
  387.  
  388.     stype[1] = "binary";
  389.     settype(2, stype);
  390. }
  391.  
  392. /*
  393.  * Set ascii transfer type.
  394.  */
  395. /*VARARGS*/
  396. void
  397. setascii(argc, argv)
  398.     int argc;
  399.     char *argv[];
  400. {
  401.  
  402.     stype[1] = "ascii";
  403.     settype(2, stype);
  404. }
  405.  
  406. /*
  407.  * Set tenex transfer type.
  408.  */
  409. /*VARARGS*/
  410. void
  411. settenex(argc, argv)
  412.     int argc;
  413.     char *argv[];
  414. {
  415.  
  416.     stype[1] = "tenex";
  417.     settype(2, stype);
  418. }
  419.  
  420. /*
  421.  * Set file transfer mode.
  422.  */
  423. /*ARGSUSED*/
  424. void
  425. setftmode(argc, argv)
  426.     int argc;
  427.     char *argv[];
  428. {
  429.  
  430.     printf("We only support %s mode, sorry.\n", modename);
  431.     code = -1;
  432. }
  433.  
  434. /*
  435.  * Set file transfer format.
  436.  */
  437. /*ARGSUSED*/
  438. void
  439. setform(argc, argv)
  440.     int argc;
  441.     char *argv[];
  442. {
  443.  
  444.     printf("We only support %s format, sorry.\n", formname);
  445.     code = -1;
  446. }
  447.  
  448. /*
  449.  * Set file transfer structure.
  450.  */
  451. /*ARGSUSED*/
  452. void
  453. setstruct(argc, argv)
  454.     int argc;
  455.     char *argv[];
  456. {
  457.  
  458.     printf("We only support %s structure, sorry.\n", structname);
  459.     code = -1;
  460. }
  461.  
  462. /*
  463.  * Send a single file.
  464.  */
  465. void
  466. put(argc, argv)
  467.     int argc;
  468.     char *argv[];
  469. {
  470.     char *cmd, *local, *remote;
  471.     int loc = 0;
  472.  
  473.     if (argc == 2) {
  474.         argc++;
  475.         argv[2] = argv[1];
  476.         loc++;
  477.     }
  478.     if (argc < 2 && !another(&argc, &argv, "local-file"))
  479.         goto usage;
  480.     if (argc < 3 && !another(&argc, &argv, "remote-file")) {
  481. usage:
  482.         printf("usage: %s local-file remote-file\n", argv[0]);
  483.         code = -1;
  484.         return;
  485.     }
  486.  
  487.     local = globulize (argv[1]);
  488.     if (! local) {
  489.         code = -1;
  490.         return;
  491.     }
  492.  
  493.     /*
  494.      * If "globulize" modifies argv[1], and argv[2] is a copy of
  495.      * the old argv[1], make it a copy of the new argv[1].
  496.      */
  497.     if (loc)
  498.         remote = strdup (local);
  499.     else
  500.         remote = strdup (argv[2]);
  501.  
  502.     cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
  503.     if (loc && ntflag) {
  504.         char *new = dotrans(remote);
  505.         free (remote);
  506.         remote = new;
  507.     }
  508.     if (loc && mapflag) {
  509.         char *new = domap(remote);
  510.         free (remote);
  511.         remote = new;
  512.     }
  513.     sendrequest(cmd, local, remote,
  514.             strcmp (argv[1], local) != 0
  515.             || strcmp (argv[2], remote) != 0);
  516.     free (local);
  517.     free (remote);
  518. }
  519.  
  520. /*
  521.  * Send multiple files.
  522.  */
  523. void
  524. mput(argc, argv)
  525.     int argc;
  526.     char **argv;
  527. {
  528.     int i;
  529.     sig_t oldintr;
  530.     int ointer;
  531.  
  532.     if (argc < 2 && !another(&argc, &argv, "local-files")) {
  533.         printf("usage: %s local-files\n", argv[0]);
  534.         code = -1;
  535.         return;
  536.     }
  537.     mname = argv[0];
  538.     mflag = 1;
  539.     oldintr = signal(SIGINT, mabort);
  540.     (void) setjmp(jabort);
  541.     if (proxy) {
  542.         char *cp;
  543.  
  544.         while ((cp = remglob(argv,0)) != NULL) {
  545.             if (*cp == 0)
  546.                 mflag = 0;
  547.             if (mflag && confirm(argv[0], cp)) {
  548.                 char *tp = cp;
  549.  
  550.                 if (mcase) {
  551.                     if (all_upper (tp))
  552.                         tp = strdown (strdup (tp));
  553.                 }
  554.                 if (ntflag) {
  555.                     char *new = dotrans(tp);
  556.                     if (tp != cp)
  557.                         free (tp);
  558.                     tp = new;
  559.                 }
  560.                 if (mapflag) {
  561.                     char *new = domap(tp);
  562.                     if (tp != cp)
  563.                         free (tp);
  564.                     tp = new;
  565.                 }
  566.                 sendrequest((sunique) ? "STOU" : "STOR",
  567.                     cp, tp, cp != tp || !interactive);
  568.                 if (!mflag && fromatty) {
  569.                     ointer = interactive;
  570.                     interactive = 1;
  571.                     if (confirm("Continue with","mput")) {
  572.                         mflag++;
  573.                     }
  574.                     interactive = ointer;
  575.                 }
  576.  
  577.                 if (tp != cp)
  578.                     free (tp);
  579.             }
  580.  
  581.             free (cp);
  582.         }
  583.         (void) signal(SIGINT, oldintr);
  584.         mflag = 0;
  585.         return;
  586.     }
  587.     for (i = 1; i < argc; i++) {
  588.         char **cpp, **gargs;
  589.         glob_t gl;
  590.         int flags;
  591.  
  592.         if (!doglob) {
  593.             if (mflag && confirm(argv[0], argv[i])) {
  594.                 char *tp = argv[i];
  595.                 if (ntflag)
  596.                     tp = dotrans (tp);
  597.                 if (mapflag) {
  598.                     char *new = domap (tp);
  599.                     if (tp != argv[i])
  600.                         free (tp);
  601.                     tp = new;
  602.                 }
  603.                 sendrequest((sunique) ? "STOU" : "STOR",
  604.                     argv[i], tp, tp != argv[i] || !interactive);
  605.                 if (!mflag && fromatty) {
  606.                     ointer = interactive;
  607.                     interactive = 1;
  608.                     if (confirm("Continue with","mput")) {
  609.                         mflag++;
  610.                     }
  611.                     interactive = ointer;
  612.                 }
  613.                 if (tp != argv[i])
  614.                     free (tp);
  615.             }
  616.             continue;
  617.         }
  618.  
  619.         memset(&gl, 0, sizeof(gl));
  620.         flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
  621. #ifdef GLOB_QUOTE
  622.         flags |= GLOB_QUOTE;
  623. #endif
  624.         if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
  625.             warnx("%s: not found", argv[i]);
  626.             globfree(&gl);
  627.             continue;
  628.         }
  629.         for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
  630.             if (mflag && confirm(argv[0], *cpp)) {
  631.                 char *tp = *cpp;
  632.                 if (ntflag)
  633.                     tp = dotrans (tp);
  634.                 if (mapflag) {
  635.                     char *new = domap (tp);
  636.                     if (tp != *cpp)
  637.                         free (tp);
  638.                     tp = new;
  639.                 }
  640.                 sendrequest((sunique) ? "STOU" : "STOR",
  641.                     *cpp, tp, *cpp != tp || !interactive);
  642.                 if (!mflag && fromatty) {
  643.                     ointer = interactive;
  644.                     interactive = 1;
  645.                     if (confirm("Continue with","mput")) {
  646.                         mflag++;
  647.                     }
  648.                     interactive = ointer;
  649.                 }
  650.                 if (tp != *cpp)
  651.                     free (tp);
  652.             }
  653.         }
  654.         globfree(&gl);
  655.     }
  656.     (void) signal(SIGINT, oldintr);
  657.     mflag = 0;
  658. }
  659.  
  660. void
  661. reget(argc, argv)
  662.     int argc;
  663.     char *argv[];
  664. {
  665.  
  666.     (void) getit(argc, argv, 1, "r+w");
  667. }
  668.  
  669. void
  670. get(argc, argv)
  671.     int argc;
  672.     char *argv[];
  673. {
  674.  
  675.     (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
  676. }
  677.  
  678. /*
  679.  * Receive one file.
  680.  */
  681. int
  682. getit(argc, argv, restartit, mode)
  683.     int argc;
  684.     char *argv[];
  685.     char *mode;
  686.     int restartit;
  687. {
  688.     int loc = 0;
  689.     char *local;
  690.  
  691.     if (argc == 2) {
  692.         argc++;
  693.         argv[2] = argv[1];
  694.         loc++;
  695.     }
  696.     if (argc < 2 && !another(&argc, &argv, "remote-file"))
  697.         goto usage;
  698.     if (argc < 3 && !another(&argc, &argv, "local-file")) {
  699. usage:
  700.         printf("usage: %s remote-file [ local-file ]\n", argv[0]);
  701.         code = -1;
  702.         return (0);
  703.     }
  704.  
  705.     local = globulize (argv[2]);
  706.     if (! local) {
  707.         code = -1;
  708.         return (0);
  709.     }
  710.     if (loc && mcase && all_upper (local))
  711.         strdown (local);
  712.     if (loc && ntflag) {
  713.         char *new = dotrans(local);
  714.         free (local);
  715.         local = new;
  716.     }
  717.     if (loc && mapflag) {
  718.         char *new = domap(local);
  719.         free (local);
  720.         local = new;
  721.     }
  722.     if (restartit) {
  723.         struct stat stbuf;
  724.         int ret;
  725.  
  726.         ret = stat(local, &stbuf);
  727.         if (restartit == 1) {
  728.             if (ret < 0) {
  729.                 warn("local: %s", local);
  730.                 free (local);
  731.                 return (0);
  732.             }
  733.             restart_point = stbuf.st_size;
  734.         } else {
  735.             if (ret == 0) {
  736.                 int overbose;
  737.  
  738.                 overbose = verbose;
  739.                 if (debug == 0)
  740.                     verbose = -1;
  741.                 if (command("MDTM %s", argv[1]) == COMPLETE) {
  742.                     int yy, mo, day, hour, min, sec;
  743.                     struct tm *tm;
  744.                     verbose = overbose;
  745.                     sscanf(reply_string,
  746.                         "%*s %04d%02d%02d%02d%02d%02d",
  747.                         &yy, &mo, &day, &hour, &min, &sec);
  748.                     tm = gmtime(&stbuf.st_mtime);
  749.                     tm->tm_mon++;
  750.                     if (tm->tm_year > yy%100) {
  751.                         free (local);
  752.                         return (1);
  753.                     }
  754.                     if ((tm->tm_year == yy%100 &&
  755.                         tm->tm_mon > mo) ||
  756.                        (tm->tm_mon == mo &&
  757.                         tm->tm_mday > day) ||
  758.                        (tm->tm_mday == day &&
  759.                         tm->tm_hour > hour) ||
  760.                        (tm->tm_hour == hour &&
  761.                         tm->tm_min > min) ||
  762.                        (tm->tm_min == min &&
  763.                         tm->tm_sec > sec)) {
  764.                         free (local);
  765.                         return (1);
  766.                     }
  767.                 } else {
  768.                     printf("%s\n", reply_string);
  769.                     verbose = overbose;
  770.                     free (local);
  771.                     return (0);
  772.                 }
  773.             }
  774.         }
  775.     }
  776.  
  777.     recvrequest("RETR", local, argv[1], mode, strcmp (local, argv[2]) != 0);
  778.     restart_point = 0;
  779.     free (local);
  780.     return (0);
  781. }
  782.  
  783. /* ARGSUSED */
  784. void
  785. mabort(signo)
  786.     int signo;
  787. {
  788.     int ointer;
  789.  
  790.     printf("\n");
  791.     (void) fflush(stdout);
  792.     if (mflag && fromatty) {
  793.         ointer = interactive;
  794.         interactive = 1;
  795.         if (confirm("Continue with", mname)) {
  796.             interactive = ointer;
  797.             longjmp(jabort,0);
  798.         }
  799.         interactive = ointer;
  800.     }
  801.     mflag = 0;
  802.     longjmp(jabort,0);
  803. }
  804.  
  805. /*
  806.  * Get multiple files.
  807.  */
  808. void
  809. mget(argc, argv)
  810.     int argc;
  811.     char **argv;
  812. {
  813.     sig_t oldintr;
  814.     int ch, ointer;
  815.     char *cp, *tp, *tp2;
  816.  
  817.     if (argc < 2 && !another(&argc, &argv, "remote-files")) {
  818.         printf("usage: %s remote-files\n", argv[0]);
  819.         code = -1;
  820.         return;
  821.     }
  822.     mname = argv[0];
  823.     mflag = 1;
  824.     oldintr = signal(SIGINT, mabort);
  825.     (void) setjmp(jabort);
  826.     while ((cp = remglob(argv,proxy)) != NULL) {
  827.         if (*cp == '\0') {
  828.             mflag = 0;
  829.             continue;
  830.         }
  831.         if (mflag && confirm(argv[0], cp)) {
  832.             tp = cp;
  833.             if (mcase && ! all_lower (tp))
  834.                 tp = strdown (strdup (tp));
  835.             if (ntflag) {
  836.                 char *new = dotrans (tp);
  837.                 if (tp != cp)
  838.                     free (tp);
  839.                 tp = new;
  840.             }
  841.             if (mapflag) {
  842.                 char *new = domap (tp);
  843.                 if (tp != cp)
  844.                     free (tp);
  845.                 tp = new;
  846.             }
  847.             recvrequest("RETR", tp, cp, "w",
  848.                     tp != cp || !interactive);
  849.             if (!mflag && fromatty) {
  850.                 ointer = interactive;
  851.                 interactive = 1;
  852.                 if (confirm("Continue with","mget")) {
  853.                     mflag++;
  854.                 }
  855.                 interactive = ointer;
  856.             }
  857.             if (tp != cp)
  858.                 free (tp);
  859.         }
  860.         free (cp);
  861.     }
  862.     (void) signal(SIGINT,oldintr);
  863.     mflag = 0;
  864. }
  865.  
  866. char *
  867. remglob(argv,doswitch)
  868.     char *argv[];
  869.     int doswitch;
  870. {
  871.     static FILE *ftemp = NULL;
  872.     static char **args;
  873.     int buf_len = 0;
  874.     char *buf = 0;
  875.     int sofar = 0;
  876.     int oldverbose, oldhash;
  877.     char *cp, *mode, *end;
  878.  
  879.     if (!mflag) {
  880.         if (!doglob) {
  881.             args = NULL;
  882.         }
  883.         else {
  884.             if (ftemp) {
  885.                 (void) fclose(ftemp);
  886.                 ftemp = NULL;
  887.             }
  888.         }
  889.         return (NULL);
  890.     }
  891.     if (!doglob) {
  892.         if (args == NULL)
  893.             args = argv;
  894.         if ((cp = *++args) == NULL)
  895.             args = NULL;
  896.         return cp ? 0 : strdup (cp);
  897.     }
  898.     if (ftemp == NULL) {
  899.         char temp[sizeof _PATH_TMP + sizeof "XXXXXX"];
  900.  
  901.         strcpy (temp, _PATH_TMP);
  902.         strcat (temp, "XXXXXX");
  903.         mktemp (temp);
  904.  
  905.         oldverbose = verbose, verbose = 0;
  906.         oldhash = hash, hash = 0;
  907.         if (doswitch) {
  908.             pswitch(!proxy);
  909.         }
  910.         for (mode = "w"; *++argv != NULL; mode = "a")
  911.             recvrequest ("NLST", temp, *argv, mode, 0);
  912.         if (doswitch) {
  913.             pswitch(!proxy);
  914.         }
  915.         verbose = oldverbose; hash = oldhash;
  916.         ftemp = fopen(temp, "r");
  917.         (void) unlink(temp);
  918.         if (ftemp == NULL) {
  919.             printf("can't find list of remote files, oops\n");
  920.             return (NULL);
  921.         }
  922.     }
  923.  
  924.     buf_len = 100;        /* Any old size */
  925.     buf = malloc (buf_len + 1);
  926.  
  927.     sofar = 0;
  928.     for (;;) {
  929.         if (! buf) {
  930.             printf ("malloc failure\n");
  931.             return 0;
  932.         }
  933.         if (! fgets(buf + sofar, buf_len - sofar, ftemp)) {
  934.             fclose(ftemp);
  935.             ftemp = NULL;
  936.             free (buf);
  937.             return 0;
  938.         }
  939.  
  940.         sofar = strlen (buf);
  941.         if (buf[sofar - 1] == '\n') {
  942.             buf[sofar - 1] = '\0';
  943.             return buf;
  944.         }
  945.  
  946.         /* Make more room and read some more... */
  947.         buf_len += buf_len;
  948.         buf = realloc (buf, buf_len);
  949.     }
  950. }
  951.  
  952. char *
  953. onoff(bool)
  954.     int bool;
  955. {
  956.     return (bool ? "on" : "off");
  957. }
  958.  
  959. /*
  960.  * Show status.
  961.  */
  962. /*ARGSUSED*/
  963. void
  964. status(argc, argv)
  965.     int argc;
  966.     char *argv[];
  967. {
  968.     int i;
  969.  
  970.     if (connected)
  971.         printf("Connected to %s.\n", hostname);
  972.     else
  973.         printf("Not connected.\n");
  974.     if (!proxy) {
  975.         pswitch(1);
  976.         if (connected) {
  977.             printf("Connected for proxy commands to %s.\n", hostname);
  978.         }
  979.         else {
  980.             printf("No proxy connection.\n");
  981.         }
  982.         pswitch(0);
  983.     }
  984.     printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
  985.         modename, typename, formname, structname);
  986.     printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
  987.         onoff(verbose), onoff(bell), onoff(interactive),
  988.         onoff(doglob));
  989.     printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
  990.         onoff(runique));
  991.     printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
  992.     if (ntflag) {
  993.         printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
  994.     }
  995.     else {
  996.         printf("Ntrans: off\n");
  997.     }
  998.     if (mapflag) {
  999.         printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
  1000.     }
  1001.     else {
  1002.         printf("Nmap: off\n");
  1003.     }
  1004.     printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
  1005.         onoff(hash), onoff(sendport));
  1006.     if (macnum > 0) {
  1007.         printf("Macros:\n");
  1008.         for (i=0; i<macnum; i++) {
  1009.             printf("\t%s\n",macros[i].mac_name);
  1010.         }
  1011.     }
  1012.     code = 0;
  1013. }
  1014.  
  1015. /*
  1016.  * Set beep on cmd completed mode.
  1017.  */
  1018. /*VARARGS*/
  1019. void
  1020. setbell(argc, argv)
  1021.     int argc;
  1022.     char *argv[];
  1023. {
  1024.  
  1025.     bell = !bell;
  1026.     printf("Bell mode %s.\n", onoff(bell));
  1027.     code = bell;
  1028. }
  1029.  
  1030. /*
  1031.  * Turn on packet tracing.
  1032.  */
  1033. /*VARARGS*/
  1034. void
  1035. settrace(argc, argv)
  1036.     int argc;
  1037.     char *argv[];
  1038. {
  1039.  
  1040.     trace = !trace;
  1041.     printf("Packet tracing %s.\n", onoff(trace));
  1042.     code = trace;
  1043. }
  1044.  
  1045. /*
  1046.  * Toggle hash mark printing during transfers.
  1047.  */
  1048. /*VARARGS*/
  1049. void
  1050. sethash(argc, argv)
  1051.     int argc;
  1052.     char *argv[];
  1053. {
  1054.  
  1055.     hash = !hash;
  1056.     printf("Hash mark printing %s", onoff(hash));
  1057.     code = hash;
  1058.     if (hash)
  1059.         printf(" (%d bytes/hash mark)", 1024);
  1060.     printf(".\n");
  1061. }
  1062.  
  1063. /*
  1064.  * Turn on printing of server echo's.
  1065.  */
  1066. /*VARARGS*/
  1067. void
  1068. setverbose(argc, argv)
  1069.     int argc;
  1070.     char *argv[];
  1071. {
  1072.  
  1073.     verbose = !verbose;
  1074.     printf("Verbose mode %s.\n", onoff(verbose));
  1075.     code = verbose;
  1076. }
  1077.  
  1078. /*
  1079.  * Toggle PORT cmd use before each data connection.
  1080.  */
  1081. /*VARARGS*/
  1082. void
  1083. setport(argc, argv)
  1084.     int argc;
  1085.     char *argv[];
  1086. {
  1087.  
  1088.     sendport = !sendport;
  1089.     printf("Use of PORT cmds %s.\n", onoff(sendport));
  1090.     code = sendport;
  1091. }
  1092.  
  1093. /*
  1094.  * Turn on interactive prompting
  1095.  * during mget, mput, and mdelete.
  1096.  */
  1097. /*VARARGS*/
  1098. void
  1099. setprompt(argc, argv)
  1100.     int argc;
  1101.     char *argv[];
  1102. {
  1103.  
  1104.     interactive = !interactive;
  1105.     printf("Interactive mode %s.\n", onoff(interactive));
  1106.     code = interactive;
  1107. }
  1108.  
  1109. /*
  1110.  * Toggle metacharacter interpretation
  1111.  * on local file names.
  1112.  */
  1113. /*VARARGS*/
  1114. void
  1115. setglob(argc, argv)
  1116.     int argc;
  1117.     char *argv[];
  1118. {
  1119.  
  1120.     doglob = !doglob;
  1121.     printf("Globbing %s.\n", onoff(doglob));
  1122.     code = doglob;
  1123. }
  1124.  
  1125. /*
  1126.  * Set debugging mode on/off and/or
  1127.  * set level of debugging.
  1128.  */
  1129. /*VARARGS*/
  1130. void
  1131. setdebug(argc, argv)
  1132.     int argc;
  1133.     char *argv[];
  1134. {
  1135.     int val;
  1136.  
  1137.     if (argc > 1) {
  1138.         val = atoi(argv[1]);
  1139.         if (val < 0) {
  1140.             printf("%s: bad debugging value.\n", argv[1]);
  1141.             code = -1;
  1142.             return;
  1143.         }
  1144.     } else
  1145.         val = !debug;
  1146.     debug = val;
  1147.     if (debug)
  1148.         options |= SO_DEBUG;
  1149.     else
  1150.         options &= ~SO_DEBUG;
  1151.     printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
  1152.     code = debug > 0;
  1153. }
  1154.  
  1155. /*
  1156.  * Set current working directory
  1157.  * on remote machine.
  1158.  */
  1159. void
  1160. cd(argc, argv)
  1161.     int argc;
  1162.     char *argv[];
  1163. {
  1164.  
  1165.     if (argc < 2 && !another(&argc, &argv, "remote-directory")) {
  1166.         printf("usage: %s remote-directory\n", argv[0]);
  1167.         code = -1;
  1168.         return;
  1169.     }
  1170.     if (command("CWD %s", argv[1]) == ERROR && code == 500) {
  1171.         if (verbose)
  1172.             printf("CWD command not recognized, trying XCWD\n");
  1173.         (void) command("XCWD %s", argv[1]);
  1174.     }
  1175. }
  1176.  
  1177. /*
  1178.  * Set current working directory
  1179.  * on local machine.
  1180.  */
  1181. void
  1182. lcd(argc, argv)
  1183.     int argc;
  1184.     char *argv[];
  1185. {
  1186.     char *dir;
  1187.  
  1188.     if (argc < 2)
  1189.         argc++, argv[1] = home;
  1190.     if (argc != 2) {
  1191.         printf("usage: %s local-directory\n", argv[0]);
  1192.         code = -1;
  1193.         return;
  1194.     }
  1195.  
  1196.     dir = globulize (argv[1]);
  1197.     if (! dir) {
  1198.         code = -1;
  1199.         return;
  1200.     }
  1201.  
  1202.     if (chdir(dir) < 0) {
  1203.         warn("dir: %s", dir);
  1204.         free (dir);
  1205.         code = -1;
  1206.         return;
  1207.     }
  1208.  
  1209.     free (dir);
  1210.  
  1211.     dir = getcwd (0, 0);
  1212.     if (dir) {
  1213.         printf("Local directory now %s\n", dir);
  1214.         free (dir);
  1215.     } else
  1216.         warnx("getcwd: %s", strerror (errno));
  1217.     code = 0;
  1218. }
  1219.  
  1220. /*
  1221.  * Delete a single file.
  1222.  */
  1223. void
  1224. delete(argc, argv)
  1225.     int argc;
  1226.     char *argv[];
  1227. {
  1228.  
  1229.     if (argc < 2 && !another(&argc, &argv, "remote-file")) {
  1230.         printf("usage: %s remote-file\n", argv[0]);
  1231.         code = -1;
  1232.         return;
  1233.     }
  1234.     (void) command("DELE %s", argv[1]);
  1235. }
  1236.  
  1237. /*
  1238.  * Delete multiple files.
  1239.  */
  1240. void
  1241. mdelete(argc, argv)
  1242.     int argc;
  1243.     char **argv;
  1244. {
  1245.     sig_t oldintr;
  1246.     int ointer;
  1247.     char *cp;
  1248.  
  1249.     if (argc < 2 && !another(&argc, &argv, "remote-files")) {
  1250.         printf("usage: %s remote-files\n", argv[0]);
  1251.         code = -1;
  1252.         return;
  1253.     }
  1254.     mname = argv[0];
  1255.     mflag = 1;
  1256.     oldintr = signal(SIGINT, mabort);
  1257.     (void) setjmp(jabort);
  1258.     while ((cp = remglob(argv,0)) != NULL) {
  1259.         if (*cp == '\0') {
  1260.             mflag = 0;
  1261.             continue;
  1262.         }
  1263.         if (mflag && confirm(argv[0], cp)) {
  1264.             (void) command("DELE %s", cp);
  1265.             if (!mflag && fromatty) {
  1266.                 ointer = interactive;
  1267.                 interactive = 1;
  1268.                 if (confirm("Continue with", "mdelete")) {
  1269.                     mflag++;
  1270.                 }
  1271.                 interactive = ointer;
  1272.             }
  1273.         }
  1274.         free (cp);
  1275.     }
  1276.     (void) signal(SIGINT, oldintr);
  1277.     mflag = 0;
  1278. }
  1279.  
  1280. /*
  1281.  * Rename a remote file.
  1282.  */
  1283. void
  1284. renamefile(argc, argv)
  1285.     int argc;
  1286.     char *argv[];
  1287. {
  1288.  
  1289.     if (argc < 2 && !another(&argc, &argv, "from-name"))
  1290.         goto usage;
  1291.     if (argc < 3 && !another(&argc, &argv, "to-name")) {
  1292. usage:
  1293.         printf("%s from-name to-name\n", argv[0]);
  1294.         code = -1;
  1295.         return;
  1296.     }
  1297.     if (command("RNFR %s", argv[1]) == CONTINUE)
  1298.         (void) command("RNTO %s", argv[2]);
  1299. }
  1300.  
  1301. /*
  1302.  * Get a directory listing
  1303.  * of remote files.
  1304.  */
  1305. void
  1306. ls(argc, argv)
  1307.     int argc;
  1308.     char *argv[];
  1309. {
  1310.     char *cmd, *dest;
  1311.  
  1312.     if (argc < 2)
  1313.         argc++, argv[1] = NULL;
  1314.     if (argc < 3)
  1315.         argc++, argv[2] = "-";
  1316.     if (argc > 3) {
  1317.         printf("usage: %s remote-directory local-file\n", argv[0]);
  1318.         code = -1;
  1319.         return;
  1320.     }
  1321.     cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
  1322.  
  1323.     if (strcmp(argv[2], "-") != 0) {
  1324.         dest = globulize(argv[2]);
  1325.         if (! dest) {
  1326.             code = -1;
  1327.             return;
  1328.         }
  1329.         if (*dest != '|' && !confirm("output to local-file:", dest)) {
  1330.             code = -1;
  1331.             goto out;
  1332.         }
  1333.     } else
  1334.         dest = 0;
  1335.  
  1336.     recvrequest(cmd, dest ? dest : "-", argv[1], "w", 0);
  1337.  out:
  1338.     if (dest)
  1339.         free (dest);
  1340. }
  1341.  
  1342. /*
  1343.  * Get a directory listing
  1344.  * of multiple remote files.
  1345.  */
  1346. void
  1347. mls(argc, argv)
  1348.     int argc;
  1349.     char **argv;
  1350. {
  1351.     sig_t oldintr;
  1352.     int ointer, i;
  1353.     char *cmd, mode[1], *dest;
  1354.  
  1355.     if (argc < 2 && !another(&argc, &argv, "remote-files"))
  1356.         goto usage;
  1357.     if (argc < 3 && !another(&argc, &argv, "local-file")) {
  1358. usage:
  1359.         printf("usage: %s remote-files local-file\n", argv[0]);
  1360.         code = -1;
  1361.         return;
  1362.     }
  1363.  
  1364.     dest = argv[argc - 1];
  1365.     argv[argc - 1] = NULL;
  1366.     if (strcmp(dest, "-") && *dest != '|') {
  1367.         dest = globulize (dest);
  1368.         if (! dest) {
  1369.             code = -1;
  1370.             return;
  1371.         }
  1372.         if (! confirm("output to local-file:", dest)) {
  1373.             code = -1;
  1374.             free (dest);
  1375.             return;
  1376.         }
  1377.     } else
  1378.         dest = strdup (dest);
  1379.  
  1380.     cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
  1381.     mname = argv[0];
  1382.     mflag = 1;
  1383.     oldintr = signal(SIGINT, mabort);
  1384.     (void) setjmp(jabort);
  1385.     for (i = 1; mflag && i < argc-1; ++i) {
  1386.         *mode = (i == 1) ? 'w' : 'a';
  1387.         recvrequest(cmd, dest, argv[i], mode, 0);
  1388.         if (!mflag && fromatty) {
  1389.             ointer = interactive;
  1390.             interactive = 1;
  1391.             if (confirm("Continue with", argv[0])) {
  1392.                 mflag ++;
  1393.             }
  1394.             interactive = ointer;
  1395.         }
  1396.     }
  1397.  
  1398.     (void) signal(SIGINT, oldintr);
  1399.     mflag = 0;
  1400.     free (dest);
  1401. }
  1402.  
  1403. /*
  1404.  * Do a shell escape
  1405.  */
  1406. /*ARGSUSED*/
  1407. void
  1408. shell(argc, argv)
  1409.     int argc;
  1410.     char **argv;
  1411. {
  1412.     pid_t pid;
  1413.     sig_t old1, old2;
  1414.     char shellnam[40], *shell, *namep;
  1415.     union wait status;
  1416.  
  1417.     old1 = signal (SIGINT, SIG_IGN);
  1418.     old2 = signal (SIGQUIT, SIG_IGN);
  1419.     if ((pid = fork()) == 0) {
  1420.         for (pid = 3; pid < 20; pid++)
  1421.             (void) close(pid);
  1422.         (void) signal(SIGINT, SIG_DFL);
  1423.         (void) signal(SIGQUIT, SIG_DFL);
  1424.         shell = getenv("SHELL");
  1425.         if (shell == NULL)
  1426.             shell = _PATH_BSHELL;
  1427.         namep = strrchr(shell,'/');
  1428.         if (namep == NULL)
  1429.             namep = shell;
  1430.         (void) strcpy(shellnam,"-");
  1431.         (void) strcat(shellnam, ++namep);
  1432.         if (strcmp(namep, "sh") != 0)
  1433.             shellnam[0] = '+';
  1434.         if (debug) {
  1435.             printf ("%s\n", shell);
  1436.             (void) fflush (stdout);
  1437.         }
  1438.         if (argc > 1) {
  1439.             execl(shell,shellnam,"-c",altarg,(char *)0);
  1440.         }
  1441.         else {
  1442.             execl(shell,shellnam,(char *)0);
  1443.         }
  1444.         warn("%s", shell);
  1445.         code = -1;
  1446.         exit(1);
  1447.     }
  1448.     if (pid > 0)
  1449.         while (wait((int *)&status) != pid)
  1450.             ;
  1451.     (void) signal(SIGINT, old1);
  1452.     (void) signal(SIGQUIT, old2);
  1453.     if (pid == -1) {
  1454.         warn("%s", "Try again later");
  1455.         code = -1;
  1456.     }
  1457.     else {
  1458.         code = 0;
  1459.     }
  1460. }
  1461.  
  1462. /*
  1463.  * Send new user information (re-login)
  1464.  */
  1465. void
  1466. user(argc, argv)
  1467.     int argc;
  1468.     char **argv;
  1469. {
  1470.     char acct[80];
  1471.     int n, aflag = 0;
  1472.  
  1473.     if (argc < 2)
  1474.         (void) another(&argc, &argv, "username");
  1475.     if (argc < 2 || argc > 4) {
  1476.         printf("usage: %s username [password] [account]\n", argv[0]);
  1477.         code = -1;
  1478.         return;
  1479.     }
  1480.     n = command("USER %s", argv[1]);
  1481.     if (n == CONTINUE) {
  1482.         if (argc < 3 )
  1483.             argv[2] = getpass("Password: "), argc++;
  1484.         n = command("PASS %s", argv[2]);
  1485.     }
  1486.     if (n == CONTINUE) {
  1487.         if (argc < 4) {
  1488.             printf("Account: "); (void) fflush(stdout);
  1489.             (void) fgets(acct, sizeof(acct) - 1, stdin);
  1490.             acct[strlen(acct) - 1] = '\0';
  1491.             argv[3] = acct; argc++;
  1492.         }
  1493.         n = command("ACCT %s", argv[3]);
  1494.         aflag++;
  1495.     }
  1496.     if (n != COMPLETE) {
  1497.         fprintf(stdout, "Login failed.\n");
  1498.         return;
  1499.     }
  1500.     if (!aflag && argc == 4) {
  1501.         (void) command("ACCT %s", argv[3]);
  1502.     }
  1503. }
  1504.  
  1505. /*
  1506.  * Print working directory.
  1507.  */
  1508. /*VARARGS*/
  1509. void
  1510. pwd(argc, argv)
  1511.     int argc;
  1512.     char *argv[];
  1513. {
  1514.     int oldverbose = verbose;
  1515.  
  1516.     /*
  1517.      * If we aren't verbose, this doesn't do anything!
  1518.      */
  1519.     verbose = 1;
  1520.     if (command("PWD") == ERROR && code == 500) {
  1521.         printf("PWD command not recognized, trying XPWD\n");
  1522.         (void) command("XPWD");
  1523.     }
  1524.     verbose = oldverbose;
  1525. }
  1526.  
  1527. /*
  1528.  * Make a directory.
  1529.  */
  1530. void
  1531. makedir(argc, argv)
  1532.     int argc;
  1533.     char *argv[];
  1534. {
  1535.  
  1536.     if (argc < 2 && !another(&argc, &argv, "directory-name")) {
  1537.         printf("usage: %s directory-name\n", argv[0]);
  1538.         code = -1;
  1539.         return;
  1540.     }
  1541.     if (command("MKD %s", argv[1]) == ERROR && code == 500) {
  1542.         if (verbose)
  1543.             printf("MKD command not recognized, trying XMKD\n");
  1544.         (void) command("XMKD %s", argv[1]);
  1545.     }
  1546. }
  1547.  
  1548. /*
  1549.  * Remove a directory.
  1550.  */
  1551. void
  1552. removedir(argc, argv)
  1553.     int argc;
  1554.     char *argv[];
  1555. {
  1556.  
  1557.     if (argc < 2 && !another(&argc, &argv, "directory-name")) {
  1558.         printf("usage: %s directory-name\n", argv[0]);
  1559.         code = -1;
  1560.         return;
  1561.     }
  1562.     if (command("RMD %s", argv[1]) == ERROR && code == 500) {
  1563.         if (verbose)
  1564.             printf("RMD command not recognized, trying XRMD\n");
  1565.         (void) command("XRMD %s", argv[1]);
  1566.     }
  1567. }
  1568.  
  1569. /*
  1570.  * Send a line, verbatim, to the remote machine.
  1571.  */
  1572. void
  1573. quote(argc, argv)
  1574.     int argc;
  1575.     char *argv[];
  1576. {
  1577.  
  1578.     if (argc < 2 && !another(&argc, &argv, "command line to send")) {
  1579.         printf("usage: %s line-to-send\n", argv[0]);
  1580.         code = -1;
  1581.         return;
  1582.     }
  1583.     quote1("", argc, argv);
  1584. }
  1585.  
  1586. /*
  1587.  * Send a SITE command to the remote machine.  The line
  1588.  * is sent verbatim to the remote machine, except that the
  1589.  * word "SITE" is added at the front.
  1590.  */
  1591. void
  1592. site(argc, argv)
  1593.     int argc;
  1594.     char *argv[];
  1595. {
  1596.  
  1597.     if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
  1598.         printf("usage: %s line-to-send\n", argv[0]);
  1599.         code = -1;
  1600.         return;
  1601.     }
  1602.     quote1("SITE ", argc, argv);
  1603. }
  1604.  
  1605. /*
  1606.  * Turn argv[1..argc) into a space-separated string, then prepend initial text.
  1607.  * Send the result as a one-line command and get response.
  1608.  */
  1609. void
  1610. quote1(initial, argc, argv)
  1611.     char *initial;
  1612.     int argc;
  1613.     char **argv;
  1614. {
  1615.     int i, len;
  1616.     char buf[BUFSIZ];        /* must be >= sizeof(line) */
  1617.  
  1618.     (void) strcpy(buf, initial);
  1619.     if (argc > 1) {
  1620.         len = strlen(buf);
  1621.         len += strlen(strcpy(&buf[len], argv[1]));
  1622.         for (i = 2; i < argc; i++) {
  1623.             buf[len++] = ' ';
  1624.             len += strlen(strcpy(&buf[len], argv[i]));
  1625.         }
  1626.     }
  1627.     if (command(buf) == PRELIM) {
  1628.         while (getreply(0) == PRELIM)
  1629.             continue;
  1630.     }
  1631. }
  1632.  
  1633. void
  1634. do_chmod(argc, argv)
  1635.     int argc;
  1636.     char *argv[];
  1637. {
  1638.  
  1639.     if (argc < 2 && !another(&argc, &argv, "mode"))
  1640.         goto usage;
  1641.     if (argc < 3 && !another(&argc, &argv, "file-name")) {
  1642. usage:
  1643.         printf("usage: %s mode file-name\n", argv[0]);
  1644.         code = -1;
  1645.         return;
  1646.     }
  1647.     (void) command("SITE CHMOD %s %s", argv[1], argv[2]);
  1648. }
  1649.  
  1650. void
  1651. do_umask(argc, argv)
  1652.     int argc;
  1653.     char *argv[];
  1654. {
  1655.     int oldverbose = verbose;
  1656.  
  1657.     verbose = 1;
  1658.     (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
  1659.     verbose = oldverbose;
  1660. }
  1661.  
  1662. void
  1663. idle(argc, argv)
  1664.     int argc;
  1665.     char *argv[];
  1666. {
  1667.     int oldverbose = verbose;
  1668.  
  1669.     verbose = 1;
  1670.     (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
  1671.     verbose = oldverbose;
  1672. }
  1673.  
  1674. /*
  1675.  * Ask the other side for help.
  1676.  */
  1677. void
  1678. rmthelp(argc, argv)
  1679.     int argc;
  1680.     char *argv[];
  1681. {
  1682.     int oldverbose = verbose;
  1683.  
  1684.     verbose = 1;
  1685.     (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
  1686.     verbose = oldverbose;
  1687. }
  1688.  
  1689. /*
  1690.  * Terminate session and exit.
  1691.  */
  1692. /*VARARGS*/
  1693. void
  1694. quit(argc, argv)
  1695.     int argc;
  1696.     char *argv[];
  1697. {
  1698.  
  1699.     if (connected)
  1700.         disconnect(0, 0);
  1701.     pswitch(1);
  1702.     if (connected) {
  1703.         disconnect(0, 0);
  1704.     }
  1705.     exit(0);
  1706. }
  1707.  
  1708. /*
  1709.  * Terminate session, but don't exit.
  1710.  */
  1711. void
  1712. disconnect(argc, argv)
  1713.     int argc;
  1714.     char *argv[];
  1715. {
  1716.  
  1717.     if (!connected)
  1718.         return;
  1719.     (void) command("QUIT");
  1720.     if (cout) {
  1721.         (void) fclose(cout);
  1722.     }
  1723.     cout = NULL;
  1724.     connected = 0;
  1725.     data = -1;
  1726.     if (!proxy) {
  1727.         macnum = 0;
  1728.     }
  1729. }
  1730.  
  1731. int
  1732. confirm(cmd, file)
  1733.     char *cmd, *file;
  1734. {
  1735.     char line[BUFSIZ];
  1736.  
  1737.     if (!interactive)
  1738.         return (1);
  1739.     printf("%s %s? ", cmd, file);
  1740.     (void) fflush(stdout);
  1741.     if (fgets(line, sizeof line, stdin) == NULL)
  1742.         return (0);
  1743.     return (*line != 'n' && *line != 'N');
  1744. }
  1745.  
  1746. void
  1747. fatal(msg)
  1748.     char *msg;
  1749. {
  1750.  
  1751.     errx(1, "%s", msg);
  1752. }
  1753.  
  1754. /*
  1755.  * Glob a local file name specification with
  1756.  * the expectation of a single return value.
  1757.  * Can't control multiple values being expanded
  1758.  * from the expression, we return only the first.
  1759.  */
  1760. char *
  1761. globulize(cp)
  1762.     char *cp;
  1763. {
  1764.     glob_t gl;
  1765.     int flags;
  1766.  
  1767.     if (!doglob)
  1768.         return strdup (cp);
  1769.  
  1770.     flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
  1771. #ifdef GLOB_QUOTE
  1772.     flags |= GLOB_QUOTE;
  1773. #endif
  1774.  
  1775.     memset(&gl, 0, sizeof(gl));
  1776.     if (glob(cp, flags, NULL, &gl) ||
  1777.         gl.gl_pathc == 0) {
  1778.         warnx("%s: not found", cp);
  1779.         globfree(&gl);
  1780.         return (0);
  1781.     }
  1782.  
  1783.     cp = strdup(gl.gl_pathv[0]);
  1784.     globfree(&gl);
  1785.  
  1786.     return cp;
  1787. }
  1788.  
  1789. void
  1790. account(argc,argv)
  1791.     int argc;
  1792.     char **argv;
  1793. {
  1794.     char acct[50], *ap;
  1795.  
  1796.     if (argc > 1) {
  1797.         ++argv;
  1798.         --argc;
  1799.         (void) strncpy(acct,*argv,49);
  1800.         acct[49] = '\0';
  1801.         while (argc > 1) {
  1802.             --argc;
  1803.             ++argv;
  1804.             (void) strncat(acct,*argv, 49-strlen(acct));
  1805.         }
  1806.         ap = acct;
  1807.     }
  1808.     else {
  1809.         ap = getpass("Account:");
  1810.     }
  1811.     (void) command("ACCT %s", ap);
  1812. }
  1813.  
  1814. jmp_buf abortprox;
  1815.  
  1816. void
  1817. proxabort()
  1818. {
  1819.  
  1820.     if (!proxy) {
  1821.         pswitch(1);
  1822.     }
  1823.     if (connected) {
  1824.         proxflag = 1;
  1825.     }
  1826.     else {
  1827.         proxflag = 0;
  1828.     }
  1829.     pswitch(0);
  1830.     longjmp(abortprox,1);
  1831. }
  1832.  
  1833. void
  1834. doproxy(argc, argv)
  1835.     int argc;
  1836.     char *argv[];
  1837. {
  1838.     struct cmd *c;
  1839.     sig_t oldintr;
  1840.  
  1841.     if (argc < 2 && !another(&argc, &argv, "command")) {
  1842.         printf("usage: %s command\n", argv[0]);
  1843.         code = -1;
  1844.         return;
  1845.     }
  1846.     c = getcmd(argv[1]);
  1847.     if (c == (struct cmd *) -1) {
  1848.         printf("?Ambiguous command\n");
  1849.         (void) fflush(stdout);
  1850.         code = -1;
  1851.         return;
  1852.     }
  1853.     if (c == 0) {
  1854.         printf("?Invalid command\n");
  1855.         (void) fflush(stdout);
  1856.         code = -1;
  1857.         return;
  1858.     }
  1859.     if (!c->c_proxy) {
  1860.         printf("?Invalid proxy command\n");
  1861.         (void) fflush(stdout);
  1862.         code = -1;
  1863.         return;
  1864.     }
  1865.     if (setjmp(abortprox)) {
  1866.         code = -1;
  1867.         return;
  1868.     }
  1869.     oldintr = signal(SIGINT, proxabort);
  1870.     pswitch(1);
  1871.     if (c->c_conn && !connected) {
  1872.         printf("Not connected\n");
  1873.         (void) fflush(stdout);
  1874.         pswitch(0);
  1875.         (void) signal(SIGINT, oldintr);
  1876.         code = -1;
  1877.         return;
  1878.     }
  1879.     (*c->c_handler)(argc-1, argv+1);
  1880.     if (connected) {
  1881.         proxflag = 1;
  1882.     }
  1883.     else {
  1884.         proxflag = 0;
  1885.     }
  1886.     pswitch(0);
  1887.     (void) signal(SIGINT, oldintr);
  1888. }
  1889.  
  1890. void
  1891. setcase(argc, argv)
  1892.     int argc;
  1893.     char *argv[];
  1894. {
  1895.  
  1896.     mcase = !mcase;
  1897.     printf("Case mapping %s.\n", onoff(mcase));
  1898.     code = mcase;
  1899. }
  1900.  
  1901. void
  1902. setcr(argc, argv)
  1903.     int argc;
  1904.     char *argv[];
  1905. {
  1906.  
  1907.     crflag = !crflag;
  1908.     printf("Carriage Return stripping %s.\n", onoff(crflag));
  1909.     code = crflag;
  1910. }
  1911.  
  1912. void
  1913. setntrans(argc,argv)
  1914.     int argc;
  1915.     char *argv[];
  1916. {
  1917.     if (argc == 1) {
  1918.         ntflag = 0;
  1919.         printf("Ntrans off.\n");
  1920.         code = ntflag;
  1921.         return;
  1922.     }
  1923.     ntflag++;
  1924.     code = ntflag;
  1925.     (void) strncpy(ntin, argv[1], 16);
  1926.     ntin[16] = '\0';
  1927.     if (argc == 2) {
  1928.         ntout[0] = '\0';
  1929.         return;
  1930.     }
  1931.     (void) strncpy(ntout, argv[2], 16);
  1932.     ntout[16] = '\0';
  1933. }
  1934.  
  1935. char *
  1936. dotrans(name)
  1937.     char *name;
  1938. {
  1939.     char *new = malloc (strlen (name) + 1);
  1940.     char *cp1, *cp2 = new;
  1941.     int i, ostop, found;
  1942.  
  1943.     for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
  1944.         continue;
  1945.     for (cp1 = name; *cp1; cp1++) {
  1946.         found = 0;
  1947.         for (i = 0; *(ntin + i) && i < 16; i++) {
  1948.             if (*cp1 == *(ntin + i)) {
  1949.                 found++;
  1950.                 if (i < ostop) {
  1951.                     *cp2++ = *(ntout + i);
  1952.                 }
  1953.                 break;
  1954.             }
  1955.         }
  1956.         if (!found) {
  1957.             *cp2++ = *cp1;
  1958.         }
  1959.     }
  1960.     *cp2 = '\0';
  1961.     return (new);
  1962. }
  1963.  
  1964. void
  1965. setpassive(argc, argv)
  1966.     int argc;
  1967.     char *argv[];
  1968. {
  1969.  
  1970.     passivemode = !passivemode;
  1971.     printf("Passive mode %s.\n", onoff(passivemode));
  1972.     code = passivemode;
  1973. }
  1974.  
  1975. void
  1976. setnmap(argc, argv)
  1977.     int argc;
  1978.     char *argv[];
  1979. {
  1980.     char *cp;
  1981.  
  1982.     if (argc == 1) {
  1983.         mapflag = 0;
  1984.         printf("Nmap off.\n");
  1985.         code = mapflag;
  1986.         return;
  1987.     }
  1988.     if (argc < 3 && !another(&argc, &argv, "mapout")) {
  1989.         printf("Usage: %s [mapin mapout]\n",argv[0]);
  1990.         code = -1;
  1991.         return;
  1992.     }
  1993.     mapflag = 1;
  1994.     code = 1;
  1995.     cp = strchr(altarg, ' ');
  1996.     if (proxy) {
  1997.         while(*++cp == ' ')
  1998.             continue;
  1999.         altarg = cp;
  2000.         cp = strchr(altarg, ' ');
  2001.     }
  2002.     *cp = '\0';
  2003.  
  2004.     if (mapin)
  2005.         free (mapin);
  2006.     mapin = strdup (altarg);
  2007.  
  2008.     while (*++cp == ' ')
  2009.         continue;
  2010.     if (mapout)
  2011.         free (mapout);
  2012.     mapout = strdup (cp);
  2013. }
  2014.  
  2015. static int
  2016. cp_subst (from_p, to_p, toks, tp, te, tok0, buf_p, buf_len_p)
  2017. char **from_p, **to_p;
  2018. char *tp[9], *te[9];
  2019. int toks[9];
  2020. char *tok0;
  2021. char **buf_p;
  2022. int *buf_len_p;
  2023. {
  2024.     int toknum;
  2025.     char *src;
  2026.     int src_len;
  2027.  
  2028.     if (*++(*from_p) == '0') {
  2029.         src = tok0;
  2030.         src_len = strlen (tok0);
  2031.     }
  2032.     else if (toks[toknum = **from_p - '1']) {
  2033.         src = tp[toknum];
  2034.         src_len = te[toknum] - src;
  2035.     }
  2036.     else
  2037.         return 0;
  2038.  
  2039.     if (src_len > 2) {
  2040.         /* This subst will be longer than the original, so make room
  2041.            for it.  */
  2042.         *buf_len_p += src_len - 2;
  2043.         *buf_p = realloc (*buf_p, *buf_len_p);
  2044.     }
  2045.     while (src_len--)
  2046.         *(*to_p)++ = *src++;
  2047.  
  2048.     return 1;
  2049. }
  2050.  
  2051. char *
  2052. domap(name)
  2053.     char *name;
  2054. {
  2055.     int buf_len = strlen (name) + 1;
  2056.     char *buf = malloc (buf_len);
  2057.     char *cp1 = name, *cp2 = mapin;
  2058.     char *tp[9], *te[9];
  2059.     int i, toks[9], toknum = 0, match = 1;
  2060.  
  2061.     for (i=0; i < 9; ++i) {
  2062.         toks[i] = 0;
  2063.     }
  2064.     while (match && *cp1 && *cp2) {
  2065.         switch (*cp2) {
  2066.             case '\\':
  2067.                 if (*++cp2 != *cp1) {
  2068.                     match = 0;
  2069.                 }
  2070.                 break;
  2071.             case '$':
  2072.                 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
  2073.                     if (*cp1 != *(++cp2+1)) {
  2074.                         toks[toknum = *cp2 - '1']++;
  2075.                         tp[toknum] = cp1;
  2076.                         while (*++cp1 && *(cp2+1)
  2077.                             != *cp1);
  2078.                         te[toknum] = cp1;
  2079.                     }
  2080.                     cp2++;
  2081.                     break;
  2082.                 }
  2083.                 /* FALLTHROUGH */
  2084.             default:
  2085.                 if (*cp2 != *cp1) {
  2086.                     match = 0;
  2087.                 }
  2088.                 break;
  2089.         }
  2090.         if (match && *cp1) {
  2091.             cp1++;
  2092.         }
  2093.         if (match && *cp2) {
  2094.             cp2++;
  2095.         }
  2096.     }
  2097.     if (!match && *cp1) /* last token mismatch */
  2098.     {
  2099.         toks[toknum] = 0;
  2100.     }
  2101.     cp1 = buf;
  2102.     *cp1 = '\0';
  2103.     cp2 = mapout;
  2104.     while (*cp2) {
  2105.         match = 0;
  2106.         switch (*cp2) {
  2107.             case '\\':
  2108.                 if (*(cp2 + 1)) {
  2109.                     *cp1++ = *++cp2;
  2110.                 }
  2111.                 break;
  2112.             case '[':
  2113. LOOP:
  2114.                 if (*++cp2 == '$' && isdigit(*(cp2+1)))
  2115.                     cp_subst (&cp2, &cp1,
  2116.                           toks, tp, te, name,
  2117.                           &buf, &buf_len);
  2118.                 else {
  2119.                     while (*cp2 && *cp2 != ',' &&
  2120.                         *cp2 != ']') {
  2121.                         if (*cp2 == '\\') {
  2122.                             cp2++;
  2123.                         }
  2124.                         else if (*cp2 == '$' &&
  2125.                                    isdigit(*(cp2+1)))
  2126.                             if (cp_subst (&cp2,
  2127.                                       &cp1,
  2128.                                       toks,
  2129.                                       tp, te,
  2130.                                       name,
  2131.                                       &buf,
  2132.                                       &buf_len))
  2133.                                 match = 1;
  2134.                         else if (*cp2) {
  2135.                             *cp1++ = *cp2++;
  2136.                         }
  2137.                     }
  2138.                     if (!*cp2) {
  2139.                         printf("nmap: unbalanced brackets\n");
  2140.                         return (name);
  2141.                     }
  2142.                     match = 1;
  2143.                     cp2--;
  2144.                 }
  2145.                 if (match) {
  2146.                     while (*++cp2 && *cp2 != ']') {
  2147.                           if (*cp2 == '\\' && *(cp2 + 1)) {
  2148.                             cp2++;
  2149.                           }
  2150.                     }
  2151.                     if (!*cp2) {
  2152.                         printf("nmap: unbalanced brackets\n");
  2153.                         return (name);
  2154.                     }
  2155.                     break;
  2156.                 }
  2157.                 switch (*++cp2) {
  2158.                     case ',':
  2159.                         goto LOOP;
  2160.                     case ']':
  2161.                         break;
  2162.                     default:
  2163.                         cp2--;
  2164.                         goto LOOP;
  2165.                 }
  2166.                 break;
  2167.             case '$':
  2168.                 if (isdigit(*(cp2 + 1))) {
  2169.                     if (cp_subst (&cp2, &cp1,
  2170.                               toks, tp, te, name,
  2171.                               &buf, &buf_len))
  2172.                         match = 1;
  2173.                     break;
  2174.                 }
  2175.                 /* intentional drop through */
  2176.             default:
  2177.                 *cp1++ = *cp2;
  2178.                 break;
  2179.         }
  2180.         cp2++;
  2181.     }
  2182.     *cp1 = '\0';
  2183.  
  2184.     if (! *buf)
  2185.         strcpy (buf, name);
  2186.  
  2187.     return buf;
  2188. }
  2189.  
  2190. void
  2191. setsunique(argc, argv)
  2192.     int argc;
  2193.     char *argv[];
  2194. {
  2195.  
  2196.     sunique = !sunique;
  2197.     printf("Store unique %s.\n", onoff(sunique));
  2198.     code = sunique;
  2199. }
  2200.  
  2201. void
  2202. setrunique(argc, argv)
  2203.     int argc;
  2204.     char *argv[];
  2205. {
  2206.  
  2207.     runique = !runique;
  2208.     printf("Receive unique %s.\n", onoff(runique));
  2209.     code = runique;
  2210. }
  2211.  
  2212. /* change directory to perent directory */
  2213. void
  2214. cdup(argc, argv)
  2215.     int argc;
  2216.     char *argv[];
  2217. {
  2218.  
  2219.     if (command("CDUP") == ERROR && code == 500) {
  2220.         if (verbose)
  2221.             printf("CDUP command not recognized, trying XCUP\n");
  2222.         (void) command("XCUP");
  2223.     }
  2224. }
  2225.  
  2226. /* restart transfer at specific point */
  2227. void
  2228. restart(argc, argv)
  2229.     int argc;
  2230.     char *argv[];
  2231. {
  2232.  
  2233.     if (argc != 2)
  2234.         printf("restart: offset not specified\n");
  2235.     else {
  2236.         restart_point = atol(argv[1]);
  2237.         printf("restarting at %qd. %s\n", restart_point,
  2238.             "execute get, put or append to initiate transfer");
  2239.     }
  2240. }
  2241.  
  2242. /* show remote system type */
  2243. void
  2244. syst(argc, argv)
  2245.     int argc;
  2246.     char *argv[];
  2247. {
  2248.  
  2249.     (void) command("SYST");
  2250. }
  2251.  
  2252. void
  2253. macdef(argc, argv)
  2254.     int argc;
  2255.     char *argv[];
  2256. {
  2257.     char *tmp;
  2258.     int c;
  2259.  
  2260.     if (macnum == 16) {
  2261.         printf("Limit of 16 macros have already been defined\n");
  2262.         code = -1;
  2263.         return;
  2264.     }
  2265.     if (argc < 2 && !another(&argc, &argv, "macro name")) {
  2266.         printf("Usage: %s macro_name\n",argv[0]);
  2267.         code = -1;
  2268.         return;
  2269.     }
  2270.     if (interactive) {
  2271.         printf("Enter macro line by line, terminating it with a null line\n");
  2272.     }
  2273.     (void) strncpy(macros[macnum].mac_name, argv[1], 8);
  2274.     if (macnum == 0) {
  2275.         macros[macnum].mac_start = macbuf;
  2276.     }
  2277.     else {
  2278.         macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
  2279.     }
  2280.     tmp = macros[macnum].mac_start;
  2281.     while (tmp != macbuf+4096) {
  2282.         if ((c = getchar()) == EOF) {
  2283.             printf("macdef:end of file encountered\n");
  2284.             code = -1;
  2285.             return;
  2286.         }
  2287.         if ((*tmp = c) == '\n') {
  2288.             if (tmp == macros[macnum].mac_start) {
  2289.                 macros[macnum++].mac_end = tmp;
  2290.                 code = 0;
  2291.                 return;
  2292.             }
  2293.             if (*(tmp-1) == '\0') {
  2294.                 macros[macnum++].mac_end = tmp - 1;
  2295.                 code = 0;
  2296.                 return;
  2297.             }
  2298.             *tmp = '\0';
  2299.         }
  2300.         tmp++;
  2301.     }
  2302.     while (1) {
  2303.         while ((c = getchar()) != '\n' && c != EOF)
  2304.             /* LOOP */;
  2305.         if (c == EOF || getchar() == '\n') {
  2306.             printf("Macro not defined - 4k buffer exceeded\n");
  2307.             code = -1;
  2308.             return;
  2309.         }
  2310.     }
  2311. }
  2312.  
  2313. /*
  2314.  * get size of file on remote machine
  2315.  */
  2316. void
  2317. sizecmd(argc, argv)
  2318.     int argc;
  2319.     char *argv[];
  2320. {
  2321.  
  2322.     if (argc < 2 && !another(&argc, &argv, "filename")) {
  2323.         printf("usage: %s filename\n", argv[0]);
  2324.         code = -1;
  2325.         return;
  2326.     }
  2327.     (void) command("SIZE %s", argv[1]);
  2328. }
  2329.  
  2330. /*
  2331.  * get last modification time of file on remote machine
  2332.  */
  2333. void
  2334. modtime(argc, argv)
  2335.     int argc;
  2336.     char *argv[];
  2337. {
  2338.     int overbose;
  2339.  
  2340.     if (argc < 2 && !another(&argc, &argv, "filename")) {
  2341.         printf("usage: %s filename\n", argv[0]);
  2342.         code = -1;
  2343.         return;
  2344.     }
  2345.     overbose = verbose;
  2346.     if (debug == 0)
  2347.         verbose = -1;
  2348.     if (command("MDTM %s", argv[1]) == COMPLETE) {
  2349.         int yy, mo, day, hour, min, sec;
  2350.         sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
  2351.             &day, &hour, &min, &sec);
  2352.         /* might want to print this in local time */
  2353.         printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
  2354.             mo, day, yy, hour, min, sec);
  2355.     } else
  2356.         printf("%s\n", reply_string);
  2357.     verbose = overbose;
  2358. }
  2359.  
  2360. /*
  2361.  * show status on reomte machine
  2362.  */
  2363. void
  2364. rmtstatus(argc, argv)
  2365.     int argc;
  2366.     char *argv[];
  2367. {
  2368.  
  2369.     (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
  2370. }
  2371.  
  2372. /*
  2373.  * get file if modtime is more recent than current file
  2374.  */
  2375. void
  2376. newer(argc, argv)
  2377.     int argc;
  2378.     char *argv[];
  2379. {
  2380.  
  2381.     if (getit(argc, argv, -1, "w"))
  2382.         printf("Local file \"%s\" is newer than remote file \"%s\"\n",
  2383.             argv[2], argv[1]);
  2384. }
  2385.