summaryrefslogtreecommitdiffstats
path: root/usr.bin/ncftp/main.c
diff options
context:
space:
mode:
authorache <ache@FreeBSD.org>1994-09-22 23:45:37 +0000
committerache <ache@FreeBSD.org>1994-09-22 23:45:37 +0000
commit41cb9decc65e51e29f0eb6fe06bcb3594726bd6b (patch)
tree31cb31bfb69915fc791ce9c2ec7d345124bedebf /usr.bin/ncftp/main.c
downloadFreeBSD-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.c1128
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 */
+
OpenPOWER on IntegriCloud