home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / ftp / cmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-23  |  39.9 KB  |  2,160 lines

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