diff options
author | ache <ache@FreeBSD.org> | 1994-09-22 23:45:37 +0000 |
---|---|---|
committer | ache <ache@FreeBSD.org> | 1994-09-22 23:45:37 +0000 |
commit | 41cb9decc65e51e29f0eb6fe06bcb3594726bd6b (patch) | |
tree | 31cb31bfb69915fc791ce9c2ec7d345124bedebf /usr.bin/ncftp/main.c | |
download | FreeBSD-src-41cb9decc65e51e29f0eb6fe06bcb3594726bd6b.zip FreeBSD-src-41cb9decc65e51e29f0eb6fe06bcb3594726bd6b.tar.gz |
ncftp 1.8.5
Diffstat (limited to 'usr.bin/ncftp/main.c')
-rw-r--r-- | usr.bin/ncftp/main.c | 1128 |
1 files changed, 1128 insertions, 0 deletions
diff --git a/usr.bin/ncftp/main.c b/usr.bin/ncftp/main.c new file mode 100644 index 0000000..446c1c3 --- /dev/null +++ b/usr.bin/ncftp/main.c @@ -0,0 +1,1128 @@ +/* main.c + * + * $RCSfile: main.c,v $ + * $Revision: 14020.15 $ + * $Date: 93/07/09 11:50:12 $ + */ + +#define _main_c_ + +#define FTP_VERSION "1.8.5 (September 20, 1994)" + +/* #define BETA 1 */ /* If defined, it prints a little warning message. */ + +#include "sys.h" + +#include <sys/stat.h> +#include <arpa/ftp.h> +#include <setjmp.h> +#include <signal.h> +#include <errno.h> +#include <ctype.h> +#include <netdb.h> +#include <pwd.h> + +#ifdef SYSLOG +# include <syslog.h> +#endif + +#if defined(CURSES) && !defined(NO_CURSES_H) +# undef HZ /* Collides with HaZeltine ! */ +# include <curses.h> +# ifdef TERMH +# include <term.h> +# endif +#endif /* CURSES */ + +#include "util.h" +#include "cmds.h" +#include "main.h" +#include "ftp.h" +#include "ftprc.h" +#include "open.h" +#include "set.h" +#include "defaults.h" +#include "copyright.h" + +/* main.c globals */ +int slrflag; +int fromatty; /* input is from a terminal */ +int toatty; /* output is to a terminal */ +int doing_script; /* is a file being <redirected to me? */ +char *altarg; /* argv[1] with no shell-like preprocessing */ +struct servent serv; /* service spec for tcp/ftp */ +jmp_buf toplevel; /* non-local goto stuff for cmd scanner */ +char *line; /* input line buffer */ +char *stringbase; /* current scan point in line buffer */ +char *argbuf; /* argument storage buffer */ +char *argbase; /* current storage point in arg buffer */ +int margc; /* count of arguments on input line */ +char *margv[20]; /* args parsed from input line */ +struct userinfo uinfo; /* a copy of their pwent really */ +int ansi_escapes; /* for fancy graphics */ +int startup_msg = 1; /* TAR: display message on startup? */ +int ignore_rc; /* are we supposed to ignore the netrc */ +string progname; /* simple filename */ +string prompt, prompt2; /* shell prompt string */ +string anon_password; /* most likely your email address */ +string pager; /* program to browse text files */ +string version = FTP_VERSION; +long eventnumber; /* number of commands we've done */ +FILE *logf = NULL; /* log user activity */ +longstring logfname; /* name of the logfile */ +long logsize = 4096L; /* max log size. 0 == no limit */ +int percent_flags; /* "%" in prompt string? */ +int at_flags; /* "@" in prompt string? */ +string mail_path; /* your mailbox */ +time_t mbox_time; /* last modified time of mbox */ +size_t epromptlen; /* length of the last line of the + * prompt as it will appear on screen, + * (i.e. no invis escape codes). + */ + +#ifdef HPUX +char *tcap_normal = "\033&d@"; /* Default ANSI escapes */ +char *tcap_boldface = "\033&dH"; /* Half Bright */ +char *tcap_underline = "\033&dD"; +char *tcap_reverse = "\033&dB"; + +#else + +#ifdef NO_FORMATTING + +char *tcap_normal = ""; +char *tcap_boldface = ""; +char *tcap_underline = ""; +char *tcap_reverse = ""; + +#else + +char *tcap_normal = "\033[0m"; /* Default ANSI escapes */ +char *tcap_boldface = "\033[1m"; +char *tcap_underline = "\033[4m"; +char *tcap_reverse = "\033[7m"; + +#endif + +#endif + +size_t tcl_normal = 4, /* lengths of the above strings. */ + tcl_bold = 4, + tcl_uline = 4, + tcl_rev = 4; + +#ifdef CURSES +static char tcbuf[2048]; +#endif + +/* main.c externs */ +extern int debug, verbose, mprompt; +extern int options, cpend, data, connected, logged_in; +extern int curtype, macnum, remote_is_unix; +extern FILE *cout; +extern struct cmd cmdtab[]; +extern str32 curtypename; +extern char *macbuf; +extern char *reply_string; +extern char *short_verbose_msgs[4]; +extern string vstr; +extern Hostname hostname; +extern longstring cwd, lcwd, recent_file; +extern int Optind; +extern char *Optarg; +#ifdef GATEWAY +extern string gate_login; +#endif + +void main(int argc, char **argv) +{ + register char *cp; + int top, opt, openopts = 0; + string tmp, oline; + struct servent *sptr; + + if ((cp = rindex(argv[0], '/'))) cp++; + else cp = argv[0]; + (void) Strncpy(progname, cp); + + sptr = getservbyname("ftp", "tcp"); + if (sptr == 0) fatal("ftp/tcp: unknown service"); + serv = *sptr; + + if (init_arrays()) /* Reserve large blocks of memory now */ + fatal("could not reserve large amounts of memory."); + +#ifdef GZCAT + if ((GZCAT == (char *)1) || (GZCAT == (char *)0)) { + (void) fprintf(stderr, +"You compiled the program with -DGZCAT, but you must specify the path with it!\n\ +Re-compile, this time with -DGZCAT=\\\"/path/to/gzcat\\\".\n"); + exit(1); + } +#endif +#ifdef ZCAT + if ((ZCAT == (char *)1) || (ZCAT == (char *)0)) { + (void) fprintf(stderr, +"You compiled the program with -DZCAT, but you must specify the path with it!\n\ +Re-compile, this time with -DZCAT=\\\"/path/to/zcat\\\".\n"); + exit(1); + } +#endif + + /* + * Set up defaults for FTP. + */ + mprompt = dMPROMPT; + debug = dDEBUG; + verbose = dVERBOSE; + (void) Strncpy(vstr, short_verbose_msgs[verbose+1]); + + (void) Strncpy(curtypename, dTYPESTR); + curtype = dTYPE; + (void) Strncpy(prompt, dPROMPT); +#ifdef GATEWAY + (void) Strncpy(gate_login, dGATEWAY_LOGIN); +#endif + +#ifdef SOCKS + SOCKSinit("ncftp"); +#endif + + /* Setup our pager variable, before we run through the rc, + which may change it. */ + set_pager(getenv("PAGER"), 0); +#ifdef CURSES + ansi_escapes = 1; + termcap_init(); +#else + ansi_escapes = 0; + if ((cp = getenv("TERM")) != NULL) { + if ((*cp == 'v' && cp[1] == 't') /* vt100, vt102, ... */ + || (strcmp(cp, "xterm") == 0)) + ansi_escapes = 1; + } +#endif + (void) getuserinfo(); + + /* Init the mailbox checking code. */ + (void) time(&mbox_time); + + (void) Strncpy(anon_password, uinfo.username); + if (getlocalhostname(uinfo.hostname, sizeof(uinfo.hostname)) == 0) { + (void) Strncat(anon_password, "@"); + (void) Strncat(anon_password, uinfo.hostname); + } +#if dLOGGING + (void) Strncpy(logfname, dLOGNAME); + (void) LocalDotPath(logfname); +#else + *logfname = 0; +#endif + (void) Strncpy(recent_file, dRECENTF); + (void) LocalDotPath(recent_file); + + (void) get_cwd(lcwd, (int) sizeof(lcwd)); + +#ifdef SYSLOG +# ifdef LOG_LOCAL3 + openlog ("NcFTP", LOG_PID, LOG_LOCAL3); +# else + openlog ("NcFTP", LOG_PID); +# endif +#endif /* SYSLOG */ + + + ignore_rc = 0; + (void) strcpy(oline, "open "); + while ((opt = Getopt(argc, argv, "D:V:INRHaicmup:rd:g:")) >= 0) { + switch(opt) { + case 'a': + case 'c': + case 'i': + case 'm': + case 'u': + case 'r': + (void) sprintf(tmp, "-%c ", opt); + goto cattmp; + + case 'p': + case 'd': + case 'g': + (void) sprintf(tmp, "-%c %s ", opt, Optarg); + cattmp: + (void) strcat(oline, tmp); + openopts++; + break; + + case 'D': + debug = atoi(Optarg); + break; + + case 'V': + set_verbose(Optarg, 0); + break; + + case 'I': + mprompt = !mprompt; + break; + + case 'N': + ++ignore_rc; + break; + + case 'H': + (void) show_version(0, NULL); + exit (0); + + default: + usage: + (void) fprintf(stderr, "Usage: %s [program options] [[open options] site.to.open[:path]]\n\ +Program Options:\n\ + -D x : Set debugging level to x (a number).\n\ + -H : Show version and compilation information.\n\ + -I : Toggle interactive (mprompt) mode.\n\ + -N : Toggle reading of the .netrc/.ncftprc.\n\ + -V x : Set verbosity to level x (-1,0,1,2).\n\ +Open Options:\n\ + -a : Open anonymously (this is the default).\n\ + -u : Open, specify user/password.\n\ + -i : Ignore machine entry in your .netrc.\n\ + -p N : Use port #N for connection.\n\ + -r : \"Redial\" until connected.\n\ + -d N : Redial, pausing N seconds between tries.\n\ + -g N : Redial, giving up after N tries.\n\ + :path : ``Colon-mode:'' If \"path\" is a file, it opens site, retrieves\n\ + file \"path,\" then exits; if \"path\" is a remote directory,\n\ + it opens site then starts you in that directory..\n\ + -c : If you're using colon-mode with a file path, this will cat the\n\ + file to stdout instead of storing on disk.\n\ + -m : Just like -c, only it pipes the file to your $PAGER.\n\ +Examples:\n\ + ncftp ftp.unl.edu:/pub/README (just fetches README then quits)\n\ + ncftp (just enters ncftp command shell)\n\ + ncftp -V -u ftp.unl.edu\n\ + ncftp -c ftp.unl.edu:/pub/README (cats README to stdout then quits)\n\ + ncftp -D -r -d 120 -g 10 ftp.unl.edu\n", progname); + exit(1); + } + } + + cp = argv[Optind]; /* the site to open. */ + if (cp == NULL) { + if (openopts) + goto usage; + } else + (void) strcat(oline, cp); + + if (ignore_rc <= 0) + (void) thrash_rc(); + if (ignore_rc <= 1) + ReadRecentSitesFile(); + + (void) fix_options(); /* adjust "options" according to "debug" */ + + fromatty = doing_script = isatty(0); + toatty = isatty(1); + (void) UserLoggedIn(); /* Init parent-death detection. */ + cpend = 0; /* no pending replies */ + + if (*logfname) + logf = fopen (logfname, "a"); + + + /* The user specified a host, maybe in 'colon-mode', on the command + * line. Open it now... + */ + if (argc > 1 && cp) { + if (setjmp(toplevel)) + exit(0); + (void) Signal(SIGINT, intr); + (void) Signal(SIGPIPE, lostpeer); + (void) strcpy(line, oline); + makeargv(); + /* setpeer uses this to tell if it was called from the cmd-line. */ + eventnumber = 0L; + (void) cmdOpen(margc, margv); + } + eventnumber = 1L; + + (void) init_prompt(); + + if (startup_msg) { /* TAR */ + if (ansi_escapes) { +#ifdef BETA +# define BETA_MSG "\n\ +For testing purposes only. Do not re-distribute or subject to novice users." +#else +# define BETA_MSG "" +#endif + +#ifndef CURSES + (void) printf("%sNcFTP %s by Mike Gleason, NCEMRSoft.%s%s%s%s\n", + tcap_boldface, + FTP_VERSION, + tcap_normal, + tcap_reverse, + BETA_MSG, + tcap_normal + ); +#else + char vis[256]; + (void) sprintf(vis, "%sNcFTP %s by Mike Gleason, NCEMRSoft.%s%s%s%s\n", + tcap_boldface, + FTP_VERSION, + tcap_normal, + tcap_reverse, + BETA_MSG, + tcap_normal + ); + tcap_put(vis); +#endif /* !CURSES */ + } + else + (void) printf("%s%s\n", FTP_VERSION, BETA_MSG); + } /* TAR */ + if (NOT_VQUIET) + PrintTip(); + top = setjmp(toplevel) == 0; + if (top) { + (void) Signal(SIGINT, intr); + (void) Signal(SIGPIPE, lostpeer); + } + for (;;) { + (void) cmdscanner(top); + top = 1; + } +} /* main */ + + + +/*ARGSUSED*/ +void intr SIG_PARAMS +{ + dbprintf("intr()\n"); + (void) Signal(SIGINT, intr); + (void) longjmp(toplevel, 1); +} /* intr */ + + + +int getuserinfo(void) +{ + register char *cp; + struct passwd *pw; + string str; + extern char *home; /* for glob.c */ + + home = uinfo.homedir; /* for glob.c */ + pw = NULL; +#ifdef USE_GETPWUID + /* Try to use getpwuid(), but if we have to, fall back to getpwnam(). */ + pw = getpwuid(getuid()); + if (pw == NULL) { + /* Oh well, try getpwnam() then. */ + cp = getlogin(); + if (cp == NULL) { + cp = getenv("LOGNAME"); + if (cp == NULL) + cp = getenv("USER"); + } + if (cp != NULL) + pw = getpwnam(cp); + } +#else + /* Try to use getpwnam(), but if we have to, fall back to getpwuid(). */ + cp = getlogin(); + if (cp == NULL) { + cp = getenv("LOGNAME"); + if (cp == NULL) + cp = getenv("USER"); + } + if (cp != NULL) + pw = getpwnam(cp); + if (pw == NULL) { + /* Oh well, try getpwuid() then. */ + pw = getpwuid(getuid()); + } +#endif + if (pw != NULL) { + uinfo.uid = pw->pw_uid; + (void) Strncpy(uinfo.username, pw->pw_name); + (void) Strncpy(uinfo.shell, pw->pw_shell); + if ((cp = getenv("HOME")) != NULL) + (void) Strncpy(uinfo.homedir, cp); + else + (void) Strncpy(uinfo.homedir, pw->pw_dir); + cp = getenv("MAIL"); + if (cp == NULL) + cp = getenv("mail"); + if (cp == NULL) + (void) sprintf(str, "/usr/spool/mail/%s", uinfo.username); + else + (void) Strncpy(str, cp); + cp = str; + + /* + * mbox variable may be like MAIL=(28 /usr/mail/me /usr/mail/you), + * so try to find the first mail path. + */ + while ((*cp != '/') && (*cp != 0)) + cp++; + (void) Strncpy(mail_path, cp); + if ((cp = index(mail_path, ' ')) != NULL) + *cp = '\0'; + return (0); + } else { + PERROR("getuserinfo", "Could not get your passwd entry!"); + (void) Strncpy(uinfo.shell, "/bin/sh"); + (void) Strncpy(uinfo.homedir, "."); /* current directory */ + uinfo.uid = 999; + if ((cp = getenv("HOME")) != NULL) + (void) Strncpy(uinfo.homedir, cp); + mail_path[0] = 0; + return (-1); + } +} /* getuserinfo */ + + + + +int init_arrays(void) +{ + if ((macbuf = (char *) malloc((size_t)(MACBUFLEN))) == NULL) + goto barf; + if ((line = (char *) malloc((size_t)(CMDLINELEN))) == NULL) + goto barf; + if ((argbuf = (char *) malloc((size_t)(CMDLINELEN))) == NULL) + goto barf; + if ((reply_string = (char *) malloc((size_t)(RECEIVEDLINELEN))) == NULL) + goto barf; + + *macbuf = '\0'; + init_transfer_buffer(); + return (0); +barf: + return (-1); +} /* init_arrays */ + + + +#ifndef BUFSIZ +#define BUFSIZ 512 +#endif + +void init_transfer_buffer(void) +{ + extern char *xferbuf; + extern size_t xferbufsize; + + /* Make sure we use a multiple of BUFSIZ for efficiency. */ + xferbufsize = (MAX_XFER_BUFSIZE / BUFSIZ) * BUFSIZ; + while (1) { + xferbuf = (char *) malloc (xferbufsize); + if (xferbuf != NULL || xferbufsize < 1024) + break; + xferbufsize >>= 2; + } + + if (xferbuf != NULL) return; + fatal("out of memory for transfer buffer."); +} /* init_transfer_buffer */ + + + + +void init_prompt(void) +{ + register char *cp; + + percent_flags = at_flags = 0; + for (cp = prompt; *cp; cp++) { + if (*cp == '%') percent_flags = 1; + else if (*cp == '@') at_flags = 1; + } +} /* init_prompt */ + + + +/*ARGSUSED*/ +void lostpeer SIG_PARAMS +{ + if (connected) { + close_streams(1); + if (data >= 0) { + (void) shutdown(data, 1+1); + (void) close(data); + data = -1; + } + connected = 0; + } + if (connected) { + close_streams(1); + connected = 0; + } + hostname[0] = cwd[0] = 0; + logged_in = macnum = 0; +} /* lostpeer */ + + +/* + * Command parser. + */ +void cmdscanner(int top) +{ + register struct cmd *c; + + if (!top) + (void) putchar('\n'); + for (;;) { + if (!doing_script && !UserLoggedIn()) + (void) quit(0, NULL); + if (Gets(strprompt(), line, (size_t)CMDLINELEN) == NULL) { + (void) quit(0, NULL); /* control-d */ + } + eventnumber++; + dbprintf("\"%s\"\n", line); + (void) makeargv(); + if (margc == 0) { + continue; /* blank line... */ + } + c = getcmd(margv[0]); + if (c == (struct cmd *) -1) { + (void) printf("?Ambiguous command\n"); + continue; + } + if (c == 0) { + if (!implicit_cd(margv[0])) + (void) printf("?Invalid command\n"); + continue; + } + if (c->c_conn && !connected) { + (void) printf ("Not connected.\n"); + continue; + } + if ((*c->c_handler)(margc, margv) == USAGE) + cmd_usage(c); + if (c->c_handler != help) + break; + } + (void) Signal(SIGINT, intr); + (void) Signal(SIGPIPE, lostpeer); +} /* cmdscanner */ + + + + +char *strprompt(void) +{ + time_t tyme; + char eventstr[8]; + char *dname, *lastlinestart; + register char *p, *q; + string str; + int flag; + + if (at_flags == 0 && percent_flags == 0) { + epromptlen = strlen(prompt); + return (prompt); /* But don't overwrite it! */ + } + epromptlen = 0; + lastlinestart = prompt2; + if (at_flags) { + for (p = prompt, q = prompt2, *q = 0; (*p); p++) { + if (*p == '@') switch (flag = *++p) { + case '\0': + --p; + break; + case 'M': + if (CheckNewMail() > 0) + q = Strpcpy(q, "(Mail) "); + break; + case 'N': + q = Strpcpy(q, "\n"); + lastlinestart = q; + epromptlen = 0; + break; + case 'P': /* reset to no bold, no uline, no inverse, etc. */ + if (ansi_escapes) { + q = Strpcpy(q, tcap_normal); + epromptlen += tcl_normal; + } + break; + case 'B': /* toggle boldface */ + if (ansi_escapes) { + q = Strpcpy(q, tcap_boldface); + epromptlen += tcl_bold; + } + break; + case 'U': /* toggle underline */ + if (ansi_escapes) { + q = Strpcpy(q, tcap_underline); + epromptlen += tcl_uline; + } + break; + case 'R': + case 'I': /* toggle inverse (reverse) video */ + if (ansi_escapes) { + q = Strpcpy(q, tcap_reverse); + epromptlen += tcl_rev; + } + break; + case 'D': /* insert current directory */ + case 'J': + if ((flag == 'J') && (remote_is_unix)) { + /* Not the whole path, just the dir name. */ + dname = rindex(cwd, '/'); + if (dname == NULL) + dname = cwd; + else if ((dname != cwd) && (dname[1])) + ++dname; + } else + dname = cwd; + if (dname[0]) { + q = Strpcpy(q, dname); + q = Strpcpy(q, " "); + } + break; + case 'H': /* insert name of connected host */ + if (logged_in) { + (void) sprintf(str, "%s ", hostname); + q = Strpcpy(q, str); + } + break; + case 'C': /* Insert host:path (colon-mode format. */ + if (logged_in) { + (void) sprintf(str, "%s:%s ", hostname, cwd); + q = Strpcpy(q, str); + } else + q = Strpcpy(q, "(not connected)"); + break; + case 'c': + if (logged_in) { + (void) sprintf(str, "%s:%s\n", hostname, cwd); + q = Strpcpy(q, str); + lastlinestart = q; /* there is a \n at the end. */ + epromptlen = 0; + } + break; + case '!': + case 'E': /* insert event number */ + (void) sprintf(eventstr, "%ld", eventnumber); + q = Strpcpy(q, eventstr); + break; + default: + *q++ = *p; /* just copy it; unknown switch */ + } else + *q++ = *p; + } + *q = '\0'; + } else + (void) strcpy(prompt2, prompt); + +#ifndef NO_STRFTIME + if (percent_flags) { + /* only strftime if the user requested it (with a %something), + otherwise don't waste time doing nothing. */ + (void) time(&tyme); + (void) Strncpy(str, prompt2); + (void) strftime(prompt2, sizeof(str), str, localtime(&tyme)); + } +#endif + epromptlen = (size_t) ((long) strlen(lastlinestart) - (long) epromptlen); + return (prompt2); +} /* strprompt */ + + +/* + * Slice a string up into argc/argv. + */ + +void makeargv(void) +{ + char **argp; + + margc = 0; + argp = margv; + stringbase = line; /* scan from first of buffer */ + argbase = argbuf; /* store from first of buffer */ + slrflag = 0; + while ((*argp++ = slurpstring()) != 0) + margc++; +} /* makeargv */ + + + + +/* + * Parse string into argbuf; + * implemented with FSM to + * handle quoting and strings + */ +char *slurpstring(void) +{ + int got_one = 0; + register char *sb = stringbase; + register char *ap = argbase; + char *tmp = argbase; /* will return this if token found */ + + if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ + switch (slrflag) { /* and $ as token for macro invoke */ + case 0: + slrflag++; + stringbase++; + return ((*sb == '!') ? "!" : "$"); + /* NOTREACHED */ + case 1: + slrflag++; + altarg = stringbase; + break; + default: + break; + } + } + +S0: + switch (*sb) { + + case '\0': + goto OUT; + + case ' ': + case '\t': + case '\n': + case '=': + sb++; goto S0; + + default: + switch (slrflag) { + case 0: + slrflag++; + break; + case 1: + slrflag++; + altarg = sb; + break; + default: + break; + } + goto S1; + } + +S1: + switch (*sb) { + + case ' ': + case '\t': + case '\n': + case '=': + case '\0': + goto OUT; /* end of token */ + + case '\\': + sb++; goto S2; /* slurp next character */ + + case '"': + sb++; goto S3; /* slurp quoted string */ + + default: + *ap++ = *sb++; /* add character to token */ + got_one = 1; + goto S1; + } + +S2: + switch (*sb) { + + case '\0': + goto OUT; + + default: + *ap++ = *sb++; + got_one = 1; + goto S1; + } + +S3: + switch (*sb) { + + case '\0': + goto OUT; + + case '"': + sb++; goto S1; + + default: + *ap++ = *sb++; + got_one = 1; + goto S3; + } + +OUT: + if (got_one) + *ap++ = '\0'; + argbase = ap; /* update storage pointer */ + stringbase = sb; /* update scan pointer */ + if (got_one) { + return(tmp); + } + switch (slrflag) { + case 0: + slrflag++; + break; + case 1: + slrflag++; + altarg = (char *) 0; + break; + default: + break; + } + return((char *)0); +} /* slurpstring */ + +/* + * Help command. + * Call each command handler with argc == 0 and argv[0] == name. + */ +int +help(int argc, char **argv) +{ + register struct cmd *c; + int showall = 0, helpall = 0; + char *arg; + int i, j, k; + int nRows, nCols; + int nCmds2Print; + int screenColumns; + int len, widestName; + char *cp, **cmdnames, spec[16]; + + if (argc == 2) { + showall = (strcmp(argv[1], "showall") == 0); + helpall = (strcmp(argv[1], "helpall") == 0); + } + if (argc == 1 || showall) { + (void) printf("\ +Commands may be abbreviated. 'help showall' shows aliases, invisible and\n\ +unsupported commands. 'help <command>' gives a brief description of <command>.\n\n"); + + for (c = cmdtab, nCmds2Print=0; c->c_name != NULL; c++) + if (!c->c_hidden || showall) + nCmds2Print++; + + if ((cmdnames = (char **) malloc(sizeof(char *) * nCmds2Print)) == NULL) + fatal("out of memory!"); + + for (c = cmdtab, i=0, widestName=0; c->c_name != NULL; c++) { + if (!c->c_hidden || showall) { + cmdnames[i++] = c->c_name; + len = (int) strlen(c->c_name); + if (len > widestName) + widestName = len; + } + } + + if ((cp = getenv("COLUMNS")) == NULL) + screenColumns = 80; + else + screenColumns = atoi(cp); + + widestName += 2; /* leave room for white-space in between cols. */ + nCols = screenColumns / widestName; + /* if ((screenColumns % widestName) > 0) nCols++; */ + nRows = nCmds2Print / nCols; + if ((nCmds2Print % nCols) > 0) + nRows++; + + (void) sprintf(spec, "%%-%ds", widestName); + for (i=0; i<nRows; i++) { + for (j=0; j<nCols; j++) { + k = nRows*j + i; + if (k < nCmds2Print) + (void) printf(spec, cmdnames[k]); + } + (void) printf("\n"); + } + Free(cmdnames); + } else if (helpall) { + /* Really intended to debug the help strings. */ + for (c = cmdtab; c->c_name != NULL; c++) { + cmd_help(c); + cmd_usage(c); + } + } else while (--argc > 0) { + arg = *++argv; + c = getcmd(arg); + if (c == (struct cmd *)-1) + (void) printf("?Ambiguous help command %s\n", arg); + else if (c == (struct cmd *)0) + (void) printf("?Invalid help command %s\n", arg); + else { + cmd_help(c); + cmd_usage(c); + } + } + return NOERR; +} /* help */ + + +/* + * If the user wants to, s/he can specify the maximum size of the log + * file, so it doesn't waste too much disk space. If the log is too + * fat, trim the older lines (at the top) until we're under the limit. + */ +void trim_log(void) +{ + FILE *new, *old; + struct stat st; + long fat; + string tmplogname, str; + + if (logsize <= 0 || *logfname == 0 || stat(logfname, &st) || + (old = fopen(logfname, "r")) == NULL) + return; /* never trim, or no log */ + fat = st.st_size - logsize; + if (fat <= 0L) return; /* log too small yet */ + while (fat > 0L) { + if (FGets(str, old) == NULL) return; + fat -= (long) strlen(str); + } + /* skip lines until a new site was opened */ + while (1) { + if (FGets(str, old) == NULL) { + (void) fclose(old); + (void) unlink(logfname); + return; /* nothing left, start anew */ + } + if (*str != '\t') break; + } + + /* copy the remaining lines in "old" to "new" */ + (void) Strncpy(tmplogname, logfname); + tmplogname[strlen(tmplogname) - 1] = 'T'; + if ((new = fopen(tmplogname, "w")) == NULL) { + (void) PERROR("trim_log", tmplogname); + return; + } + (void) fputs(str, new); + while (FGets(str, old)) + (void) fputs(str, new); + (void) fclose(old); (void) fclose(new); + if (unlink(logfname) < 0) + PERROR("trim_log", logfname); + if (rename(tmplogname, logfname) < 0) + PERROR("trim_log", tmplogname); +} /* trim_log */ + + + + +int CheckNewMail(void) +{ + struct stat stbuf; + + if (*mail_path == '\0') return 0; + if (stat(mail_path, &stbuf) < 0) { /* cant find mail_path so we'll */ + *mail_path = '\0'; /* never check it again */ + return 0; + } + + /* + * Check if the size is non-zero and the access time is less than + * the modify time -- this indicates unread mail. + */ + if ((stbuf.st_size != 0) && (stbuf.st_atime <= stbuf.st_mtime)) { + if (stbuf.st_mtime > mbox_time) { + (void) printf("%s\n", NEWMAILMESSAGE); + mbox_time = stbuf.st_mtime; + } + return 1; + } + + return 0; +} /* CheckNewMail */ + + + +#ifdef CURSES +int termcap_get(char **dest, char *attr) +{ + static char area[1024]; + static char *s = area; + char *buf, *cp; + int i, result = -1; + int len = 0; + + *dest = NULL; + while (*attr != '\0') { + buf = tgetstr(attr, &s); + if (buf != NULL && buf[0] != '\0') { + for (i = 0; (buf[i] <= '9') && (buf[i] >= '0'); ) + i++; + /* Get rid of the terminal delays, like "$<2>". */ + if ((cp = strstr(&(buf[i]), "$<")) != NULL) + *cp = 0; + if (*dest == NULL) + *dest = (char *)malloc(strlen(&(buf[i])) + 1); + else + *dest = (char *)realloc(*dest, len + strlen(&(buf[i])) + 1); + if (*dest == NULL) + break; + (void) strcpy(*dest + len, &(buf[i])); + len += strlen (&(buf[i])); + } + attr += 2; + } + if (*dest == NULL) + *dest = ""; + else + result = 0; + return (result); +} /* termcap_get */ + + + +void termcap_init(void) +{ + char *term; + + if ((term = getenv("TERM")) == NULL) { + term = "dumb"; /* TAR */ + ansi_escapes = 0; + } + if (tgetent(tcbuf,term) != 1) { + (void) fprintf(stderr,"Can't get termcap entry for terminal [%s]\n", term); + } else { + (void) termcap_get(&tcap_normal, "meuese"); + if (termcap_get(&tcap_boldface, "md") < 0) { + /* Dim-mode is better than nothing... */ + (void) termcap_get(&tcap_boldface, "mh"); + } + (void) termcap_get(&tcap_underline, "us"); + (void) termcap_get(&tcap_reverse, "so"); + tcl_normal = strlen(tcap_normal); + tcl_bold = strlen(tcap_boldface); + tcl_uline = strlen(tcap_underline); + tcl_rev = strlen(tcap_reverse); + } + +} /* termcap_init */ + + + +static int c_output(int c) +{ + return (putchar(c)); +} /* c_output */ + + + + +void tcap_put(char *cap) +{ + tputs(cap, 0, c_output); +} /* tcap_put */ + +#endif /* CURSES */ + +/* eof main.c */ + |