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