home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / inetutils-1.2-src.tgz / tar.out / fsf / inetutils / ftp / main.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  12KB  |  593 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 copyright[] =
  36. "@(#) Copyright (c) 1985, 1989, 1993, 1994\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)main.c    8.6 (Berkeley) 10/9/94";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * FTP User Program -- Command Interface.
  46.  */
  47.  
  48. #ifdef HAVE_CONFIG_H
  49. #include <config.h>
  50. #endif
  51.  
  52. /*#include <sys/ioctl.h>*/
  53. #include <sys/types.h>
  54. #include <sys/socket.h>
  55.  
  56. #include <arpa/ftp.h>
  57.  
  58. #include <ctype.h>
  59. #include <err.h>
  60. #include <netdb.h>
  61. #include <pwd.h>
  62. #include <signal.h>
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <unistd.h>
  66. #include <getopt.h>
  67. #include <version.h>
  68.  
  69. #include "ftp_var.h"
  70.  
  71. #define USAGE "Usage: %s [OPTION...] [HOST [PORT]]\n"
  72.  
  73. /* basename (argv[0]).  NetBSD, linux, & gnu libc all define it.  */
  74. extern char *__progname;
  75.  
  76. /* Print a help message describing all options to STDOUT and exit with a
  77.    status of 0.  */
  78. static void
  79. ohelp ()
  80. {
  81.   fprintf (stdout, USAGE, __progname);
  82.   puts ("\n\
  83.   -d, --debug                Turn on debugging mode\n\
  84.   -g, --no-glob              Turn off file name globbing\n\
  85.   -i, --no-prompt            Don't prompt during multiple-file transfers\n\
  86.   -n, --no-login             Don't automatically login to the remove system\n\
  87.   -t, --trace                Enable packet tracing\n\
  88.   -v, --verbose              Be verbose\n\
  89.       --help                 Give this help list\n\
  90.       --version              Print program version");
  91.   exit (0);
  92. }
  93.  
  94. /* Print a message saying to use --help to STDERR, and exit with a status of
  95.    1.  */
  96. static void
  97. try_help ()
  98. {
  99.   fprintf (stderr, "Try `%s --help' for more information.\n", __progname);
  100.   exit (1);
  101. }
  102.  
  103. /* Print a usage message to STDERR and exit with a status of 1.  */
  104. static void
  105. usage ()
  106. {
  107.   fprintf (stderr, USAGE, __progname);
  108.   try_help ();
  109. }
  110.  
  111. static struct option long_options[] =
  112. {
  113.   { "trace", no_argument, 0, 't' },
  114.   { "verbose", no_argument, 0, 'v' },
  115.   { "no-login", no_argument, 0, 'n' },
  116.   { "no-prompt", no_argument, 0, 'i' },
  117.   { "debug", no_argument, 0, 'd' },
  118.   { "no-glob", no_argument, 0, 'g' },
  119.   { "help", no_argument, 0, '&' },
  120.   { "version", no_argument, 0, 'V' },
  121.   { 0 }
  122. };
  123.  
  124. int
  125. main(argc, argv)
  126.     int argc;
  127.     char *argv[];
  128. {
  129.     int ch, top;
  130.     struct passwd *pw = NULL;
  131.     char *cp;
  132.  
  133. #ifndef HAVE___PROGNAME
  134.     extern char *__progname;
  135.     __progname = argv[0];
  136. #endif
  137.  
  138.     sp = getservbyname("ftp", "tcp");
  139.     if (sp == 0)
  140.         errx(1, "ftp/tcp: unknown service");
  141.     doglob = 1;
  142.     interactive = 1;
  143.     autologin = 1;
  144.  
  145.     while ((ch = getopt_long (argc, argv, "dgintv", long_options, 0))
  146.            != EOF)
  147.     {
  148.         switch (ch) {
  149.         case 'd':
  150.             options |= SO_DEBUG;
  151.             debug++;
  152.             break;
  153.             
  154.         case 'g':
  155.             doglob = 0;
  156.             break;
  157.  
  158.         case 'i':
  159.             interactive = 0;
  160.             break;
  161.  
  162.         case 'n':
  163.             autologin = 0;
  164.             break;
  165.  
  166.         case 't':
  167.             trace++;
  168.             break;
  169.  
  170.         case 'v':
  171.             verbose++;
  172.             break;
  173.  
  174.         case '&':
  175.             ohelp ();
  176.         case 'V':
  177.             puts (inetutils_version);
  178.             exit (0);
  179.  
  180.         case '?':
  181.             try_help ();
  182.  
  183.         default:
  184.             usage ();
  185.         }
  186.     }
  187.     argc -= optind;
  188.     argv += optind;
  189.  
  190.     fromatty = isatty(fileno(stdin));
  191.     if (fromatty)
  192.         verbose++;
  193.     cpend = 0;    /* no pending replies */
  194.     proxy = 0;    /* proxy not active */
  195.     passivemode = 0; /* passive mode not active */
  196.     crflag = 1;    /* strip c.r. on ascii gets */
  197.     sendport = -1;    /* not using ports */
  198.     /*
  199.      * Set up the home directory in case we're globbing.
  200.      */
  201.     cp = getlogin();
  202.     if (cp != NULL) {
  203.         pw = getpwnam(cp);
  204.     }
  205.     if (pw == NULL)
  206.         pw = getpwuid(getuid());
  207.     if (pw != NULL) {
  208.         char *buf = malloc (strlen (pw->pw_dir) + 1);
  209.         if (buf) {
  210.             strcpy(buf, pw->pw_dir);
  211.             home = buf;
  212.         }
  213.     }
  214.     if (argc > 0) {
  215.         char *xargv[5];
  216.         extern char *__progname;
  217.  
  218.         if (setjmp(toplevel))
  219.             exit(0);
  220.         (void) signal(SIGINT, intr);
  221.         (void) signal(SIGPIPE, lostpeer);
  222.         xargv[0] = __progname;
  223.         xargv[1] = argv[0];
  224.         xargv[2] = argv[1];
  225.         xargv[3] = argv[2];
  226.         xargv[4] = NULL;
  227.         setpeer(argc+1, xargv);
  228.     }
  229.     top = setjmp(toplevel) == 0;
  230.     if (top) {
  231.         (void) signal(SIGINT, intr);
  232.         (void) signal(SIGPIPE, lostpeer);
  233.     }
  234.     for (;;) {
  235.         cmdscanner(top);
  236.         top = 1;
  237.     }
  238. }
  239.  
  240. void
  241. intr()
  242. {
  243.  
  244.     longjmp(toplevel, 1);
  245. }
  246.  
  247. void
  248. lostpeer()
  249. {
  250.  
  251.     if (connected) {
  252.         if (cout != NULL) {
  253.             (void) shutdown(fileno(cout), 1+1);
  254.             (void) fclose(cout);
  255.             cout = NULL;
  256.         }
  257.         if (data >= 0) {
  258.             (void) shutdown(data, 1+1);
  259.             (void) close(data);
  260.             data = -1;
  261.         }
  262.         connected = 0;
  263.     }
  264.     pswitch(1);
  265.     if (connected) {
  266.         if (cout != NULL) {
  267.             (void) shutdown(fileno(cout), 1+1);
  268.             (void) fclose(cout);
  269.             cout = NULL;
  270.         }
  271.         connected = 0;
  272.     }
  273.     proxflag = 0;
  274.     pswitch(0);
  275. }
  276.  
  277. /*
  278. char *
  279. tail(filename)
  280.     char *filename;
  281. {
  282.     char *s;
  283.     
  284.     while (*filename) {
  285.         s = strrchr(filename, '/');
  286.         if (s == NULL)
  287.             break;
  288.         if (s[1])
  289.             return (s + 1);
  290.         *s = '\0';
  291.     }
  292.     return (filename);
  293. }
  294. */
  295.  
  296. /*
  297.  * Command parser.
  298.  */
  299. void
  300. cmdscanner(top)
  301.     int top;
  302. {
  303.     struct cmd *c;
  304.     int l;
  305.  
  306.     if (!top)
  307.         (void) putchar('\n');
  308.     for (;;) {
  309.         if (fromatty) {
  310.             printf("ftp> ");
  311.             (void) fflush(stdout);
  312.         }
  313.         if (fgets(line, sizeof line, stdin) == NULL)
  314.             quit(0, 0);
  315.         l = strlen(line);
  316.         if (l == 0)
  317.             break;
  318.         if (line[--l] == '\n') {
  319.             if (l == 0)
  320.                 break;
  321.             line[l] = '\0';
  322.         } else if (l == sizeof(line) - 2) {
  323.             printf("sorry, input line too long\n");
  324.             while ((l = getchar()) != '\n' && l != EOF)
  325.                 /* void */;
  326.             break;
  327.         } /* else it was a line without a newline */
  328.         makeargv();
  329.         if (margc == 0) {
  330.             continue;
  331.         }
  332.         c = getcmd(margv[0]);
  333.         if (c == (struct cmd *)-1) {
  334.             printf("?Ambiguous command\n");
  335.             continue;
  336.         }
  337.         if (c == 0) {
  338.             printf("?Invalid command\n");
  339.             continue;
  340.         }
  341.         if (c->c_conn && !connected) {
  342.             printf("Not connected.\n");
  343.             continue;
  344.         }
  345.         (*c->c_handler)(margc, margv);
  346.         if (bell && c->c_bell)
  347.             (void) putchar('\007');
  348.         if (c->c_handler != help)
  349.             break;
  350.     }
  351.     (void) signal(SIGINT, intr);
  352.     (void) signal(SIGPIPE, lostpeer);
  353. }
  354.  
  355. struct cmd *
  356. getcmd(name)
  357.     char *name;
  358. {
  359.     char *p, *q;
  360.     struct cmd *c, *found;
  361.     int nmatches, longest;
  362.  
  363.     longest = 0;
  364.     nmatches = 0;
  365.     found = 0;
  366.     for (c = cmdtab; p = c->c_name; c++) {
  367.         for (q = name; *q == *p++; q++)
  368.             if (*q == 0)        /* exact match? */
  369.                 return (c);
  370.         if (!*q) {            /* the name was a prefix */
  371.             if (q - name > longest) {
  372.                 longest = q - name;
  373.                 nmatches = 1;
  374.                 found = c;
  375.             } else if (q - name == longest)
  376.                 nmatches++;
  377.         }
  378.     }
  379.     if (nmatches > 1)
  380.         return ((struct cmd *)-1);
  381.     return (found);
  382. }
  383.  
  384. /*
  385.  * Slice a string up into argc/argv.
  386.  */
  387.  
  388. int slrflag;
  389.  
  390. void
  391. makeargv()
  392. {
  393.     char **argp;
  394.  
  395.     margc = 0;
  396.     argp = margv;
  397.     stringbase = line;        /* scan from first of buffer */
  398.     argbase = argbuf;        /* store from first of buffer */
  399.     slrflag = 0;
  400.     while (*argp++ = slurpstring())
  401.         margc++;
  402. }
  403.  
  404. /*
  405.  * Parse string into argbuf;
  406.  * implemented with FSM to
  407.  * handle quoting and strings
  408.  */
  409. char *
  410. slurpstring()
  411. {
  412.     int got_one = 0;
  413.     char *sb = stringbase;
  414.     char *ap = argbase;
  415.     char *tmp = argbase;        /* will return this if token found */
  416.  
  417.     if (*sb == '!' || *sb == '$') {    /* recognize ! as a token for shell */
  418.         switch (slrflag) {    /* and $ as token for macro invoke */
  419.             case 0:
  420.                 slrflag++;
  421.                 stringbase++;
  422.                 return ((*sb == '!') ? "!" : "$");
  423.                 /* NOTREACHED */
  424.             case 1:
  425.                 slrflag++;
  426.                 altarg = stringbase;
  427.                 break;
  428.             default:
  429.                 break;
  430.         }
  431.     }
  432.  
  433. S0:
  434.     switch (*sb) {
  435.  
  436.     case '\0':
  437.         goto OUT;
  438.  
  439.     case ' ':
  440.     case '\t':
  441.         sb++; goto S0;
  442.  
  443.     default:
  444.         switch (slrflag) {
  445.             case 0:
  446.                 slrflag++;
  447.                 break;
  448.             case 1:
  449.                 slrflag++;
  450.                 altarg = sb;
  451.                 break;
  452.             default:
  453.                 break;
  454.         }
  455.         goto S1;
  456.     }
  457.  
  458. S1:
  459.     switch (*sb) {
  460.  
  461.     case ' ':
  462.     case '\t':
  463.     case '\0':
  464.         goto OUT;    /* end of token */
  465.  
  466.     case '\\':
  467.         sb++; goto S2;    /* slurp next character */
  468.  
  469.     case '"':
  470.         sb++; goto S3;    /* slurp quoted string */
  471.  
  472.     default:
  473.         *ap++ = *sb++;    /* add character to token */
  474.         got_one = 1;
  475.         goto S1;
  476.     }
  477.  
  478. S2:
  479.     switch (*sb) {
  480.  
  481.     case '\0':
  482.         goto OUT;
  483.  
  484.     default:
  485.         *ap++ = *sb++;
  486.         got_one = 1;
  487.         goto S1;
  488.     }
  489.  
  490. S3:
  491.     switch (*sb) {
  492.  
  493.     case '\0':
  494.         goto OUT;
  495.  
  496.     case '"':
  497.         sb++; goto S1;
  498.  
  499.     default:
  500.         *ap++ = *sb++;
  501.         got_one = 1;
  502.         goto S3;
  503.     }
  504.  
  505. OUT:
  506.     if (got_one)
  507.         *ap++ = '\0';
  508.     argbase = ap;            /* update storage pointer */
  509.     stringbase = sb;        /* update scan pointer */
  510.     if (got_one) {
  511.         return (tmp);
  512.     }
  513.     switch (slrflag) {
  514.         case 0:
  515.             slrflag++;
  516.             break;
  517.         case 1:
  518.             slrflag++;
  519.             altarg = (char *) 0;
  520.             break;
  521.         default:
  522.             break;
  523.     }
  524.     return ((char *)0);
  525. }
  526.  
  527. #define HELPINDENT ((int) sizeof ("directory"))
  528.  
  529. /*
  530.  * Help command.
  531.  * Call each command handler with argc == 0 and argv[0] == name.
  532.  */
  533. void
  534. help(argc, argv)
  535.     int argc;
  536.     char *argv[];
  537. {
  538.     struct cmd *c;
  539.  
  540.     if (argc == 1) {
  541.         int i, j, w, k;
  542.         int columns, width = 0, lines;
  543.  
  544.         printf("Commands may be abbreviated.  Commands are:\n\n");
  545.         for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
  546.             int len = strlen(c->c_name);
  547.  
  548.             if (len > width)
  549.                 width = len;
  550.         }
  551.         width = (width + 8) &~ 7;
  552.         columns = 80 / width;
  553.         if (columns == 0)
  554.             columns = 1;
  555.         lines = (NCMDS + columns - 1) / columns;
  556.         for (i = 0; i < lines; i++) {
  557.             for (j = 0; j < columns; j++) {
  558.                 c = cmdtab + j * lines + i;
  559.                 if (c->c_name && (!proxy || c->c_proxy)) {
  560.                     printf("%s", c->c_name);
  561.                 }
  562.                 else if (c->c_name) {
  563.                     for (k=0; k < strlen(c->c_name); k++) {
  564.                         (void) putchar(' ');
  565.                     }
  566.                 }
  567.                 if (c + lines >= &cmdtab[NCMDS]) {
  568.                     printf("\n");
  569.                     break;
  570.                 }
  571.                 w = strlen(c->c_name);
  572.                 while (w < width) {
  573.                     w = (w + 8) &~ 7;
  574.                     (void) putchar('\t');
  575.                 }
  576.             }
  577.         }
  578.         return;
  579.     }
  580.     while (--argc > 0) {
  581.         char *arg;
  582.         arg = *++argv;
  583.         c = getcmd(arg);
  584.         if (c == (struct cmd *)-1)
  585.             printf("?Ambiguous help command %s\n", arg);
  586.         else if (c == (struct cmd *)0)
  587.             printf("?Invalid help command %s\n", arg);
  588.         else
  589.             printf("%-*s\t%s\n", HELPINDENT,
  590.                 c->c_name, c->c_help);
  591.     }
  592. }
  593.