home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / TERMNET / NCFTP183 / MAIN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-20  |  25.1 KB  |  1,129 lines

  1. /* main.c
  2.  *
  3.  *  $RCSfile: main.c,v $
  4.  *  $Revision: 14020.15 $
  5.  *  $Date: 93/07/09 11:50:12 $
  6.  */
  7.  
  8. #define _main_c_
  9.  
  10. #define FTP_VERSION "1.8.3 (August 27, 1994)"
  11.  
  12. /* #define BETA 1 */ /* If defined, it prints a little warning message. */
  13.  
  14. #include "sys.h"
  15.  
  16. #include <sys/stat.h>
  17. #include <arpa/ftp.h>
  18. #include <setjmp.h>
  19. #include <signal.h>
  20. #include <errno.h>
  21. #include <ctype.h>
  22. #include <netdb.h>
  23. #include <pwd.h>
  24.  
  25. #ifdef SYSLOG
  26. #    include <syslog.h>
  27. #endif
  28.  
  29. #if defined(CURSES) && !defined(NO_CURSES_H)
  30. #    undef HZ        /* Collides with HaZeltine ! */
  31. #    include <curses.h>
  32. #    ifdef TERMH
  33. #        include <term.h>
  34. #    endif
  35. #endif    /* CURSES */
  36.  
  37. #include "util.h"
  38. #include "cmds.h"
  39. #include "main.h"
  40. #include "ftp.h"
  41. #include "ftprc.h"
  42. #include "open.h"
  43. #include "set.h"
  44. #include "defaults.h"
  45. #include "copyright.h"
  46.  
  47. /* main.c globals */
  48. int                    slrflag;
  49. int                    fromatty;            /* input is from a terminal */
  50. int                    toatty;                /* output is to a terminal */
  51. int                    doing_script;        /* is a file being <redirected to me? */
  52. char                *altarg;            /* argv[1] with no shell-like preprocessing  */
  53. struct servent        serv;                /* service spec for tcp/ftp */
  54. jmp_buf                toplevel;            /* non-local goto stuff for cmd scanner */
  55. char                *line;                /* input line buffer */
  56. char                *stringbase;        /* current scan point in line buffer */
  57. char                *argbuf;            /* argument storage buffer */
  58. char                *argbase;            /* current storage point in arg buffer */
  59. int                    margc;                /* count of arguments on input line */
  60. char                *margv[20];            /* args parsed from input line */
  61. struct userinfo        uinfo;                /* a copy of their pwent really */
  62. int                    ansi_escapes;        /* for fancy graphics */
  63. int                             startup_msg = 1;        /* TAR: display message on startup? */
  64. int                    ignore_rc;            /* are we supposed to ignore the netrc */
  65. string                progname;            /* simple filename */
  66. string                prompt, prompt2;    /* shell prompt string */
  67. string                anon_password;        /* most likely your email address */
  68. string                pager;                /* program to browse text files */
  69. string                version = FTP_VERSION;
  70. long                eventnumber;        /* number of commands we've done */
  71. FILE                *logf = NULL;        /* log user activity */
  72. longstring            logfname;            /* name of the logfile */
  73. long                logsize = 4096L;    /* max log size. 0 == no limit */
  74. int                    percent_flags;        /* "%" in prompt string? */
  75. int                    at_flags;            /* "@" in prompt string? */
  76. string                 mail_path;            /* your mailbox */
  77. time_t                mbox_time;            /* last modified time of mbox */
  78. size_t                epromptlen;            /* length of the last line of the
  79.                                          * prompt as it will appear on screen,
  80.                                          * (i.e. no invis escape codes).
  81.                                          */
  82.  
  83. #ifdef HPUX
  84. char                *tcap_normal = "\033&d@";    /* Default ANSI escapes */
  85. char                *tcap_boldface = "\033&dH";     /* Half Bright */
  86. char                *tcap_underline = "\033&dD";
  87. char                *tcap_reverse = "\033&dB";
  88.  
  89. #else
  90.  
  91. #ifdef NO_FORMATTING
  92.  
  93. char                            *tcap_normal = "";
  94. char                            *tcap_boldface = "";
  95. char                            *tcap_underline = "";
  96. char                            *tcap_reverse = "";
  97.  
  98. #else
  99.  
  100. char                            *tcap_normal = "\033[0m";       /* Default ANSI escapes */
  101. char                            *tcap_boldface = "\033[1m";
  102. char                            *tcap_underline = "\033[4m";
  103. char                            *tcap_reverse = "\033[7m";
  104.  
  105. #endif
  106.  
  107. #endif
  108.  
  109. size_t                tcl_normal = 4,        /* lengths of the above strings. */
  110.                     tcl_bold = 4,
  111.                     tcl_uline = 4,
  112.                     tcl_rev = 4;
  113.  
  114. #ifdef CURSES
  115. static char            tcbuf[2048];
  116. #endif
  117.  
  118. /* main.c externs */
  119. extern int            debug, verbose, mprompt;
  120. extern int            options, cpend, data, connected, logged_in;
  121. extern int            curtype, macnum, remote_is_unix;
  122. extern FILE            *cout;
  123. extern struct cmd    cmdtab[];
  124. extern str32        curtypename;
  125. extern char            *macbuf;
  126. extern char            *reply_string;
  127. extern char            *short_verbose_msgs[4];
  128. extern string        vstr;
  129. extern Hostname        hostname;
  130. extern longstring    cwd, lcwd, recent_file;
  131. extern int            Optind;
  132. extern char            *Optarg;
  133. #ifdef GATEWAY
  134. extern string        gate_login;
  135. #endif
  136.  
  137. void main(int argc, char **argv)
  138. {
  139.     register char        *cp;
  140.     int                    top, opt, openopts = 0;
  141.     string                tmp, oline;
  142.     struct servent        *sptr;
  143.  
  144.     if ((cp = rindex(argv[0], '/'))) cp++;
  145.     else cp = argv[0];
  146.     (void) Strncpy(progname, cp);
  147.     
  148.     sptr = getservbyname("ftp", "tcp");
  149.     if (sptr == 0) fatal("ftp/tcp: unknown service");
  150.     serv = *sptr;
  151.  
  152.     if (init_arrays())            /* Reserve large blocks of memory now */
  153.         fatal("could not reserve large amounts of memory.");
  154.  
  155. #ifdef GZCAT
  156.     if ((GZCAT == (char *)1) || (GZCAT == (char *)0)) {
  157.         (void) fprintf(stderr,
  158. "You compiled the program with -DGZCAT, but you must specify the path with it!\n\
  159. Re-compile, this time with -DGZCAT=\\\"/path/to/gzcat\\\".\n");
  160.         exit(1);
  161.     }
  162. #endif
  163. #ifdef ZCAT
  164.     if ((ZCAT == (char *)1) || (ZCAT == (char *)0)) {
  165.         (void) fprintf(stderr,
  166. "You compiled the program with -DZCAT, but you must specify the path with it!\n\
  167. Re-compile, this time with -DZCAT=\\\"/path/to/zcat\\\".\n");
  168.         exit(1);
  169.     }
  170. #endif
  171.  
  172.     /*
  173.      * Set up defaults for FTP.
  174.      */
  175.     mprompt = dMPROMPT;
  176.     debug = dDEBUG;
  177.     verbose = dVERBOSE;
  178.     (void) Strncpy(vstr, short_verbose_msgs[verbose+1]);
  179.  
  180.     (void) Strncpy(curtypename, dTYPESTR);
  181.     curtype = dTYPE;
  182.     (void) Strncpy(prompt, dPROMPT);
  183. #ifdef GATEWAY
  184.     (void) Strncpy(gate_login, dGATEWAY_LOGIN);
  185. #endif
  186.  
  187. #ifdef SOCKS
  188.     SOCKSinit("ncftp");
  189. #endif
  190.     
  191.     /*    Setup our pager variable, before we run through the rc,
  192.         which may change it. */
  193.     set_pager(getenv("PAGER"), 0);
  194. #ifdef CURSES
  195.     ansi_escapes = 1;
  196.     termcap_init();
  197. #else
  198.     ansi_escapes = 0;
  199.     if ((cp = getenv("TERM")) != NULL) {
  200.         if ((*cp == 'v' && cp[1] == 't')        /* vt100, vt102, ... */
  201.             || (strcmp(cp, "xterm") == 0))
  202.             ansi_escapes = 1;
  203.     }
  204. #endif
  205.     (void) getuserinfo();
  206.  
  207.     /* Init the mailbox checking code. */
  208.     (void) time(&mbox_time);
  209.  
  210.     (void) Strncpy(anon_password, uinfo.username);
  211.     if (getlocalhostname(uinfo.hostname, sizeof(uinfo.hostname)) == 0) {
  212.         (void) Strncat(anon_password, "@");
  213.         (void) Strncat(anon_password, uinfo.hostname);
  214.     }
  215. #if dLOGGING
  216.     (void) Strncpy(logfname, dLOGNAME);
  217.     (void) LocalDotPath(logfname);
  218. #else
  219.     *logfname = 0;
  220. #endif
  221.     (void) Strncpy(recent_file, dRECENTF);
  222.     (void) LocalDotPath(recent_file);
  223.  
  224.     (void) get_cwd(lcwd, (int) sizeof(lcwd));
  225.  
  226. #ifdef SYSLOG
  227. #    ifdef LOG_LOCAL3
  228.     openlog ("NcFTP", LOG_PID, LOG_LOCAL3);
  229. #    else
  230.     openlog ("NcFTP", LOG_PID);
  231. #    endif
  232. #endif                /* SYSLOG */
  233.  
  234.  
  235.     ignore_rc = 0;
  236.     (void) strcpy(oline, "open ");
  237.     while ((opt = Getopt(argc, argv, "D:V:INRHaicmup:rd:g:")) >= 0) {
  238.         switch(opt) {
  239.             case 'a':
  240.             case 'c':
  241.             case 'i':
  242.             case 'm':
  243.             case 'u':
  244.             case 'r':
  245.                 (void) sprintf(tmp, "-%c ", opt);
  246.                 goto cattmp;
  247.  
  248.             case 'p':
  249.             case 'd':
  250.             case 'g':
  251.                 (void) sprintf(tmp, "-%c %s ", opt, Optarg);
  252.             cattmp:
  253.                 (void) strcat(oline, tmp);
  254.                 openopts++;
  255.                 break;
  256.  
  257.             case 'D':
  258.                 debug = atoi(Optarg);
  259.                 break;
  260.             
  261.             case 'V':
  262.                 set_verbose(Optarg, 0);
  263.                 break;
  264.  
  265.             case 'I':
  266.                 mprompt = !mprompt;
  267.                 break;
  268.  
  269.             case 'N':
  270.                 ++ignore_rc;
  271.                 break;
  272.  
  273.             case 'H':
  274.                 (void) show_version(0, NULL);
  275.                 exit (0);
  276.  
  277.             default:
  278.             usage:
  279.                 (void) fprintf(stderr, "Usage: %s [program options] [[open options] site.to.open[:path]]\n\
  280. Program Options:\n\
  281.     -D x   : Set debugging level to x (a number).\n\
  282.     -H     : Show version and compilation information.\n\
  283.     -I     : Toggle interactive (mprompt) mode.\n\
  284.     -N     : Toggle reading of the .netrc/.ncftprc.\n\
  285.     -V x   : Set verbosity to level x (-1,0,1,2).\n\
  286. Open Options:\n\
  287.     -a     : Open anonymously (this is the default).\n\
  288.     -u     : Open, specify user/password.\n\
  289.     -i     : Ignore machine entry in your .netrc.\n\
  290.     -p N   : Use port #N for connection.\n\
  291.     -r     : \"Redial\" until connected.\n\
  292.     -d N   : Redial, pausing N seconds between tries.\n\
  293.     -g N   : Redial, giving up after N tries.\n\
  294.     :path  : ``Colon-mode:'' If \"path\" is a file, it opens site, retrieves\n\
  295.              file \"path,\" then exits; if \"path\" is a remote directory,\n\
  296.              it opens site then starts you in that directory..\n\
  297.     -c     : If you're using colon-mode with a file path, this will cat the\n\
  298.              file to stdout instead of storing on disk.\n\
  299.     -m     : Just like -c, only it pipes the file to your $PAGER.\n\
  300. Examples:\n\
  301.     ncftp ftp.unl.edu:/pub/README (just fetches README then quits)\n\
  302.     ncftp  (just enters ncftp command shell)\n\
  303.     ncftp -V -u ftp.unl.edu\n\
  304.     ncftp -c ftp.unl.edu:/pub/README (cats README to stdout then quits)\n\
  305.     ncftp -D -r -d 120 -g 10 ftp.unl.edu\n", progname);
  306.             exit(1);
  307.         }
  308.     }
  309.  
  310.     cp = argv[Optind];  /* the site to open. */
  311.     if (cp == NULL) {
  312.         if (openopts)
  313.             goto usage;
  314.     } else
  315.         (void) strcat(oline, cp);
  316.  
  317.     if (ignore_rc <= 0)
  318.         (void) thrash_rc();
  319.     if (ignore_rc <= 1)
  320.         ReadRecentSitesFile();
  321.  
  322.     (void) fix_options();    /* adjust "options" according to "debug"  */
  323.     
  324.     fromatty = doing_script = isatty(0);
  325.     toatty = isatty(1);
  326.     (void) UserLoggedIn();    /* Init parent-death detection. */
  327.     cpend = 0;  /* no pending replies */
  328.     
  329.     if (*logfname)
  330.         logf = fopen (logfname, "a");
  331.  
  332.  
  333.     /* The user specified a host, maybe in 'colon-mode', on the command
  334.      * line.  Open it now...
  335.      */
  336.     if (argc > 1 && cp) {
  337.         if (setjmp(toplevel))
  338.             exit(0);
  339.         (void) Signal(SIGINT, intr);
  340.         (void) Signal(SIGPIPE, lostpeer);
  341.         (void) strcpy(line, oline);
  342.         makeargv();
  343.         /* setpeer uses this to tell if it was called from the cmd-line. */
  344.         eventnumber = 0L;
  345.         (void) cmdOpen(margc, margv);
  346.     }
  347.     eventnumber = 1L;
  348.  
  349.     (void) init_prompt();
  350.  
  351.     if (startup_msg) {  /* TAR */
  352.         if (ansi_escapes) {
  353. #ifdef BETA
  354. #    define BETA_MSG "\n\
  355. For testing purposes only.  Do not re-distribute or subject to novice users."
  356. #else
  357. #    define BETA_MSG ""
  358. #endif
  359.  
  360. #ifndef CURSES
  361.         (void) printf("%sNcFTP %s by Mike Gleason, NCEMRSoft.%s%s%s%s\n", 
  362.             tcap_boldface,
  363.             FTP_VERSION,
  364.             tcap_normal,
  365.             tcap_reverse,
  366.             BETA_MSG,
  367.             tcap_normal
  368.         );
  369. #else
  370.         char vis[256];
  371.         (void) sprintf(vis, "%sNcFTP %s by Mike Gleason, NCEMRSoft.%s%s%s%s\n", 
  372.             tcap_boldface,
  373.             FTP_VERSION,
  374.             tcap_normal,
  375.             tcap_reverse,
  376.             BETA_MSG,
  377.             tcap_normal
  378.         );
  379.         tcap_put(vis);
  380. #endif /* !CURSES */
  381.         }
  382.         else
  383.         (void) printf("%s%s\n", FTP_VERSION, BETA_MSG);
  384.     }  /* TAR */
  385.     if (NOT_VQUIET)
  386.         PrintTip();
  387.     top = setjmp(toplevel) == 0;
  388.     if (top) {
  389.         (void) Signal(SIGINT, intr);
  390.         (void) Signal(SIGPIPE, lostpeer);
  391.     }
  392.     for (;;) {
  393.         (void) cmdscanner(top);
  394.         top = 1;
  395.     }
  396. }    /* main */
  397.  
  398.  
  399.  
  400. /*ARGSUSED*/
  401. void intr SIG_PARAMS
  402. {
  403.     dbprintf("intr()\n");
  404.     (void) Signal(SIGINT, intr);
  405.     (void) longjmp(toplevel, 1);
  406. }    /* intr */
  407.  
  408.  
  409.  
  410. int getuserinfo(void)
  411. {
  412.     register char            *cp;
  413.     struct passwd            *pw;
  414.     string                    str;
  415.     extern char                *home;    /* for glob.c */
  416.     
  417.     home = uinfo.homedir;    /* for glob.c */
  418.     pw = NULL;
  419. #ifdef USE_GETPWUID
  420.     /* Try to use getpwuid(), but if we have to, fall back to getpwnam(). */
  421.     pw = getpwuid(getuid());
  422.     if (pw == NULL) {
  423.         /* Oh well, try getpwnam() then. */
  424.         cp = getlogin();
  425.         if (cp == NULL) {
  426.             cp = getenv("LOGNAME");
  427.             if (cp == NULL)
  428.                 cp = getenv("USER");
  429.         }
  430.         if (cp != NULL)
  431.             pw = getpwnam(cp);
  432.     }
  433. #else
  434.     /* Try to use getpwnam(), but if we have to, fall back to getpwuid(). */
  435.     cp = getlogin();
  436.     if (cp == NULL) {
  437.         cp = getenv("LOGNAME");
  438.         if (cp == NULL)
  439.             cp = getenv("USER");
  440.     }
  441.     if (cp != NULL)
  442.         pw = getpwnam(cp);
  443.     if (pw == NULL) {
  444.         /* Oh well, try getpwuid() then. */
  445.         pw = getpwuid(getuid());
  446.     }
  447. #endif
  448.     if (pw != NULL) {
  449.         uinfo.uid = pw->pw_uid;
  450.         (void) Strncpy(uinfo.username, pw->pw_name);
  451.         (void) Strncpy(uinfo.shell, pw->pw_shell);
  452.         if ((cp = getenv("HOME")) != NULL)
  453.             (void) Strncpy(uinfo.homedir, cp);
  454.         else
  455.             (void) Strncpy(uinfo.homedir, pw->pw_dir);
  456.         cp = getenv("MAIL");
  457.         if (cp == NULL)
  458.             cp = getenv("mail");
  459.         if (cp == NULL)
  460.             (void) sprintf(str, "/usr/spool/mail/%s", uinfo.username);
  461.         else
  462.             (void) Strncpy(str, cp);
  463.         cp = str;
  464.  
  465.         /*
  466.          * mbox variable may be like MAIL=(28 /usr/mail/me /usr/mail/you),
  467.          * so try to find the first mail path.
  468.          */
  469.         while ((*cp != '/') && (*cp != 0))
  470.             cp++;
  471.         (void) Strncpy(mail_path, cp);
  472.         if ((cp = index(mail_path, ' ')) != NULL)
  473.             *cp = '\0';
  474.         return (0);
  475.     } else {
  476.         PERROR("getuserinfo", "Could not get your passwd entry!");
  477.         (void) Strncpy(uinfo.shell, "/bin/sh");
  478.         (void) Strncpy(uinfo.homedir, ".");    /* current directory */
  479.         uinfo.uid = 999;
  480.         if ((cp = getenv("HOME")) != NULL)
  481.             (void) Strncpy(uinfo.homedir, cp);
  482.         mail_path[0] = 0;
  483.         return (-1);
  484.     }
  485. }    /* getuserinfo */
  486.  
  487.  
  488.  
  489.  
  490. int init_arrays(void)
  491. {
  492.     if ((macbuf = (char *) malloc((size_t)(MACBUFLEN))) == NULL)
  493.         goto barf;
  494.     if ((line = (char *) malloc((size_t)(CMDLINELEN))) == NULL)
  495.         goto barf;
  496.     if ((argbuf = (char *) malloc((size_t)(CMDLINELEN))) == NULL)
  497.         goto barf;
  498.     if ((reply_string = (char *) malloc((size_t)(RECEIVEDLINELEN))) == NULL)
  499.         goto barf;
  500.     
  501.     *macbuf = '\0';
  502.     init_transfer_buffer();
  503.     return (0);
  504. barf:
  505.     return (-1);
  506. }    /* init_arrays */
  507.  
  508.  
  509.  
  510. #ifndef BUFSIZ
  511. #define BUFSIZ 512
  512. #endif
  513.  
  514. void init_transfer_buffer(void)
  515. {
  516.     extern char *xferbuf;
  517.     extern size_t xferbufsize;
  518.     
  519.     /* Make sure we use a multiple of BUFSIZ for efficiency. */
  520.     xferbufsize = (MAX_XFER_BUFSIZE / BUFSIZ) * BUFSIZ;
  521.     while (1) {
  522.         xferbuf = (char *) malloc (xferbufsize);
  523.         if (xferbuf != NULL || xferbufsize < 1024)
  524.             break;
  525.         xferbufsize >>= 2;
  526.     }
  527.     
  528.     if (xferbuf != NULL) return;
  529.     fatal("out of memory for transfer buffer.");
  530. }    /* init_transfer_buffer */
  531.  
  532.  
  533.  
  534.  
  535. void init_prompt(void)
  536. {
  537.     register char *cp;
  538.     
  539.     percent_flags = at_flags = 0;
  540.     for (cp = prompt; *cp; cp++) {
  541.         if (*cp == '%') percent_flags = 1;
  542.         else if (*cp == '@') at_flags = 1;
  543.     }
  544. }    /* init_prompt */
  545.  
  546.  
  547.  
  548. /*ARGSUSED*/
  549. void lostpeer SIG_PARAMS
  550. {
  551.     if (connected) {
  552.         close_streams(1);
  553.         if (data >= 0) {
  554.             (void) shutdown(data, 1+1);
  555.             (void) close(data);
  556.             data = -1;
  557.         }
  558.         connected = 0;
  559.     }
  560.     if (connected) {
  561.         close_streams(1);
  562.         connected = 0;
  563.     }
  564.     hostname[0] = cwd[0] = 0;
  565.     logged_in = macnum = 0;
  566. }    /* lostpeer */
  567.  
  568.  
  569. /*
  570.  * Command parser.
  571.  */
  572. void cmdscanner(int top)
  573. {
  574.     register struct cmd *c;
  575.  
  576.     if (!top)
  577.         (void) putchar('\n');
  578.     for (;;) {
  579.         if (!doing_script && !UserLoggedIn())
  580.             (void) quit(0, NULL);
  581.         if (Gets(strprompt(), line, (size_t)CMDLINELEN) == NULL) {
  582.             (void) quit(0, NULL);    /* control-d */
  583.         }
  584.         eventnumber++;
  585.         dbprintf("\"%s\"\n", line);
  586.         (void) makeargv();
  587.         if (margc == 0) {
  588.             continue;    /* blank line... */
  589.         }
  590.         c = getcmd(margv[0]);
  591.         if (c == (struct cmd *) -1) {
  592.             (void) printf("?Ambiguous command\n");
  593.             continue;
  594.         }
  595.         if (c == 0) {
  596.             if (!implicit_cd(margv[0]))
  597.                 (void) printf("?Invalid command\n");
  598.             continue;
  599.         }
  600.         if (c->c_conn && !connected) {
  601.             (void) printf ("Not connected.\n");
  602.             continue;
  603.         }
  604.         if ((*c->c_handler)(margc, margv) == USAGE)
  605.             cmd_usage(c);
  606.         if (c->c_handler != help)
  607.             break;
  608.     }
  609.     (void) Signal(SIGINT, intr);
  610.     (void) Signal(SIGPIPE, lostpeer);
  611. }    /* cmdscanner */
  612.  
  613.  
  614.  
  615.  
  616. char *strprompt(void)
  617. {
  618.     time_t                    tyme;
  619.     char                    eventstr[8];
  620.     char                    *dname, *lastlinestart;
  621.     register char            *p, *q;
  622.     string                    str;
  623.     int                        flag;
  624.  
  625.     if (at_flags == 0 && percent_flags == 0) {
  626.         epromptlen = strlen(prompt);
  627.         return (prompt);    /* But don't overwrite it! */
  628.     }
  629.     epromptlen = 0;
  630.     lastlinestart = prompt2;
  631.     if (at_flags) {
  632.         for (p = prompt, q = prompt2, *q = 0; (*p); p++) {
  633.             if (*p == '@') switch (flag = *++p) {
  634.                 case '\0':
  635.                     --p;
  636.                     break;
  637.                 case 'M':
  638.                     if (CheckNewMail() > 0)
  639.                         q = Strpcpy(q, "(Mail) ");
  640.                     break;
  641.                 case 'N':
  642.                     q = Strpcpy(q, "\n");
  643.                     lastlinestart = q;
  644.                     epromptlen = 0;
  645.                     break;
  646.                 case 'P':    /* reset to no bold, no uline, no inverse, etc. */
  647.                     if (ansi_escapes) {
  648.                         q = Strpcpy(q, tcap_normal);
  649.                         epromptlen += tcl_normal;
  650.                     }
  651.                     break;
  652.                 case 'B':    /* toggle boldface */
  653.                     if (ansi_escapes) {
  654.                         q = Strpcpy(q, tcap_boldface);
  655.                         epromptlen += tcl_bold;
  656.                     }
  657.                     break;
  658.                 case 'U':    /* toggle underline */
  659.                     if (ansi_escapes) {
  660.                         q = Strpcpy(q, tcap_underline);
  661.                         epromptlen += tcl_uline;
  662.                     }
  663.                     break;
  664.                 case 'R':
  665.                 case 'I':    /* toggle inverse (reverse) video */
  666.                     if (ansi_escapes) {
  667.                         q = Strpcpy(q, tcap_reverse);
  668.                         epromptlen += tcl_rev;
  669.                     }
  670.                     break;
  671.                 case 'D':    /* insert current directory */
  672.                 case 'J':
  673.                     if ((flag == 'J') && (remote_is_unix)) {
  674.                         /* Not the whole path, just the dir name. */
  675.                         dname = rindex(cwd, '/');
  676.                         if (dname == NULL)
  677.                             dname = cwd;
  678.                         else if ((dname != cwd) && (dname[1]))
  679.                             ++dname;
  680.                     } else
  681.                         dname = cwd;
  682.                     if (dname[0]) {
  683.                         q = Strpcpy(q, dname);
  684.                         q = Strpcpy(q, " ");
  685.                     }
  686.                     break;
  687.                 case 'H':    /* insert name of connected host */
  688.                     if (logged_in) {
  689.                         (void) sprintf(str, "%s ", hostname);
  690.                         q = Strpcpy(q, str);
  691.                     }
  692.                     break;
  693.                 case 'C':  /* Insert host:path (colon-mode format. */
  694.                     if (logged_in) {
  695.                         (void) sprintf(str, "%s:%s ", hostname, cwd);
  696.                         q = Strpcpy(q, str);
  697.                     } else
  698.                         q = Strpcpy(q, "(not connected)");
  699.                     break;
  700.                 case 'c':
  701.                     if (logged_in) {
  702.                         (void) sprintf(str, "%s:%s\n", hostname, cwd);
  703.                         q = Strpcpy(q, str);
  704.                         lastlinestart = q;    /* there is a \n at the end. */
  705.                         epromptlen = 0;
  706.                     }
  707.                     break;
  708.                 case '!':
  709.                 case 'E':    /* insert event number */
  710.                     (void) sprintf(eventstr, "%ld", eventnumber);
  711.                     q = Strpcpy(q, eventstr);
  712.                     break;
  713.                 default:
  714.                     *q++ = *p;    /* just copy it; unknown switch */
  715.             } else
  716.                 *q++ = *p;
  717.         }
  718.         *q = '\0';
  719.     } else 
  720.         (void) strcpy(prompt2, prompt);
  721.     
  722. #ifndef NO_STRFTIME
  723.     if (percent_flags) {
  724.         /*    only strftime if the user requested it (with a %something),
  725.             otherwise don't waste time doing nothing. */
  726.         (void) time(&tyme);
  727.         (void) Strncpy(str, prompt2);
  728.         (void) strftime(prompt2, sizeof(str), str, localtime(&tyme));
  729.     }
  730. #endif
  731.     epromptlen = (size_t) ((long) strlen(lastlinestart) - (long) epromptlen);
  732.     return (prompt2);
  733. }    /* strprompt */
  734.  
  735.  
  736. /*
  737.  * Slice a string up into argc/argv.
  738.  */
  739.  
  740. void makeargv(void)
  741. {
  742.     char **argp;
  743.  
  744.     margc = 0;
  745.     argp = margv;
  746.     stringbase = line;        /* scan from first of buffer */
  747.     argbase = argbuf;        /* store from first of buffer */
  748.     slrflag = 0;
  749.     while ((*argp++ = slurpstring()) != 0)
  750.         margc++;
  751. }    /* makeargv */
  752.  
  753.  
  754.  
  755.  
  756. /*
  757.  * Parse string into argbuf;
  758.  * implemented with FSM to
  759.  * handle quoting and strings
  760.  */
  761. char *slurpstring(void)
  762. {
  763.     int got_one = 0;
  764.     register char *sb = stringbase;
  765.     register char *ap = argbase;
  766.     char *tmp = argbase;        /* will return this if token found */
  767.  
  768.     if (*sb == '!' || *sb == '$') {    /* recognize ! as a token for shell */
  769.         switch (slrflag) {    /* and $ as token for macro invoke */
  770.             case 0:
  771.                 slrflag++;
  772.                 stringbase++;
  773.                 return ((*sb == '!') ? "!" : "$");
  774.                 /* NOTREACHED */
  775.             case 1:
  776.                 slrflag++;
  777.                 altarg = stringbase;
  778.                 break;
  779.             default:
  780.                 break;
  781.         }
  782.     }
  783.  
  784. S0:
  785.     switch (*sb) {
  786.  
  787.     case '\0':
  788.         goto OUT;
  789.  
  790.     case ' ':
  791.     case '\t':
  792.     case '\n':
  793.     case '=':
  794.         sb++; goto S0;
  795.  
  796.     default:
  797.         switch (slrflag) {
  798.             case 0:
  799.                 slrflag++;
  800.                 break;
  801.             case 1:
  802.                 slrflag++;
  803.                 altarg = sb;
  804.                 break;
  805.             default:
  806.                 break;
  807.         }
  808.         goto S1;
  809.     }
  810.  
  811. S1:
  812.     switch (*sb) {
  813.  
  814.     case ' ':
  815.     case '\t':
  816.     case '\n':
  817.     case '=':
  818.     case '\0':
  819.         goto OUT;    /* end of token */
  820.  
  821.     case '\\':
  822.         sb++; goto S2;    /* slurp next character */
  823.  
  824.     case '"':
  825.         sb++; goto S3;    /* slurp quoted string */
  826.  
  827.     default:
  828.         *ap++ = *sb++;    /* add character to token */
  829.         got_one = 1;
  830.         goto S1;
  831.     }
  832.  
  833. S2:
  834.     switch (*sb) {
  835.  
  836.     case '\0':
  837.         goto OUT;
  838.  
  839.     default:
  840.         *ap++ = *sb++;
  841.         got_one = 1;
  842.         goto S1;
  843.     }
  844.  
  845. S3:
  846.     switch (*sb) {
  847.  
  848.     case '\0':
  849.         goto OUT;
  850.  
  851.     case '"':
  852.         sb++; goto S1;
  853.  
  854.     default:
  855.         *ap++ = *sb++;
  856.         got_one = 1;
  857.         goto S3;
  858.     }
  859.  
  860. OUT:
  861.     if (got_one)
  862.         *ap++ = '\0';
  863.     argbase = ap;            /* update storage pointer */
  864.     stringbase = sb;        /* update scan pointer */
  865.     if (got_one) {
  866.         return(tmp);
  867.     }
  868.     switch (slrflag) {
  869.         case 0:
  870.             slrflag++;
  871.             break;
  872.         case 1:
  873.             slrflag++;
  874.             altarg = (char *) 0;
  875.             break;
  876.         default:
  877.             break;
  878.     }
  879.     return((char *)0);
  880. }    /* slurpstring */
  881.  
  882. /*
  883.  * Help command.
  884.  * Call each command handler with argc == 0 and argv[0] == name.
  885.  */
  886. int
  887. help(int argc, char **argv)
  888. {
  889.     register struct cmd        *c;
  890.     int                        showall = 0, helpall = 0;
  891.     char                    *arg;
  892.     int                        i, j, k;
  893.     int                     nRows, nCols;
  894.     int                     nCmds2Print;
  895.     int                     screenColumns;
  896.     int                     len, widestName;
  897.     char                     *cp, **cmdnames, spec[16];
  898.  
  899.     if (argc == 2) {
  900.         showall = (strcmp(argv[1], "showall") == 0);
  901.         helpall = (strcmp(argv[1], "helpall") == 0);
  902.     }
  903.     if (argc == 1 || showall)  {
  904.         (void) printf("\
  905. Commands may be abbreviated.  'help showall' shows aliases, invisible and\n\
  906. unsupported commands.  'help <command>' gives a brief description of <command>.\n\n");
  907.  
  908.         for (c = cmdtab, nCmds2Print=0; c->c_name != NULL; c++) 
  909.             if (!c->c_hidden || showall)
  910.                 nCmds2Print++;
  911.  
  912.         if ((cmdnames = (char **) malloc(sizeof(char *) * nCmds2Print)) == NULL)
  913.             fatal("out of memory!");
  914.  
  915.         for (c = cmdtab, i=0, widestName=0; c->c_name != NULL; c++) {
  916.             if (!c->c_hidden || showall) {
  917.                 cmdnames[i++] = c->c_name;
  918.                 len = (int) strlen(c->c_name);
  919.                 if (len > widestName)
  920.                     widestName = len;
  921.             }
  922.         }
  923.  
  924.         if ((cp = getenv("COLUMNS")) == NULL)
  925.             screenColumns = 80;
  926.         else
  927.             screenColumns = atoi(cp);
  928.  
  929.         widestName += 2;    /* leave room for white-space in between cols. */
  930.         nCols = screenColumns / widestName;
  931.         /* if ((screenColumns % widestName) > 0) nCols++; */
  932.         nRows = nCmds2Print / nCols;
  933.         if ((nCmds2Print % nCols) > 0)
  934.             nRows++;
  935.  
  936.         (void) sprintf(spec, "%%-%ds", widestName);
  937.         for (i=0; i<nRows; i++) {
  938.             for (j=0; j<nCols; j++) {
  939.                 k = nRows*j + i;
  940.                 if (k < nCmds2Print)
  941.                     (void) printf(spec, cmdnames[k]);
  942.             }
  943.             (void) printf("\n");
  944.         }
  945.         Free(cmdnames);
  946.     } else if (helpall) {
  947.         /* Really intended to debug the help strings. */
  948.         for (c = cmdtab; c->c_name != NULL; c++) {
  949.             cmd_help(c);
  950.             cmd_usage(c);
  951.         }
  952.     } else while (--argc > 0) {
  953.         arg = *++argv;
  954.         c = getcmd(arg);
  955.         if (c == (struct cmd *)-1)
  956.             (void) printf("?Ambiguous help command %s\n", arg);
  957.         else if (c == (struct cmd *)0)
  958.             (void) printf("?Invalid help command %s\n", arg);
  959.         else {
  960.             cmd_help(c);
  961.             cmd_usage(c);
  962.         }
  963.     }
  964.     return NOERR;
  965. }    /* help */
  966.  
  967.  
  968. /*
  969.  * If the user wants to, s/he can specify the maximum size of the log
  970.  * file, so it doesn't waste too much disk space.  If the log is too
  971.  * fat, trim the older lines (at the top) until we're under the limit.
  972.  */
  973. void trim_log(void)
  974. {
  975.     FILE                *new, *old;
  976.     struct stat            st;
  977.     long                fat;
  978.     string                tmplogname, str;
  979.  
  980.     if (logsize <= 0 || *logfname == 0 || stat(logfname, &st) ||
  981.         (old = fopen(logfname, "r")) == NULL)
  982.         return;    /* never trim, or no log */
  983.     fat = st.st_size - logsize;
  984.     if (fat <= 0L) return;    /* log too small yet */
  985.     while (fat > 0L) {
  986.         if (FGets(str, old) == NULL) return;
  987.         fat -= (long) strlen(str);
  988.     }
  989.     /* skip lines until a new site was opened */
  990.     while (1) {
  991.         if (FGets(str, old) == NULL) {
  992.             (void) fclose(old);
  993.             (void) unlink(logfname);
  994.             return;    /* nothing left, start anew */
  995.         }
  996.         if (*str != '\t') break;
  997.     }
  998.     
  999.     /* copy the remaining lines in "old" to "new" */
  1000.     (void) Strncpy(tmplogname, logfname);
  1001.     tmplogname[strlen(tmplogname) - 1] = 'T';
  1002.     if ((new = fopen(tmplogname, "w")) == NULL) {
  1003.         (void) PERROR("trim_log", tmplogname);
  1004.         return;
  1005.     }
  1006.     (void) fputs(str, new);
  1007.     while (FGets(str, old))
  1008.         (void) fputs(str, new);
  1009.     (void) fclose(old); (void) fclose(new);
  1010.     if (unlink(logfname) < 0)
  1011.         PERROR("trim_log", logfname);
  1012.     if (rename(tmplogname, logfname) < 0)
  1013.         PERROR("trim_log", tmplogname);
  1014. }    /* trim_log */
  1015.  
  1016.  
  1017.  
  1018.  
  1019. int CheckNewMail(void)
  1020. {
  1021.     struct stat stbuf;
  1022.  
  1023.     if (*mail_path == '\0') return 0;
  1024.     if (stat(mail_path, &stbuf) < 0) {    /* cant find mail_path so we'll */
  1025.         *mail_path = '\0';                /* never check it again */
  1026.         return 0;
  1027.     }
  1028.  
  1029.     /*
  1030.      * Check if the size is non-zero and the access time is less than
  1031.      * the modify time -- this indicates unread mail.
  1032.      */
  1033.     if ((stbuf.st_size != 0) && (stbuf.st_atime <= stbuf.st_mtime)) {
  1034.         if (stbuf.st_mtime > mbox_time) {
  1035.             (void) printf("%s\n", NEWMAILMESSAGE);
  1036.             mbox_time = stbuf.st_mtime;
  1037.         }
  1038.         return 1;
  1039.     }
  1040.  
  1041.     return 0;
  1042. }    /* CheckNewMail */
  1043.  
  1044.  
  1045.  
  1046. #ifdef CURSES
  1047. int termcap_get(char **dest, char *attr)
  1048. {
  1049.     static char area[1024];
  1050.     static char *s = area;
  1051.     char *buf, *cp;
  1052.     int i, result = -1;
  1053.     int len = 0;
  1054.  
  1055.     *dest = NULL;
  1056.     while (*attr != '\0') {
  1057.         buf = tgetstr(attr, &s);
  1058.         if (buf != NULL && buf[0] != '\0') {
  1059.             for (i = 0; (buf[i] <= '9') && (buf[i] >= '0'); )
  1060.                 i++;
  1061.             /* Get rid of the terminal delays, like "$<2>". */
  1062.             if ((cp = strstr(&(buf[i]), "$<")) != NULL)
  1063.                 *cp = 0;
  1064.             if (*dest == NULL)
  1065.                 *dest = (char *)malloc(strlen(&(buf[i])) + 1);
  1066.             else
  1067.                 *dest = (char *)realloc(*dest, len + strlen(&(buf[i])) + 1);
  1068.             if (*dest == NULL)
  1069.                 break;
  1070.             (void) strcpy(*dest + len, &(buf[i]));
  1071.             len += strlen (&(buf[i]));
  1072.         }
  1073.         attr += 2;
  1074.     }
  1075.     if (*dest == NULL)
  1076.         *dest = "";
  1077.     else
  1078.         result = 0;
  1079.     return (result);
  1080. }    /* termcap_get */
  1081.  
  1082.  
  1083.   
  1084. void termcap_init(void)
  1085. {
  1086.     char *term;
  1087.  
  1088.     if ((term = getenv("TERM")) == NULL) {
  1089.         term = "dumb";  /* TAR */
  1090.         ansi_escapes = 0;
  1091.     }
  1092.     if (tgetent(tcbuf,term) != 1) {
  1093.         (void) fprintf(stderr,"Can't get termcap entry for terminal [%s]\n", term);
  1094.     } else {
  1095.         (void) termcap_get(&tcap_normal, "meuese");
  1096.         if (termcap_get(&tcap_boldface, "md") < 0) {
  1097.             /* Dim-mode is better than nothing... */
  1098.             (void) termcap_get(&tcap_boldface, "mh");
  1099.         }
  1100.         (void) termcap_get(&tcap_underline, "us");
  1101.         (void) termcap_get(&tcap_reverse, "so");
  1102.         tcl_normal = strlen(tcap_normal);
  1103.         tcl_bold = strlen(tcap_boldface);
  1104.         tcl_uline = strlen(tcap_underline);
  1105.         tcl_rev = strlen(tcap_reverse);
  1106.     }
  1107.  
  1108. }    /* termcap_init */
  1109.  
  1110.  
  1111.  
  1112. static int c_output(int c)
  1113. {
  1114.     return (putchar(c));
  1115. }    /* c_output */
  1116.  
  1117.  
  1118.  
  1119.  
  1120. void tcap_put(char *cap)
  1121. {
  1122.     tputs(cap, 0, c_output);
  1123. }    /* tcap_put */
  1124.  
  1125. #endif /* CURSES */
  1126.  
  1127. /* eof main.c */
  1128.  
  1129.