home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume35 / ncftp / part02 / main.c < prev   
Encoding:
C/C++ Source or Header  |  1993-01-25  |  18.6 KB  |  896 lines

  1. /* main.c */
  2.  
  3. #define _main_c_
  4.  
  5. #include "sys.h"
  6. #include <sys/types.h>
  7. #include <sys/param.h>
  8. #include <sys/socket.h>
  9. #include <sys/stat.h>
  10. #include <sys/time.h>
  11. #include <arpa/ftp.h>
  12. #include <setjmp.h>
  13. #include <signal.h>
  14. #include <string.h>
  15. #include <errno.h>
  16. #include <ctype.h>
  17. #include <netdb.h>
  18. #include <pwd.h>
  19.  
  20. #ifdef SYSLOG
  21. #    include <syslog.h>
  22. #endif
  23.  
  24. #ifndef NO_UNISTDH
  25. #    include <unistd.h>
  26. #endif
  27.  
  28. #ifdef CURSES
  29. #    undef HZ        /* Collides with HaZeltine ! */
  30. #    include <curses.h>
  31. #endif    /* CURSES */
  32.  
  33. #include "ftpdefs.h"
  34. #include "defaults.h"
  35. #include "cmds.h"
  36. #include "main.h"
  37. #include "ftp.h"
  38. #include "ftprc.h"
  39. #include "copyright.h"
  40.  
  41. /* main.c globals */
  42. int                    slrflag;
  43. int                    fromatty;            /* input is from a terminal */
  44. char                *altarg;            /* argv[1] with no shell-like preprocessing  */
  45. struct    servent        *sp;                /* service spec for tcp/ftp */
  46. jmp_buf                toplevel;            /* non-local goto stuff for cmd scanner */
  47. char                *line;                /* input line buffer */
  48. char                *stringbase;        /* current scan point in line buffer */
  49. char                *argbuf;            /* argument storage buffer */
  50. char                *argbase;            /* current storage point in arg buffer */
  51. int                    margc;                /* count of arguments on input line */
  52. char                *margv[20];            /* args parsed from input line */
  53. struct userinfo        uinfo;                /* a copy of their pwent really */
  54. int                    ansi_escapes;        /* for fancy graphics */
  55. int                    ignore_rc;            /* are we supposed to ignore the netrc */
  56. string                progname;            /* simple filename */
  57. string                prompt, prompt2;    /* shell prompt string */
  58. string                anon_password;        /* most likely your email address */
  59. string                pager;                /* program to browse text files */
  60. string                version = FTP_VERSION;
  61. long                eventnumber;        /* number of commands we've done */
  62. FILE                *logf = NULL;        /* log user activity */
  63. string                logfname;            /* name of the logfile */
  64. long                logsize = 4096L;    /* max log size. 0 == no limit */
  65. int                    percent_flags;        /* "%" in prompt string? */
  66. int                    at_flags;            /* "@" in prompt string? */
  67. string                 mail_path;            /* your mailbox */
  68. int                    newmail;            /* how many new letters you have */
  69. time_t                mbox_time;            /* last modified time of mbox */
  70.  
  71. char                *tcap_normal = "\033[0m";    /* Default ANSI escapes */
  72. char                *tcap_boldface = "\033[1m";
  73. char                *tcap_underline = "\033[4m";
  74. char                *tcap_reverse = "\033[7m";
  75.  
  76. #ifdef CURSES
  77. static char            tcbuf[2048];
  78. #endif
  79.  
  80. /* main.c externs */
  81. extern int            debug, verbose, mprompt;
  82. extern int            options, cpend, data, connected;
  83. extern int            curtype, macnum;
  84. extern FILE            *cout;
  85. extern struct cmd    cmdtab[];
  86. extern str32        curtypename;
  87. extern char            *macbuf;
  88. extern char            *reply_string;
  89. extern string        hostname, cwd, lcwd;
  90. extern int            Optind;
  91. extern char            *Optarg;
  92.  
  93. main(int argc, char **argv)
  94. {
  95.     register char        *cp;
  96.     int                    top, opt, openopts = 0;
  97.     string                tmp, oline;    
  98.  
  99.     if ((cp = rindex(argv[0], '/'))) cp++;
  100.     else cp = argv[0];
  101.     (void) Strncpy(progname, cp);
  102.     
  103.     sp = getservbyname("ftp", "tcp");
  104.     if (sp == 0) fatal("ftp/tcp: unknown service");
  105.  
  106.     if (init_arrays())            /* Reserve large blocks of memory now */
  107.         fatal("could not reserve large amounts of memory.");
  108.  
  109.     /*
  110.      * Set up defaults for FTP.
  111.      */
  112.     mprompt = dMPROMPT;
  113.     verbose = dVERBOSE;
  114.     debug = dDEBUG;
  115.  
  116.     (void) Strncpy(curtypename, dTYPESTR);
  117.     curtype = dTYPE;
  118.     (void) Strncpy(prompt, dPROMPT);
  119.     
  120.     /*    Setup our pager variable, before we run through the rc,
  121.         which may change it. */
  122.     set_pager(getenv("PAGER"), 0);
  123. #ifdef CURSES
  124.     ansi_escapes = 1;
  125. #else
  126.     ansi_escapes = 0;
  127.     if ((cp = getenv("TERM")) != NULL) {
  128.         if ((*cp == 'v' && cp[1] == 't')        /* vt100, vt102, ... */
  129.             || (strcmp(cp, "xterm") == 0))
  130.             ansi_escapes = 1;
  131.     }
  132. #endif
  133.     (void) getuserinfo();
  134.     newmail = 0;
  135.     (void) time(&mbox_time);
  136.     (void) Strncpy(anon_password, uinfo.username);
  137.     if (getlocalhostname(uinfo.hostname, sizeof(uinfo.hostname)) == 0) {
  138.         (void) Strncat(anon_password, "@");
  139.         (void) Strncat(anon_password, uinfo.hostname);
  140.     }
  141. #if dLOGGING
  142.     (void) sprintf(logfname, "%s/%s", uinfo.homedir, dLOGNAME);
  143. #else
  144.     *logfname = 0;
  145. #endif
  146.     (void) get_cwd(lcwd, (int) sizeof(lcwd));
  147.  
  148. #ifdef SYSLOG
  149. #    ifdef LOG_LOCAL3
  150.     openlog ("NcFTP", LOG_PID, LOG_LOCAL3);
  151. #    else
  152.     openlog ("NcFTP", LOG_PID);
  153. #    endif
  154. #endif                /* SYSLOG */
  155.  
  156.  
  157.     ignore_rc = 0;
  158.     (void) strcpy(oline, "open ");
  159.     while ((opt = Getopt(argc, argv, "DVINRHaiup:rd:g:")) >= 0) {
  160.         switch(opt) {
  161.             case 'a':
  162.             case 'i':
  163.             case 'u':
  164.             case 'r':
  165.                 (void) sprintf(tmp, "-%c ", opt);
  166.                 goto cattmp;
  167.  
  168.             case 'p':
  169.             case 'd':
  170.             case 'g':
  171.                 (void) sprintf(tmp, "-%c %s ", opt, Optarg);
  172.             cattmp:
  173.                 (void) strcat(oline, tmp);
  174.                 openopts++;
  175.                 break;
  176.  
  177.             case 'D':
  178.                 /* options |= SO_DEBUG; done below... */
  179.                 debug++;
  180.                 break;
  181.             
  182.             case 'V':
  183.                 verbose++;
  184.                 break;
  185.  
  186.             case 'I':
  187.                 mprompt = !mprompt;
  188.                 break;
  189.  
  190.             case 'N':
  191.                 ignore_rc = !ignore_rc;
  192.                 break;
  193.  
  194.             case 'H':
  195.                 show_version(0, NULL);
  196.                 exit (0);
  197.  
  198.             default:
  199.             usage:
  200.                 (void) fprintf(stderr, "Usage: %s [program options] [[open options] site.to.open[:path]]\n\
  201. Program Options:\n\
  202.     -D     : Increase debug level.\n\
  203.     -H     : Show version and compilation information.\n\
  204.     -I     : Toggle interactive (mprompt) mode.\n\
  205.     -N     : Toggle reading of the .netrc/.ncftprc.\n\
  206.     -V     : Increase verbosity.\n\
  207. Open Options:\n\
  208.     -a     : Open anonymously (this is the default).\n\
  209.     -u     : Open, specify user/password.\n\
  210.     -i     : Ignore machine entry in your .netrc.\n\
  211.     -p N   : Use port #N for connection.\n\
  212.     -r     : \"Redial\" until connected.\n\
  213.     -d N   : Redial, pausing N seconds between tries.\n\
  214.     -g N   : Redial, giving up after N tries.\n\
  215.     :path  : Open site, retrieve file \"path,\" then exit.\n\
  216. Examples:\n\
  217.     %s ftp.unl.edu:/pub/README\n\
  218.     %s -V -u ftp.unl.edu\n\
  219.     %s -D -r -d 120 -g 10 ftp.unl.edu\n", progname, progname, progname, progname);
  220.             exit(1);
  221.         }
  222.     }
  223.  
  224.     cp = argv[Optind];  /* the site to open. */
  225.     if (cp == NULL) {
  226.         if (openopts)
  227.             goto usage;
  228.     } else
  229.         (void) strcat(oline, cp);
  230.  
  231.     if (ignore_rc == 0)
  232.         (void) thrash_rc();
  233.  
  234.     (void) fix_options();    /* adjust "options" according to "debug"  */
  235.     
  236.     fromatty = isatty(fileno(stdin));
  237.     cpend = 0;  /* no pending replies */
  238.     
  239.     if (*logfname)
  240.         logf = fopen (logfname, "a");
  241.  
  242.     eventnumber = 0L;
  243.     /* The user specified a host on the command line.  Open it now... */
  244.     if (argc > 1 && cp) {
  245.         if (setjmp(toplevel))
  246.             exit(0);
  247.         (void) signal(SIGINT, intr);
  248.         (void) signal(SIGPIPE, lostpeer);
  249.         (void) strcpy(line, oline);
  250.         makeargv();
  251.         (void) setpeer(margc, margv);
  252.     }
  253.  
  254.     (void) init_prompt();
  255.  
  256.     eventnumber = 1L;
  257.     if (ansi_escapes) {
  258. #ifndef CURSES
  259.         (void) printf("%s%s Ready.%s\n", 
  260.                 tcap_boldface, FTP_VERSION, tcap_normal);
  261. #else
  262.         string vis;
  263.         (void) sprintf(vis, "%s%s Ready.%s\n", 
  264.                 tcap_boldface, FTP_VERSION, tcap_normal);
  265.         tcap_put(vis);
  266. #endif /* !CURSES */
  267.     }
  268.     else
  269.         (void) printf("%s Ready.\n", FTP_VERSION);
  270.     top = setjmp(toplevel) == 0;
  271.     if (top) {
  272.         (void) signal(SIGINT, intr);
  273.         (void) signal(SIGPIPE, lostpeer);
  274.     }
  275.     for (;;) {
  276.         (void) cmdscanner(top);
  277.         top = 1;
  278.     }
  279. }    /* main */
  280.  
  281.  
  282.  
  283. /*ARGSUSED*/
  284. void intr(int unused)
  285. {
  286.     (void) longjmp(toplevel, 1);
  287. }    /* intr */
  288.  
  289.  
  290.  
  291. int getuserinfo(void)
  292. {
  293.     register char            *cp;
  294.     struct passwd            *pw = NULL;
  295.     string                    str;
  296.     extern char                *home;    /* for glob.c */
  297.     
  298.     cp = getlogin();
  299.     if (cp != NULL)
  300.         pw = getpwnam(cp);
  301.     if (pw == NULL)
  302.         pw = getpwuid(getuid());
  303.     if (pw != NULL) {
  304.         (void) Strncpy(uinfo.username, pw->pw_name);
  305.         (void) Strncpy(uinfo.shell, pw->pw_shell);
  306.         (void) Strncpy(uinfo.homedir, pw->pw_dir);
  307.         uinfo.uid = pw->pw_uid;
  308.         home = uinfo.homedir;    /* for glob.c */
  309.         if (((cp = getenv("MAIL")) == NULL) && ((cp = getenv("mail")) == NULL)) {
  310.             (void) sprintf(str, "/usr/spool/mail/%s", uinfo.username);
  311.             cp = str;
  312.         }
  313.         /*    mbox variable may be like MAIL=(28 /usr/mail/me /usr/mail/you),
  314.             so try to find the first mail path.  */
  315.         while (*cp != '/')
  316.             cp++;
  317.         (void) Strncpy(mail_path, cp);
  318.         if ((cp = index(mail_path, ' ')) != NULL)
  319.             *cp = '\0';
  320.         return (0);
  321.     } else {
  322.         (void) Strncpy(uinfo.username, "unknown");
  323.         (void) Strncpy(uinfo.shell, "/bin/sh");
  324.         (void) Strncpy(uinfo.homedir, ".");    /* current directory */
  325.         uinfo.uid = 999;
  326.         return (-1);
  327.     }
  328. }    /* getuserinfo */
  329.  
  330.  
  331.  
  332.  
  333. int init_arrays(void)
  334. {
  335.     if ((macbuf = (char *) malloc((size_t)(MACBUFLEN))) == NULL)
  336.         goto barf;
  337.     if ((line = (char *) malloc((size_t)(CMDLINELEN))) == NULL)
  338.         goto barf;
  339.     if ((argbuf = (char *) malloc((size_t)(CMDLINELEN))) == NULL)
  340.         goto barf;
  341.     if ((reply_string = (char *) malloc((size_t)(RECEIVEDLINELEN))) == NULL)
  342.         goto barf;
  343.     
  344.     *macbuf = '\0';
  345.     init_transfer_buffer();
  346.     return (0);
  347. barf:
  348.     return (-1);
  349. }    /* init_arrays */
  350.  
  351.  
  352.  
  353. #ifndef BUFSIZ
  354. #define BUFSIZ 512
  355. #endif
  356.  
  357. void init_transfer_buffer(void)
  358. {
  359.     extern char *xferbuf;
  360.     extern size_t xferbufsize;
  361.     
  362.     /* Make sure we use a multiple of BUFSIZ for efficiency. */
  363.     xferbufsize = (MAX_XFER_BUFSIZE / BUFSIZ) * BUFSIZ;
  364.     while (1) {
  365.         xferbuf = (char *) malloc (xferbufsize);
  366.         if (xferbuf != NULL || xferbufsize < 1024)
  367.             break;
  368.         xferbufsize >>= 2;
  369.     }
  370.     
  371.     if (xferbuf != NULL) return;
  372.     fatal("out of memory for transfer buffer.");
  373. }    /* init_transfer_buffer */
  374.  
  375.  
  376.  
  377.  
  378. void init_prompt(void)
  379. {
  380.     register char *cp;
  381.     
  382.     percent_flags = at_flags = 0;
  383.     for (cp = prompt; *cp; cp++) {
  384.         if (*cp == '%') percent_flags = 1;
  385.         else if (*cp == '@') at_flags = 1;
  386.     }
  387. }    /* init_prompt */
  388.  
  389.  
  390.  
  391. /*ARGSUSED*/
  392. void lostpeer(int unused)
  393. {
  394.     if (connected) {
  395.         close_streams(1);
  396.         if (data >= 0) {
  397.             (void) shutdown(data, 1+1);
  398.             (void) close(data);
  399.             data = -1;
  400.         }
  401.         connected = 0;
  402.     }
  403.     if (connected) {
  404.         close_streams(1);
  405.         connected = 0;
  406.     }
  407.     hostname[0] = cwd[0] = 0;
  408.     macnum = 0;
  409. }    /* lostpeer */
  410.  
  411.  
  412.  
  413. /*
  414.  * Command parser.
  415.  */
  416. void cmdscanner(int top)
  417. {
  418.     register struct cmd *c;
  419. #ifdef CURSES
  420.     string vis, *vp;
  421. #endif
  422.  
  423.     if (!top)
  424.         (void) putchar('\n');
  425.     for (;;) {
  426.         if (fromatty) {
  427. #ifndef CURSES
  428.             (void) printf(strprompt());
  429. #else
  430.             (void) Strncpy(vis, (strprompt()));
  431.             tcap_put(vis);
  432. #endif /* !CURSES */
  433.             (void) fflush(stdout);
  434.         }
  435.         if (Gets(line, (size_t)CMDLINELEN) == 0) {
  436.             if (feof(stdin) || ferror(stdin))
  437.                 (void) quit(0, NULL);    /* control-d */
  438.             break;
  439.         }
  440.         if (line[0] == 0)    /* blank line */
  441.             break;
  442.         eventnumber++;
  443.         if (debug > 1)
  444.             (void) printf("---> \"%s\"\n", line);
  445.         (void) makeargv();
  446.         if (margc == 0) {
  447.             continue;    /* blank line... */
  448.         }
  449.         c = getcmd(margv[0]);
  450.         if (c == (struct cmd *) -1) {
  451.             (void) printf("?Ambiguous command\n");
  452.             continue;
  453.         }
  454.         if (c == 0) {
  455.             if (!implicit_cd(margv[0]))
  456.                 (void) printf("?Invalid command\n");
  457.             continue;
  458.         }
  459.         if (c->c_conn && !connected) {
  460.             (void) printf ("Not connected.\n");
  461.             continue;
  462.         }
  463.         (*c->c_handler)(margc, margv);
  464.         if (c->c_handler != help)
  465.             break;
  466.     }
  467.     (void) signal(SIGINT, intr);
  468.     (void) signal(SIGPIPE, lostpeer);
  469. }    /* cmdscanner */
  470.  
  471.  
  472.  
  473.  
  474. char *strprompt(void)
  475. {
  476.     time_t                    tyme;
  477.     char                    eventstr[8];
  478.     register char            *p, *q;
  479.     string                    str;
  480. #ifdef CURSES
  481.     static int                 virgin = 0;
  482.  
  483.     if (!virgin++ && ansi_escapes)
  484.         termcap_init();
  485. #endif /* CURSES */
  486.  
  487.  
  488.     if (at_flags == 0 && percent_flags == 0)
  489.         return (prompt);    /* But don't overwrite it! */
  490.  
  491.     if (at_flags) {
  492.         for (p = prompt, q = prompt2, *q = 0; (*p); p++)
  493.             if (*p == '@') switch (islower(*p) ? (toupper(*++p)) : (*++p)) {
  494.                 case '\0':
  495.                     --p;
  496.                     break;
  497.                 case 'M':
  498.                     if (CheckNewMail() > 0)
  499.                         q = Strpcpy(q, "(Mail) ");
  500.                     break;
  501.                 case 'N':
  502.                     q = Strpcpy(q, "\n");
  503.                     break;
  504.                 case 'P':    /* reset to no bold, no uline, no inverse, etc. */
  505.                     if (ansi_escapes)
  506.                         q = Strpcpy(q, tcap_normal);
  507.                     break;
  508.                 case 'B':    /* toggle boldface */
  509.                     if (ansi_escapes)
  510.                         q = Strpcpy(q, tcap_boldface);
  511.                     break;
  512.                 case 'U':    /* toggle underline */
  513.                     if (ansi_escapes)
  514.                         q = Strpcpy(q, tcap_underline);
  515.                     break;
  516.                 case 'R':
  517.                 case 'I':    /* toggle inverse (reverse) video */
  518.                     if (ansi_escapes)
  519.                         q = Strpcpy(q, tcap_reverse);
  520.                     break;
  521.                 case 'D':    /* insert current directory */
  522.                     if (cwd != NULL)
  523.                         q = Strpcpy(q, cwd);
  524.                     break;
  525.                 case 'H':    /* insert name of connected host */
  526.                     if (hostname != NULL)
  527.                         q = Strpcpy(q, hostname);
  528.                     break;
  529.                 case '!':
  530.                 case 'E':    /* insert event number */
  531.                     (void) sprintf(eventstr, "%ld", eventnumber);
  532.                     q = Strpcpy(q, eventstr);
  533.                     break;
  534.                 default:
  535.                     *q++ = *p;    /* just copy it; unknown switch */
  536.             } else
  537.                 *q++ = *p;
  538.         *q = '\0';
  539.     } else 
  540.         (void) strcpy(prompt2, prompt);
  541.     
  542.     if (percent_flags) {
  543.         /*    only strftime if the user requested it (with a %something),
  544.             otherwise don't waste time doing nothing. */
  545.         (void) time(&tyme);
  546.         (void) Strncpy(str, prompt2);
  547.         (void) strftime(prompt2, sizeof(str), str, localtime(&tyme));
  548.     }        
  549.     return (prompt2);
  550. }    /* strprompt */
  551.  
  552.  
  553.  
  554. char *Strpcpy(char *dst, char *src)
  555. {
  556.     while (*dst++ = *src++)
  557.         ;
  558.     return (--dst);    /* return current value of dst, NOT original value! */
  559. }    /* Strpcpy */
  560.  
  561.  
  562.  
  563.  
  564. struct cmd *getcmd(char *name)
  565. {
  566.     register char *p, *q;
  567.     register struct cmd *c, *found;
  568.     register int nmatches, longest;
  569.  
  570.     if (name == NULL)
  571.         return (NULL);
  572.     longest = 0;
  573.     nmatches = 0;
  574.     found = 0;
  575.     for (c = cmdtab; p = c->c_name; c++) {
  576.         for (q = name; *q == *p++; q++)
  577.             if (*q == 0)        /* exact match? */
  578.                 return (c);
  579.         if (!*q) {            /* the name was a prefix */
  580.             if (q - name > longest) {
  581.                 longest = q - name;
  582.                 nmatches = 1;
  583.                 found = c;
  584.             } else if (q - name == longest)
  585.                 nmatches++;
  586.         }
  587.     }
  588.     if (nmatches > 1)
  589.         return ((struct cmd *)-1);
  590.     return (found);
  591. }    /* getcmd */
  592.  
  593.  
  594.  
  595.  
  596. /*
  597.  * Slice a string up into argc/argv.
  598.  */
  599.  
  600. void makeargv(void)
  601. {
  602.     char **argp;
  603.  
  604.     margc = 0;
  605.     argp = margv;
  606.     stringbase = line;        /* scan from first of buffer */
  607.     argbase = argbuf;        /* store from first of buffer */
  608.     slrflag = 0;
  609.     while (*argp++ = slurpstring())
  610.         margc++;
  611. }    /* makeargv */
  612.  
  613.  
  614.  
  615.  
  616. /*
  617.  * Parse string into argbuf;
  618.  * implemented with FSM to
  619.  * handle quoting and strings
  620.  */
  621. char *slurpstring(void)
  622. {
  623.     int got_one = 0;
  624.     register char *sb = stringbase;
  625.     register char *ap = argbase;
  626.     char *tmp = argbase;        /* will return this if token found */
  627.  
  628.     if (*sb == '!' || *sb == '$') {    /* recognize ! as a token for shell */
  629.         switch (slrflag) {    /* and $ as token for macro invoke */
  630.             case 0:
  631.                 slrflag++;
  632.                 stringbase++;
  633.                 return ((*sb == '!') ? "!" : "$");
  634.                 /* NOTREACHED */
  635.             case 1:
  636.                 slrflag++;
  637.                 altarg = stringbase;
  638.                 break;
  639.             default:
  640.                 break;
  641.         }
  642.     }
  643.  
  644. S0:
  645.     switch (*sb) {
  646.  
  647.     case '\0':
  648.         goto OUT;
  649.  
  650.     case ' ':
  651.     case '\t':
  652.     case '\n':
  653.     case '=':
  654.         sb++; goto S0;
  655.  
  656.     default:
  657.         switch (slrflag) {
  658.             case 0:
  659.                 slrflag++;
  660.                 break;
  661.             case 1:
  662.                 slrflag++;
  663.                 altarg = sb;
  664.                 break;
  665.             default:
  666.                 break;
  667.         }
  668.         goto S1;
  669.     }
  670.  
  671. S1:
  672.     switch (*sb) {
  673.  
  674.     case ' ':
  675.     case '\t':
  676.     case '\n':
  677.     case '=':
  678.     case '\0':
  679.         goto OUT;    /* end of token */
  680.  
  681.     case '\\':
  682.         sb++; goto S2;    /* slurp next character */
  683.  
  684.     case '"':
  685.         sb++; goto S3;    /* slurp quoted string */
  686.  
  687.     default:
  688.         *ap++ = *sb++;    /* add character to token */
  689.         got_one = 1;
  690.         goto S1;
  691.     }
  692.  
  693. S2:
  694.     switch (*sb) {
  695.  
  696.     case '\0':
  697.         goto OUT;
  698.  
  699.     default:
  700.         *ap++ = *sb++;
  701.         got_one = 1;
  702.         goto S1;
  703.     }
  704.  
  705. S3:
  706.     switch (*sb) {
  707.  
  708.     case '\0':
  709.         goto OUT;
  710.  
  711.     case '"':
  712.         sb++; goto S1;
  713.  
  714.     default:
  715.         *ap++ = *sb++;
  716.         got_one = 1;
  717.         goto S3;
  718.     }
  719.  
  720. OUT:
  721.     if (got_one)
  722.         *ap++ = '\0';
  723.     argbase = ap;            /* update storage pointer */
  724.     stringbase = sb;        /* update scan pointer */
  725.     if (got_one) {
  726.         return(tmp);
  727.     }
  728.     switch (slrflag) {
  729.         case 0:
  730.             slrflag++;
  731.             break;
  732.         case 1:
  733.             slrflag++;
  734.             altarg = (char *) 0;
  735.             break;
  736.         default:
  737.             break;
  738.     }
  739.     return((char *)0);
  740. }    /* slurpstring */
  741.  
  742.  
  743.  
  744.  
  745. #define HELPINDENT (sizeof ("directory"))
  746.  
  747. /*
  748.  * Help command.
  749.  * Call each command handler with argc == 0 and argv[0] == name.
  750.  */
  751. help(int argc, char **argv)
  752. {
  753.     register struct cmd        *c;
  754.     int                        i, showall = 0;
  755.     char                    *arg;
  756.  
  757.     if (argc == 2)
  758.         showall = strcmp(argv[1], "all") == 0;
  759.     if (argc == 1 || showall)  {
  760.         (void) printf("Commands may be abbreviated.  'help all' shows aliases,\ninvisible and unsupported commands.  'help <command>' \ngives a brief description of <command>.  Commands are:\n");
  761.         for (c = cmdtab, i=0; c->c_name != NULL; c++) {
  762.             if (c->c_hidden && !showall) continue;
  763.             (void) printf("%-13s", c->c_name);
  764.             if (++i == 6) {
  765.                 i = 0;
  766.                 putchar('\n');
  767.             }
  768.         }
  769.         if (i < 6)
  770.             putchar('\n');
  771.     } else while (--argc > 0) {
  772.         arg = *++argv;
  773.         c = getcmd(arg);
  774.         if (c == (struct cmd *)-1)
  775.             (void) printf("?Ambiguous help command %s\n", arg);
  776.         else if (c == (struct cmd *)0)
  777.             (void) printf("?Invalid help command %s\n", arg);
  778.         else
  779.             (void) printf("%-*s\t%s\n", HELPINDENT,
  780.                 c->c_name, c->c_help);
  781.     }
  782. }    /* help */
  783.  
  784.  
  785. /*
  786.  * If the user wants to, s/he can specify the maximum size of the log
  787.  * file, so it doesn't waste too much disk space.  If the log is too
  788.  * fat, trim the older lines (at the top) until we're under the limit.
  789.  */
  790. void trim_log(void)
  791. {
  792.     FILE                *new, *old;
  793.     struct stat            st;
  794.     long                fat;
  795.     string                tmplogname, str;
  796.  
  797.     if (logsize <= 0 || *logfname == 0 || stat(logfname, &st) ||
  798.         (old = fopen(logfname, "r")) == NULL)
  799.         return;    /* never trim, or no log */
  800.     fat = st.st_size - logsize;
  801.     if (fat <= 0L) return;    /* log too small yet */
  802.     while (fat > 0L) {
  803.         if (FGets(str, old) == NULL) return;
  804.         fat -= (long) strlen(str);
  805.     }
  806.     /* skip lines until a new site was opened */
  807.     while (1) {
  808.         if (FGets(str, old) == NULL) {
  809.             (void) fclose(old);
  810.             (void) unlink(logfname);
  811.             return;    /* nothing left, start anew */
  812.         }
  813.         if (*str != '\t') break;
  814.     }
  815.     
  816.     /* copy the remaining lines in "old" to "new" */
  817.     (void) Strncpy(tmplogname, logfname);
  818.     tmplogname[strlen(tmplogname) - 1] = 'T';
  819.     if ((new = fopen(tmplogname, "w")) == NULL) {
  820.         (void) Perror(tmplogname);
  821.         return;
  822.     }
  823.     (void) fputs(str, new);
  824.     while (FGets(str, old))
  825.         (void) fputs(str, new);
  826.     (void) fclose(old); (void) fclose(new);
  827.     if (unlink(logfname) < 0)
  828.         Perror(logfname);
  829.     if (rename(tmplogname, logfname) < 0)
  830.         Perror(tmplogname);
  831. }    /* trim_log */
  832.  
  833.  
  834.  
  835.  
  836. int CheckNewMail(void)
  837. {
  838.     struct stat stbuf;
  839.  
  840.     if (*mail_path == '\0') return 0;
  841.     if (stat(mail_path, &stbuf) < 0) {    /* cant find mail_path so we'll */
  842.         *mail_path = '\0';                /* never check it again */
  843.         return 0;
  844.     }
  845.  
  846.     if (stbuf.st_mtime > mbox_time) {
  847.         newmail++;
  848.         (void) printf("%s\n", NEWMAILMESSAGE);
  849.         (void) time(&mbox_time);                /* only notify once. */
  850.     }
  851.     
  852.     return newmail;
  853. }    /* CheckNewMail */
  854.  
  855.  
  856. #ifdef CURSES
  857. void termcap_init(void)
  858. {
  859.     static char area[1024];
  860.     static char *s = area;
  861.     char *tgetstr(char *, char **);
  862.     char *term;
  863.  
  864.     if (tgetent(tcbuf,(term = getenv("TERM"))) != 1) {
  865.         (void) fprintf(stderr,"Can't get termcap entry for terminal [%s]\n", term);
  866.     } else {
  867.         if (!(tcap_normal = tgetstr("se", &s)))
  868.             tcap_normal = "";
  869.         if (!(tcap_boldface = tgetstr("md", &s)))
  870.             tcap_boldface = "";
  871.         if (!(tcap_underline = tgetstr("us", &s)))
  872.             tcap_underline = "";
  873.         if (!(tcap_reverse = tgetstr("so", &s)))
  874.             tcap_reverse = "";
  875.     }
  876. }    /* termcap_init */
  877.  
  878.  
  879.  
  880. static int c_output(int c)
  881. {
  882.     putchar(c);
  883. }    /* c_output */
  884.  
  885.  
  886.  
  887.  
  888. void tcap_put(char *cap)
  889. {
  890.     tputs(cap, 0, c_output);
  891. }    /* tcap_put */
  892.  
  893. #endif /* CURSES */
  894.  
  895. /* eof main.c */
  896.