static char sccsid
[] = "@(#)lex.c 2.14 (Berkeley) %G%";
* Lexical processing of commands.
* Set up editing on the given file name.
* If isedit is true, we are considered to be editing the file,
* otherwise we are reading our mail which has signficance for
if ((ibuf
= fopen(name
, "r")) == NULL
)
* Looks like all will be well. We must now relinquish our
* hold on the current set of stuff. Must hold signals
* while we are reading the new file, else we will ruin
* the message[] data structure.
* Copy the messages into /tmp
if ((i
= open(name
, 1)) < 0)
strncpy(efile
, name
, 128);
if ((otf
= fopen(tempMesg
, "w")) == NULL
) {
if ((itf
= fopen(tempMesg
, "r")) == NULL
) {
* Interpret user commands one by one. If standard input is not a tty,
int eofloop
, shudprompt
, stop();
sigset(SIGCONT
, SIG_DFL
);
if (rcvmode
&& !sourcing
) {
if (sigset(SIGINT
, SIG_IGN
) != SIG_IGN
)
if (sigset(SIGHUP
, SIG_IGN
) != SIG_IGN
)
shudprompt
= intty
&& !sourcing
;
* Print the prompt, if needed. Clear out
* string space, and flush the output.
if (!rcvmode
&& !sourcing
)
* Read a line of commands from the current input
* and handle end of file specially.
if (readline(input
, &linebuf
[n
]) <= 0) {
if (value("ignoreeof") != NOSTR
&& shudprompt
) {
printf("Use \"quit\" to quit.\n");
if ((n
= strlen(linebuf
)) == 0)
sigset(SIGCONT
, SIG_DFL
);
* Execute a single command. If the command executed
* is "quit," then return non-zero so that the caller
* will know to return back to main, if he cares.
* Contxt is non-zero if called while composing mail.
* Strip the white space away from the beginning
* of the command, then scan out a word, which
* consists of anything except digits and white space.
* Handle ! escapes differently to get the correct
printf("Can't \"!\" while sourcing\n");
while (*cp
&& !any(*cp
, " \t0123456789$^.:/-+*'\""))
* Look up the command; if not found, bitch.
* Normally, a blank command would map to the
* first command in the table; while sourcing,
* however, we ignore blank lines to eliminate
if (sourcing
&& equal(word
, ""))
printf("Unknown command: \"%s\"\n", word
);
* See if we should execute the command -- if a conditional
* we always execute it, otherwise, check the state of cond.
if ((com
->c_argtype
& F
) == 0)
if (cond
== CRCV
&& !rcvmode
|| cond
== CSEND
&& rcvmode
)
* Special case so that quit causes a return to
* main, who will call the quit code directly.
* If we are in a source file, just unstack.
if (com
->c_func
== edstop
&& sourcing
) {
if (!edit
&& com
->c_func
== edstop
) {
* Process the arguments to the command, depending
* on the type he expects. Default to an error.
* If we are sourcing an interactive command, it's
if (!rcvmode
&& (com
->c_argtype
& M
) == 0) {
printf("May not execute \"%s\" while sending\n",
if (sourcing
&& com
->c_argtype
& I
) {
printf("May not execute \"%s\" while sourcing\n",
if (readonly
&& com
->c_argtype
& W
) {
printf("May not execute \"%s\" -- message file is read only\n",
if (contxt
&& com
->c_argtype
& R
) {
printf("Cannot recursively invoke \"%s\"\n", com
->c_name
);
switch (com
->c_argtype
& ~(F
|P
|I
|M
|T
|W
|R
)) {
* A message list defaulting to nearest forward
printf("Illegal use of \"message list\"\n");
if ((c
= getmsglist(cp
, msgvec
, com
->c_msgflag
)) < 0)
*msgvec
= first(com
->c_msgflag
,
printf("No applicable messages\n");
e
= (*com
->c_func
)(msgvec
);
* A message list with no defaults, but no error
printf("Illegal use of \"message list\"\n");
if (getmsglist(cp
, msgvec
, com
->c_msgflag
) < 0)
e
= (*com
->c_func
)(msgvec
);
* Just the straight string, with
* leading blanks removed.
* A vector of strings, in shell style.
if ((c
= getrawlist(cp
, arglist
)) < 0)
if (c
< com
->c_minargs
) {
printf("%s requires at least %d arg(s)\n",
com
->c_name
, com
->c_minargs
);
if (c
> com
->c_maxargs
) {
printf("%s takes no more than %d arg(s)\n",
com
->c_name
, com
->c_maxargs
);
e
= (*com
->c_func
)(arglist
);
* Just the constant zero, for exiting,
panic("Unknown argtype");
* Exit the current source file on
if (com
->c_func
== edstop
)
if (value("autoprint") != NOSTR
&& com
->c_argtype
& P
)
if ((dot
->m_flag
& MDELETED
) == 0) {
muvec
[0] = dot
- &message
[0] + 1;
if (!sourcing
&& (com
->c_argtype
& T
) == 0)
* When we wake up after ^Z, reprint the prompt.
* Branch here on hangup signal and simulate quit.
* Set the size of the message vector used to construct argument
* lists to message list functions.
msgvec
= (int *) calloc((unsigned) (sz
+ 1), sizeof *msgvec
);
* Find the correct command in the command table corresponding
* to the passed command "word"
extern struct cmd cmdtab
[];
for (cp
= &cmdtab
[0]; cp
->c_name
!= NOSTR
; cp
++)
if (isprefix(word
, cp
->c_name
))
* Determine if as1 is a valid prefix of as2.
* The following gets called on receipt of a rubout. This is
* to abort printout of a command, mainly.
* Dispatching here when command() is inactive crashes rcv.
* Close all open files except 0, 1, 2, and the temporary.
* The special call to getuserid() is needed so it won't get
* annoyed about losing its open file.
* Also, unstack all source files.
int inithdr
; /* am printing startup headers */
for (fp
= &_iob
[0]; fp
< &_iob
[_NFILE
]; fp
++) {
if (fp
== stdin
|| fp
== stdout
)
if (fp
== itf
|| fp
== otf
)
* Announce the presence of the current Mail version,
* give the message count, and print a header listing.
char *greeting
= "Mail version %s. Type ? for help.\n";
if (pr
&& value("quiet") == NOSTR
)
printf(greeting
, version
);
dot
= &message
[mdot
- 1];
if (msgCount
> 0 && !noheader
) {
* Announce information about the file we are editing.
* Return a likely place to set dot.
register struct message
*mp
;
register int u
, n
, mdot
, d
, s
;
char fname
[BUFSIZ
], zname
[BUFSIZ
], *ename
;
for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
if (mp
>= &message
[msgCount
])
for (mp
= &message
[0]; mp
< &message
[msgCount
]; mp
++)
if ((mp
->m_flag
& MREAD
) == 0)
if (mp
< &message
[msgCount
])
mdot
= mp
- &message
[0] + 1;
for (mp
= &message
[0], n
= 0, u
= 0; mp
< &message
[msgCount
]; mp
++) {
if ((mp
->m_flag
& MREAD
) == 0)
if (mp
->m_flag
& MDELETED
)
if (getfold(fname
) >= 0) {
if (strncmp(fname
, mailname
, strlen(fname
)) == 0) {
sprintf(zname
, "+%s", mailname
+ strlen(fname
));
printf("\"%s\": ", ename
);
printf("%d messages", msgCount
);
printf(" %d deleted", d
);
* Print the current version number.
printf("Version %s\n", version
);
* Load a file of user definitions.
register FILE *in
, *oldin
;
if ((in
= fopen(name
, "r")) == NULL
)