X (void) fix_options(); /* adjust "options" according to "debug" */
X
X fromatty = isatty(fileno(stdin));
X cpend = 0; /* no pending replies */
X
X if (*logfname)
X logf = fopen (logfname, "a");
X
X eventnumber = 0L;
X /* The user specified a host on the command line. Open it now... */
X if (argc > 1 && cp) {
X if (setjmp(toplevel))
X exit(0);
X (void) signal(SIGINT, intr);
X (void) signal(SIGPIPE, lostpeer);
X (void) strcpy(line, oline);
X makeargv();
X (void) setpeer(margc, margv);
X }
X
X (void) init_prompt();
X
X eventnumber = 1L;
X if (ansi_escapes) {
X#ifndef CURSES
X (void) printf("%s%s Ready.%s\n",
X tcap_boldface, FTP_VERSION, tcap_normal);
X#else
X string vis;
X (void) sprintf(vis, "%s%s Ready.%s\n",
X tcap_boldface, FTP_VERSION, tcap_normal);
X tcap_put(vis);
X#endif /* !CURSES */
X }
X else
X (void) printf("%s Ready.\n", FTP_VERSION);
X top = setjmp(toplevel) == 0;
X if (top) {
X (void) signal(SIGINT, intr);
X (void) signal(SIGPIPE, lostpeer);
X }
X for (;;) {
X (void) cmdscanner(top);
X top = 1;
X }
X} /* main */
X
X
X
X/*ARGSUSED*/
Xvoid intr(int unused)
X{
X (void) longjmp(toplevel, 1);
X} /* intr */
X
X
X
Xint getuserinfo(void)
X{
X register char *cp;
X struct passwd *pw = NULL;
X string str;
X extern char *home; /* for glob.c */
X
X cp = getlogin();
X if (cp != NULL)
X pw = getpwnam(cp);
X if (pw == NULL)
X pw = getpwuid(getuid());
X if (pw != NULL) {
X (void) Strncpy(uinfo.username, pw->pw_name);
X (void) Strncpy(uinfo.shell, pw->pw_shell);
X (void) Strncpy(uinfo.homedir, pw->pw_dir);
X uinfo.uid = pw->pw_uid;
X home = uinfo.homedir; /* for glob.c */
X if (((cp = getenv("MAIL")) == NULL) && ((cp = getenv("mail")) == NULL)) {
X (void) sprintf(str, "/usr/spool/mail/%s", uinfo.username);
X cp = str;
X }
X /* mbox variable may be like MAIL=(28 /usr/mail/me /usr/mail/you),
X so try to find the first mail path. */
X while (*cp != '/')
X cp++;
X (void) Strncpy(mail_path, cp);
X if ((cp = index(mail_path, ' ')) != NULL)
X *cp = '\0';
X return (0);
X } else {
X (void) Strncpy(uinfo.username, "unknown");
X (void) Strncpy(uinfo.shell, "/bin/sh");
X (void) Strncpy(uinfo.homedir, "."); /* current directory */
X uinfo.uid = 999;
X return (-1);
X }
X} /* getuserinfo */
X
X
X
X
Xint init_arrays(void)
X{
X if ((macbuf = (char *) malloc((size_t)(MACBUFLEN))) == NULL)
X goto barf;
X if ((line = (char *) malloc((size_t)(CMDLINELEN))) == NULL)
X goto barf;
X if ((argbuf = (char *) malloc((size_t)(CMDLINELEN))) == NULL)
X goto barf;
X if ((reply_string = (char *) malloc((size_t)(RECEIVEDLINELEN))) == NULL)
X goto barf;
X
X *macbuf = '\0';
X init_transfer_buffer();
X return (0);
Xbarf:
X return (-1);
X} /* init_arrays */
X
X
X
X#ifndef BUFSIZ
X#define BUFSIZ 512
X#endif
X
Xvoid init_transfer_buffer(void)
X{
X extern char *xferbuf;
X extern size_t xferbufsize;
X
X /* Make sure we use a multiple of BUFSIZ for efficiency. */
X xferbufsize = (MAX_XFER_BUFSIZE / BUFSIZ) * BUFSIZ;
X while (1) {
X xferbuf = (char *) malloc (xferbufsize);
X if (xferbuf != NULL || xferbufsize < 1024)
X break;
X xferbufsize >>= 2;
X }
X
X if (xferbuf != NULL) return;
X fatal("out of memory for transfer buffer.");
X} /* init_transfer_buffer */
X
X
X
X
Xvoid init_prompt(void)
X{
X register char *cp;
X
X percent_flags = at_flags = 0;
X for (cp = prompt; *cp; cp++) {
X if (*cp == '%') percent_flags = 1;
X else if (*cp == '@') at_flags = 1;
X }
X} /* init_prompt */
X
X
X
X/*ARGSUSED*/
Xvoid lostpeer(int unused)
X{
X if (connected) {
X close_streams(1);
X if (data >= 0) {
X (void) shutdown(data, 1+1);
X (void) close(data);
X data = -1;
X }
X connected = 0;
X }
X if (connected) {
X close_streams(1);
X connected = 0;
X }
X hostname[0] = cwd[0] = 0;
X macnum = 0;
X} /* lostpeer */
X
X
X
X/*
X * Command parser.
X */
Xvoid cmdscanner(int top)
X{
X register struct cmd *c;
X#ifdef CURSES
X string vis, *vp;
X#endif
X
X if (!top)
X (void) putchar('\n');
X for (;;) {
X if (fromatty) {
X#ifndef CURSES
X (void) printf(strprompt());
X#else
X (void) Strncpy(vis, (strprompt()));
X tcap_put(vis);
X#endif /* !CURSES */
X (void) fflush(stdout);
X }
X if (Gets(line, (size_t)CMDLINELEN) == 0) {
X if (feof(stdin) || ferror(stdin))
X (void) quit(0, NULL); /* control-d */
X break;
X }
X if (line[0] == 0) /* blank line */
X break;
X eventnumber++;
X if (debug > 1)
X (void) printf("---> \"%s\"\n", line);
X (void) makeargv();
X if (margc == 0) {
X continue; /* blank line... */
X }
X c = getcmd(margv[0]);
X if (c == (struct cmd *) -1) {
X (void) printf("?Ambiguous command\n");
X continue;
X }
X if (c == 0) {
X if (!implicit_cd(margv[0]))
X (void) printf("?Invalid command\n");
X continue;
X }
X if (c->c_conn && !connected) {
X (void) printf ("Not connected.\n");
X continue;
X }
X (*c->c_handler)(margc, margv);
X if (c->c_handler != help)
X break;
X }
X (void) signal(SIGINT, intr);
X (void) signal(SIGPIPE, lostpeer);
X} /* cmdscanner */
X
X
X
X
Xchar *strprompt(void)
X{
X time_t tyme;
X char eventstr[8];
X register char *p, *q;
X string str;
X#ifdef CURSES
X static int virgin = 0;
X
X if (!virgin++ && ansi_escapes)
X termcap_init();
X#endif /* CURSES */
X
X
X if (at_flags == 0 && percent_flags == 0)
X return (prompt); /* But don't overwrite it! */
X
X if (at_flags) {
X for (p = prompt, q = prompt2, *q = 0; (*p); p++)
X if (*p == '@') switch (islower(*p) ? (toupper(*++p)) : (*++p)) {
X case '\0':
X --p;
X break;
X case 'M':
X if (CheckNewMail() > 0)
X q = Strpcpy(q, "(Mail) ");
X break;
X case 'N':
X q = Strpcpy(q, "\n");
X break;
X case 'P': /* reset to no bold, no uline, no inverse, etc. */
X if (ansi_escapes)
X q = Strpcpy(q, tcap_normal);
X break;
X case 'B': /* toggle boldface */
X if (ansi_escapes)
X q = Strpcpy(q, tcap_boldface);
X break;
X case 'U': /* toggle underline */
X if (ansi_escapes)
X q = Strpcpy(q, tcap_underline);
X break;
X case 'R':
X case 'I': /* toggle inverse (reverse) video */
X if (ansi_escapes)
X q = Strpcpy(q, tcap_reverse);
X break;
X case 'D': /* insert current directory */
X if (cwd != NULL)
X q = Strpcpy(q, cwd);
X break;
X case 'H': /* insert name of connected host */
X if (hostname != NULL)
X q = Strpcpy(q, hostname);
X break;
X case '!':
X case 'E': /* insert event number */
X (void) sprintf(eventstr, "%ld", eventnumber);
X q = Strpcpy(q, eventstr);
X break;
X default:
X *q++ = *p; /* just copy it; unknown switch */
X } else
X *q++ = *p;
X *q = '\0';
X } else
X (void) strcpy(prompt2, prompt);
X
X if (percent_flags) {
X /* only strftime if the user requested it (with a %something),
X otherwise don't waste time doing nothing. */
X (void) time(&tyme);
X (void) Strncpy(str, prompt2);
X (void) strftime(prompt2, sizeof(str), str, localtime(&tyme));
X }
X return (prompt2);
X} /* strprompt */
X
X
X
Xchar *Strpcpy(char *dst, char *src)
X{
X while (*dst++ = *src++)
X ;
X return (--dst); /* return current value of dst, NOT original value! */
X} /* Strpcpy */
X
X
X
X
Xstruct cmd *getcmd(char *name)
X{
X register char *p, *q;
X register struct cmd *c, *found;
X register int nmatches, longest;
X
X if (name == NULL)
X return (NULL);
X longest = 0;
X nmatches = 0;
X found = 0;
X for (c = cmdtab; p = c->c_name; c++) {
X for (q = name; *q == *p++; q++)
X if (*q == 0) /* exact match? */
X return (c);
X if (!*q) { /* the name was a prefix */
X if (q - name > longest) {
X longest = q - name;
X nmatches = 1;
X found = c;
X } else if (q - name == longest)
X nmatches++;
X }
X }
X if (nmatches > 1)
X return ((struct cmd *)-1);
X return (found);
X} /* getcmd */
X
X
X
X
X/*
X * Slice a string up into argc/argv.
X */
X
Xvoid makeargv(void)
X{
X char **argp;
X
X margc = 0;
X argp = margv;
X stringbase = line; /* scan from first of buffer */
X argbase = argbuf; /* store from first of buffer */
X slrflag = 0;
X while (*argp++ = slurpstring())
X margc++;
X} /* makeargv */
X
X
X
X
X/*
X * Parse string into argbuf;
X * implemented with FSM to
X * handle quoting and strings
X */
Xchar *slurpstring(void)
X{
X int got_one = 0;
X register char *sb = stringbase;
X register char *ap = argbase;
X char *tmp = argbase; /* will return this if token found */
X
X if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
X switch (slrflag) { /* and $ as token for macro invoke */
X case 0:
X slrflag++;
X stringbase++;
X return ((*sb == '!') ? "!" : "$");
X /* NOTREACHED */
X case 1:
X slrflag++;
X altarg = stringbase;
X break;
X default:
X break;
X }
X }
X
XS0:
X switch (*sb) {
X
X case '\0':
X goto OUT;
X
X case ' ':
X case '\t':
X case '\n':
X case '=':
X sb++; goto S0;
X
X default:
X switch (slrflag) {
X case 0:
X slrflag++;
X break;
X case 1:
X slrflag++;
X altarg = sb;
X break;
X default:
X break;
X }
X goto S1;
X }
X
XS1:
X switch (*sb) {
X
X case ' ':
X case '\t':
X case '\n':
X case '=':
X case '\0':
X goto OUT; /* end of token */
X
X case '\\':
X sb++; goto S2; /* slurp next character */
X
X case '"':
X sb++; goto S3; /* slurp quoted string */
X
X default:
X *ap++ = *sb++; /* add character to token */
X got_one = 1;
X goto S1;
X }
X
XS2:
X switch (*sb) {
X
X case '\0':
X goto OUT;
X
X default:
X *ap++ = *sb++;
X got_one = 1;
X goto S1;
X }
X
XS3:
X switch (*sb) {
X
X case '\0':
X goto OUT;
X
X case '"':
X sb++; goto S1;
X
X default:
X *ap++ = *sb++;
X got_one = 1;
X goto S3;
X }
X
XOUT:
X if (got_one)
X *ap++ = '\0';
X argbase = ap; /* update storage pointer */
X stringbase = sb; /* update scan pointer */
X if (got_one) {
X return(tmp);
X }
X switch (slrflag) {
X case 0:
X slrflag++;
X break;
X case 1:
X slrflag++;
X altarg = (char *) 0;
X break;
X default:
X break;
X }
X return((char *)0);
X} /* slurpstring */
X
X
X
X
X#define HELPINDENT (sizeof ("directory"))
X
X/*
X * Help command.
X * Call each command handler with argc == 0 and argv[0] == name.
X */
Xhelp(int argc, char **argv)
X{
X register struct cmd *c;
X int i, showall = 0;
X char *arg;
X
X if (argc == 2)
X showall = strcmp(argv[1], "all") == 0;
X if (argc == 1 || showall) {
X (void) printf("Commands may be abbreviated. 'help all' shows aliases,\ninvisible and unsupported commands. 'help <command>' \ngives a brief description of <command>. Commands are:\n");
X for (c = cmdtab, i=0; c->c_name != NULL; c++) {
X if (c->c_hidden && !showall) continue;
X (void) printf("%-13s", c->c_name);
X if (++i == 6) {
X i = 0;
X putchar('\n');
X }
X }
X if (i < 6)
X putchar('\n');
X } else while (--argc > 0) {
X arg = *++argv;
X c = getcmd(arg);
X if (c == (struct cmd *)-1)
X (void) printf("?Ambiguous help command %s\n", arg);
X else if (c == (struct cmd *)0)
X (void) printf("?Invalid help command %s\n", arg);
X else
X (void) printf("%-*s\t%s\n", HELPINDENT,
X c->c_name, c->c_help);
X }
X} /* help */
X
X
X/*
X * If the user wants to, s/he can specify the maximum size of the log
X * file, so it doesn't waste too much disk space. If the log is too
X * fat, trim the older lines (at the top) until we're under the limit.
X */
Xvoid trim_log(void)
X{
X FILE *new, *old;
X struct stat st;
X long fat;
X string tmplogname, str;
X
X if (logsize <= 0 || *logfname == 0 || stat(logfname, &st) ||
X (old = fopen(logfname, "r")) == NULL)
X return; /* never trim, or no log */
X fat = st.st_size - logsize;
X if (fat <= 0L) return; /* log too small yet */
X while (fat > 0L) {
X if (FGets(str, old) == NULL) return;
X fat -= (long) strlen(str);
X }
X /* skip lines until a new site was opened */
X while (1) {
X if (FGets(str, old) == NULL) {
X (void) fclose(old);
X (void) unlink(logfname);
X return; /* nothing left, start anew */
X }
X if (*str != '\t') break;
X }
X
X /* copy the remaining lines in "old" to "new" */
X (void) Strncpy(tmplogname, logfname);
X tmplogname[strlen(tmplogname) - 1] = 'T';
X if ((new = fopen(tmplogname, "w")) == NULL) {
X (void) Perror(tmplogname);
X return;
X }
X (void) fputs(str, new);
X while (FGets(str, old))
X (void) fputs(str, new);
X (void) fclose(old); (void) fclose(new);
X if (unlink(logfname) < 0)
X Perror(logfname);
X if (rename(tmplogname, logfname) < 0)
X Perror(tmplogname);
X} /* trim_log */
X
X
X
X
Xint CheckNewMail(void)
X{
X struct stat stbuf;
X
X if (*mail_path == '\0') return 0;
X if (stat(mail_path, &stbuf) < 0) { /* cant find mail_path so we'll */
X *mail_path = '\0'; /* never check it again */
X return 0;
X }
X
X if (stbuf.st_mtime > mbox_time) {
X newmail++;
X (void) printf("%s\n", NEWMAILMESSAGE);
X (void) time(&mbox_time); /* only notify once. */
X }
X
X return newmail;
X} /* CheckNewMail */
X
X
X#ifdef CURSES
Xvoid termcap_init(void)
X{
X static char area[1024];
X static char *s = area;
X char *tgetstr(char *, char **);
X char *term;
X
X if (tgetent(tcbuf,(term = getenv("TERM"))) != 1) {
X (void) fprintf(stderr,"Can't get termcap entry for terminal [%s]\n", term);
X } else {
X if (!(tcap_normal = tgetstr("se", &s)))
X tcap_normal = "";
X if (!(tcap_boldface = tgetstr("md", &s)))
X tcap_boldface = "";
X if (!(tcap_underline = tgetstr("us", &s)))
X tcap_underline = "";
X if (!(tcap_reverse = tgetstr("so", &s)))
X tcap_reverse = "";
X }
X} /* termcap_init */
X
X
X
Xstatic int c_output(int c)
X{
X putchar(c);
X} /* c_output */
X
X
X
X
Xvoid tcap_put(char *cap)
X{
X tputs(cap, 0, c_output);
X} /* tcap_put */
X
X#endif /* CURSES */
X
X/* eof main.c */
END_OF_FILE
if test 19081 -ne `wc -c <'main.c'`; then
echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
echo shar: End of archive 2 \(of 4\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 4 archives.
rm -f ark[1-9]isdone
else
echo You still must unpack the following archives: