diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1994-05-27 12:33:43 +0000 |
commit | f9ab90d9d6d02989a075d0f0074496d5b1045e4b (patch) | |
tree | add7e996bac5289cdc55e6935750c352505560a9 /usr.bin/mail | |
parent | be22b15ae2ff8d7fe06b6e14fddf0c5b444a95da (diff) | |
download | FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.zip FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.tar.gz |
BSD 4.4 Lite Usr.bin Sources
Diffstat (limited to 'usr.bin/mail')
45 files changed, 13605 insertions, 0 deletions
diff --git a/usr.bin/mail/Makefile b/usr.bin/mail/Makefile new file mode 100644 index 0000000..576ce83 --- /dev/null +++ b/usr.bin/mail/Makefile @@ -0,0 +1,19 @@ +# @(#)Makefile 8.2 (Berkeley) 1/25/94 + +PROG= mail +CFLAGS+=-R -DUSE_OLD_TTY +SRCS= version.c aux.c cmd1.c cmd2.c cmd3.c cmdtab.c collect.c edit.c fio.c \ + getname.c head.c v7.local.c lex.c list.c main.c names.c popen.c \ + quit.c send.c strings.c temp.c tty.c vars.c +SFILES= mail.help mail.tildehelp +EFILES= mail.rc +LINKS= ${BINDIR}/mail ${BINDIR}/Mail +MLINKS= mail.1 Mail.1 + +beforeinstall: + cd ${.CURDIR}/misc; install -c -o ${BINOWN} -g ${BINGRP} \ + -m 444 ${SFILES} ${DESTDIR}/usr/share/misc + cd ${.CURDIR}/misc; install -c -o root -g wheel \ + -m 644 ${EFILES} ${DESTDIR}/etc + +.include <bsd.prog.mk> diff --git a/usr.bin/mail/USD.doc/Makefile b/usr.bin/mail/USD.doc/Makefile new file mode 100644 index 0000000..b31b448 --- /dev/null +++ b/usr.bin/mail/USD.doc/Makefile @@ -0,0 +1,11 @@ +# @(#)Makefile 8.1 (Berkeley) 6/8/93 + +DIR= usd/07.mail +SRCS= mail0.nr mail1.nr mail2.nr mail3.nr mail4.nr mail5.nr mail6.nr \ + mail7.nr mail8.nr mail9.nr maila.nr +MACROS= -me + +paper.ps: ${SRCS} + ${TBL} ${SRCS} | ${ROFF} > ${.TARGET} + +.include <bsd.doc.mk> diff --git a/usr.bin/mail/USD.doc/mail0.nr b/usr.bin/mail/USD.doc/mail0.nr new file mode 100644 index 0000000..15955be --- /dev/null +++ b/usr.bin/mail/USD.doc/mail0.nr @@ -0,0 +1,71 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail0.nr 8.1 (Berkeley) 6/8/93 +.\" +.eh 'USD:7-%''Mail Reference Manual' +.oh 'Mail Reference Manual''USD:7-%' +.if n \ +.nr fs .5v +.\".he 'Mail Reference Manual'\n(mo/\n(dy/\n(yr'%' +.tp +.sp 1.0i +.sz 12 +.rb +.(l C +MAIL REFERENCE MANUAL +.)l +.sz 10 +.sp 2 +.i +.(l C +Kurt Shoens +.)l +.r +.(l C +Revised by +.)l +.(l C +.i +Craig Leres\ \c +.r +and\ \c +.i +Mark Andrews +.)l +.r +.(l C +Version 5.5 + + +\*(td +.)l +.pn 2 diff --git a/usr.bin/mail/USD.doc/mail1.nr b/usr.bin/mail/USD.doc/mail1.nr new file mode 100644 index 0000000..bbb920d --- /dev/null +++ b/usr.bin/mail/USD.doc/mail1.nr @@ -0,0 +1,92 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail1.nr 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 Introduction +.pp +.i Mail +provides a simple and friendly environment for sending and receiving mail. +It divides incoming mail into +its constituent messages and allows the user to deal with them +in any order. In addition, it provides a set of +.i ed -\c +like commands for manipulating messages and sending mail. +.i Mail +offers the user simple editing capabilities to ease the composition +of outgoing messages, as well as providing the ability to define and send +to names which address groups of users. Finally, +.i Mail +is able to send and receive messages across such networks as the +ARPANET, UUCP, and Berkeley network. +.pp +This document describes how to use the +.i Mail +program to send and receive messages. The reader is not assumed to +be familiar with other message handling systems, but should be +familiar with the \s-2UNIX\s0\** +.(f +\** \s-1UNIX\s0 is a trademark of Bell Laboratories. +.)f +shell, the text editor, and some of the common \s-2UNIX\s0 commands. +.q "The \s-2UNIX\s0 Programmer's Manual," +.q "An Introduction to Csh," +and +.q "Text Editing with Ex and Vi" +can be consulted for more information on these topics. +.pp +Here is how messages are handled: +the mail system accepts incoming +.i messages +for you from other people +and collects them in a file, called your +.i "system mailbox" . +When you login, the system notifies you if there are any messages +waiting in your system mailbox. If you are a +.i csh +user, you will be notified when new mail arrives if you inform +the shell of the location of your mailbox. On version 7 systems, +your system mailbox is located in the directory /usr/spool/mail +in a file with your login name. If your login name is +.q sam, +then you can make +.i csh +notify you of new mail by including the following line in your .cshrc +file: +.(l +set mail=/usr/spool/mail/sam +.)l +When you read your mail using +.i Mail , +it reads your system mailbox and separates that file into the +individual messages that have been sent to you. You can then +read, reply to, delete, or save these messages. +Each message is marked with its author and the date they sent it. diff --git a/usr.bin/mail/USD.doc/mail2.nr b/usr.bin/mail/USD.doc/mail2.nr new file mode 100644 index 0000000..f64aaa6 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail2.nr @@ -0,0 +1,617 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail2.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Common usage" +.pp +The +.i Mail +command has two distinct usages, according to whether one +wants to send or receive mail. Sending mail is simple: to send a +message to a user whose login name is, say, +\*(lqroot,\*(rq +use the shell +command: +.(l +% Mail root +.)l +then type your message. When you reach the end of the message, type +an EOT (control\-d) at the beginning of a line, which will cause +.i Mail +to echo \*(lqEOT\*(rq and return you to the Shell. When the user you sent mail +to next logs in, he will receive the message: +.(l +You have mail. +.)l +to alert him to the existence of your message. +.pp +If, while you are composing the message +you decide that you do not wish to send it after all, you can +abort the letter with a \s-2RUBOUT\s0. Typing a single \s-2RUBOUT\s0 +causes +.i Mail +to print +.(l +(Interrupt -- one more to kill letter) +.)l +Typing a second +\s-2RUBOUT\s0 causes +.i Mail +to save your partial letter on the file +.q dead.letter +in your home directory and abort the letter. +Once you have +sent mail to someone, there is no way to undo the act, so be +careful. +.pp +The message your recipient reads will consist of the message you +typed, preceded by a line telling who sent the message (your login name) +and the date and time it +was sent. +.pp +If you want to send the same message to several other people, you can list +their login names on the command line. +Thus, +.(l +% Mail sam bob john +Tuition fees are due next Friday. Don't forget!! +<Control\-d> +EOT +% +.)l +will send the reminder to sam, bob, and john. +.pp +If, when you log in, you see the message, +.(l +You have mail. +.)l +you can read the mail by typing simply: +.(l +% Mail +.)l +.i Mail +will respond by typing its version number and date and then listing +the messages you have waiting. Then it will type a prompt and await +your command. The messages are assigned numbers starting with 1 \*- you +refer to the messages with these numbers. +.i Mail +keeps track of which messages are +.i new +(have been sent since you last read your mail) and +.i read +(have been read by you). New messages have an +.b N +next to them in the header listing and old, but unread messages have +a +.b U +next to them. +.i Mail +keeps track of new/old and read/unread messages by putting a +header field called +.q Status +into your messages. +.pp +To look at a specific message, use the +.b type +command, which may be abbreviated to simply +.b t . +For example, if you had the following messages: +.(l +N 1 root Wed Sep 21 09:21 "Tuition fees" +N 2 sam Tue Sep 20 22:55 +.)l +you could examine the first message by giving the command: +.(l +type 1 +.)l +which might cause +.i Mail +to respond with, for example: +.(l +Message 1: +From root Wed Sep 21 09:21:45 1978 +Subject: Tuition fees +Status: R + +Tuition fees are due next Wednesday. Don't forget!! + +.)l +Many +.i Mail +commands that operate on messages take a message number as an +argument like the +.b type +command. For these commands, there is a notion of a current +message. When you enter the +.i Mail +program, the current message is initially the first one. Thus, +you can often omit the message number and use, for example, +.(l +t +.)l +to type the current message. As a further shorthand, you can type a message +by simply giving its message number. Hence, +.(l +1 +.)l +would type the first message. +.pp +Frequently, it is useful to read the messages in your mailbox in order, +one after another. You can read the next message in +.i Mail +by simply typing a newline. As a special case, you can type a newline +as your first command to +.i Mail +to type the first message. +.pp +If, after typing a message, you wish to immediately send a reply, +you can do so with the +.b reply +command. +.b Reply , +like +.b type , +takes a message number as an argument. +.i Mail +then begins a message addressed to the user who sent you the message. +You may then type in your letter in reply, followed by a <control-d> +at the beginning of a line, as before. +.i Mail +will type EOT, then type the ampersand prompt to indicate its readiness +to accept another command. In our example, if, after typing the +first message, you wished to reply to it, you might give the command: +.(l +reply +.)l +.i Mail +responds by typing: +.(l +To: root +Subject: Re: Tuition fees +.)l +and waiting for you to enter your letter. +You are now in the message collection mode described at the beginning +of this section and +.i Mail +will gather up your message up to a control\-d. +Note that it copies the subject +header from the original message. This is useful in that correspondence +about a particular matter will tend to retain the same subject heading, +making it easy to recognize. If there are other header fields in +the message, the information found will also be used. +For example, if the letter had a +.q "To:" +header listing several recipients, +.i Mail +would arrange to send your replay to the same people as well. +Similarly, if the original message contained a +.q "Cc:" +(carbon copies to) field, +.i Mail +would send your reply to +.i those +users, too. +.i Mail +is careful, though, not too send the message to +.i you , +even if you appear in the +.q "To:" +or +.q "Cc:" +field, unless you ask to be included explicitly. See section 4 for more +details. +.pp +After typing in your letter, the dialog with +.i Mail +might look like the following: +.(l +reply +To: root +Subject: Tuition fees + +Thanks for the reminder +EOT +& +.)l +.pp +The +.b reply +command is especially useful for sustaining extended conversations +over the message system, with other +.q listening +users receiving copies of the conversation. The +.b reply +command can be abbreviated to +.b r . +.pp +Sometimes you will receive a message that has been sent to +several people and wish to reply +.i only +to the person who sent it. +.b Reply +with a capital +.b R +replies to a message, but sends a copy to the sender only. +.pp +If you wish, while reading your mail, to send a message to someone, +but not as a reply to one of your messages, you can send the message +directly with the +.b mail +command, which takes as arguments the names of the recipients you wish +to send to. For example, to send a message to +.q frank, +you would do: +.(l +mail frank +This is to confirm our meeting next Friday at 4. +EOT +& +.)l +The +.b mail +command can be abbreviated to +.b m . +.pp +Normally, each message you receive is saved in the file +.i mbox +in your login directory at the time you leave +.i Mail . +Often, +however, you will not want to save a particular message you +have received because it is only of passing interest. To avoid +saving a message in +.i mbox +you can delete it using the +.b delete +command. In our example, +.(l +delete 1 +.)l +will prevent +.i Mail +from saving message 1 (from root) in +.i mbox . +In addition to not saving deleted messages, +.i Mail +will not let +you type them, either. The effect is to make the message disappear +altogether, along with its number. The +.b delete +command can be abbreviated to simply +.b d . +.pp +Many features of +.i Mail +can be tailored to your liking with the +.b set +command. The +.b set +command has two forms, depending on whether you are setting +a +.i binary +option or a +.i valued +option. +Binary options are either on or off. For example, the +.q ask +option informs +.i Mail +that each time you send a message, you want it to prompt you for +a subject header, to be included in the message. +To set the +.q ask +option, you would type +.(l +set ask +.)l +.pp +Another useful +.i Mail +option is +.q hold. +Unless told otherwise, +.i Mail +moves the messages from your system mailbox to the file +.i mbox +in your home directory when you leave +.i Mail . +If you want +.i Mail +to keep your letters in the system mailbox instead, you can set the +.q hold +option. +.pp +Valued options are values which +.i Mail +uses to adapt to your tastes. For example, the +.q SHELL +option tells +.i Mail +which shell you like to use, and is specified by +.(l +set SHELL=/bin/csh +.)l +for example. Note that no spaces are allowed in +.q "SHELL=/bin/csh." +A complete list of the +.i Mail +options appears in section 5. +.pp +Another important valued option is +.q crt. +If you use a fast video terminal, you will find that when you +print long messages, they fly by too quickly for you to read them. +With the +.q crt +option, you can make +.i Mail +print any message larger than a given number of lines by sending +it through a paging program. This program is specified by the +valued option \fBPAGER\fP. +If \fBPAGER\fP is not set, a default paginator is used. +For example, most CRT users with 24-line screens should do: +.(l +set crt=24 +.)l +to paginate messages that will not fit on their screens. +In the default state, \fImore\fP (default paginator) prints a screenful of +information, then types --More--. Type a space to see the next screenful. +.pp +Another adaptation to user needs that +.i Mail +provides is that of +.i aliases . +An alias is simply a name which stands for one or more +real user names. +.i Mail +sent to an alias is really sent to the list of real users +associated with it. For example, an alias can be defined for the +members of a project, so that you can send mail to the whole project +by sending mail to just a single name. The +.b alias +command in +.i Mail +defines an alias. Suppose that the users in a project are +named Sam, Sally, Steve, and Susan. To define an alias called +.q project +for them, you would use the +.i Mail +command: +.(l +alias project sam sally steve susan +.)l +The +.b alias +command can also be used to provide a convenient name for someone +whose user name is inconvenient. For example, if a user named +.q "Bob Anderson" +had the login name +.q anderson," +you might want to use: +.(l +alias bob anderson +.)l +so that you could send mail to the shorter name, +.q bob. +.pp +While the +.b alias +and +.b set +commands allow you to customize +.i Mail , +they have the drawback that they must be retyped each time you enter +.i Mail . +To make them more convenient to use, +.i Mail +always looks for two files when it is invoked. It first reads +a system wide file +.q /usr/lib/Mail.rc, +then a user specific file, +.q .mailrc, +which is found in the user's home directory. +The system wide file +is maintained by the system administrator and +contains +.b set +commands that are applicable to all users of the system. +The +.q .mailrc +file is usually used by each user to set options the way he likes +and define individual aliases. +For example, my .mailrc file looks like this: +.(l +set ask nosave SHELL=/bin/csh +.)l +As you can see, it is possible to set many options in the +same +.b set +command. The +.q nosave +option is described in section 5. +.pp +Mail aliasing is implemented +at the system-wide level +by the mail delivery +system +.i sendmail . +These aliases are stored in the file /usr/lib/aliases and are +accessible to all users of the system. +The lines in /usr/lib/aliases are of +the form: +.(l +alias: name\*<1\*>, name\*<2\*>, name\*<3\*> +.)l +where +.i alias +is the mailing list name and the +.i name\*<i\*> +are the members of the list. Long lists can be continued onto the next +line by starting the next line with a space or tab. Remember that you +must execute the shell command +.i newaliases +after editing /usr/lib/aliases since the delivery system +uses an indexed file created by +.i newaliases . +.pp +We have seen that +.i Mail +can be invoked with command line arguments which are people +to send the message to, or with no arguments to read mail. +Specifying the +.rb \-f +flag on the command line causes +.i Mail +to read messages from a file other than your system mailbox. +For example, if you have a collection of messages in +the file +.q letters +you can use +.i Mail +to read them with: +.(l +% Mail \-f letters +.)l +You can use all +the +.i Mail +commands described in this document to examine, modify, or delete +messages from your +.q letters +file, which will be rewritten when you leave +.i Mail +with the +.b quit +command described below. +.pp +Since mail that you read is saved in the file +.i mbox +in your home directory by default, you can read +.i mbox +in your home directory by using simply +.(l +% Mail \-f +.)l +.pp +Normally, messages that you examine using the +.b type +command are saved in the file +.q mbox +in your home directory if you leave +.i Mail +with the +.b quit +command described below. +If you wish to retain a message in your system mailbox +you can use the +.b preserve +command to tell +.i Mail +to leave it there. +The +.b preserve +command accepts a list of message numbers, just like +.b type +and may be abbreviated to +.b pre . +.pp +Messages in your system mailbox that you do not examine are +normally retained in your system mailbox automatically. +If you wish to have such a message saved in +.i mbox +without reading it, you may use the +.b mbox +command to have them so saved. For example, +.(l +mbox 2 +.)l +in our example would cause the second message (from sam) +to be saved in +.i mbox +when the +.b quit +command is executed. +.b Mbox +is also the way to direct messages to your +.i mbox +file if you have set the +.q hold +option described above. +.b Mbox +can be abbreviated to +.b mb . +.pp +When you have perused all the messages of interest, you can leave +.i Mail +with the +.b quit +command, which saves the messages you have typed but not +deleted in the file +.i mbox +in your login directory. Deleted messages are discarded irretrievably, +and messages left untouched are preserved in your system mailbox so +that you will see them the next time you type: +.(l +% Mail +.)l +The +.b quit +command can be abbreviated to simply +.b q . +.pp +If you wish for some reason to leave +.i Mail +quickly without altering either your system mailbox or +.i mbox , +you can type the +.b x +command (short for +.b exit ), +which will immediately return you to the Shell without changing anything. +.pp +If, instead, you want to execute a Shell command without leaving +.i Mail , +you +can type the command preceded by an exclamation point, just as in the +text editor. Thus, for instance: +.(l +!date +.)l +will print the current date without leaving +.i Mail . +.pp +Finally, the +.b help +command is available to print out a brief summary of the +.i Mail +commands, using only the single character command abbreviations. diff --git a/usr.bin/mail/USD.doc/mail3.nr b/usr.bin/mail/USD.doc/mail3.nr new file mode 100644 index 0000000..64f7634 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail3.nr @@ -0,0 +1,133 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail3.nr 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 "Maintaining folders" +.pp +.i Mail +includes a simple facility for maintaining groups of messages together +in folders. This section describes this facility. +.pp +To use the folder facility, you must tell +.i Mail +where you wish to keep your folders. Each folder of messages will +be a single file. For convenience, all of your folders are kept in +a single directory of your choosing. To tell +.i Mail +where your folder directory is, put a line of the form +.(l +set folder=letters +.)l +in your +.i .mailrc +file. If, as in the example above, your folder directory does not +begin with a `/,' +.i Mail +will assume that your folder directory is to be found starting from +your home directory. Thus, if your home directory is +.b /usr/person +the above example told +.i Mail +to find your folder directory in +.b /usr/person/letters . +.pp +Anywhere a file name is expected, you can use a folder name, preceded +with `+.' For example, to put a message into a folder with the +.b save +command, you can use: +.(l +save +classwork +.)l +to save the current message in the +.i classwork +folder. If the +.i classwork +folder does not yet exist, it will be created. Note that messages +which are saved with the +.b save +command are automatically removed from your system mailbox. +.pp +In order to make a copy of a message in a folder without causing +that message to be removed from your system mailbox, use the +.b copy +command, which is identical in all other respects to the +.b save +command. For example, +.(l +copy +classwork +.)l +copies the current message into the +.i classwork +folder and leaves a copy in your system mailbox. +.pp +The +.b folder +command +can be used to direct +.i Mail +to the contents of a different folder. +For example, +.(l +folder +classwork +.)l +directs +.i Mail +to read the contents of the +.i classwork +folder. All of the commands that you can use on your system +mailbox are also applicable to folders, including +.b type , +.b delete , +and +.b reply . +To inquire which folder you are currently editing, use simply: +.(l +folder +.)l +.pp +To list your current set of folders, use the +.b folders +command. +.pp +To start +.i Mail +reading one of your folders, you can use the +.b \-f +option described in section 2. For example: +.(l +% Mail \-f +classwork +.)l +will cause +.i Mail +to read your +.i classwork +folder without looking at your system mailbox. diff --git a/usr.bin/mail/USD.doc/mail4.nr b/usr.bin/mail/USD.doc/mail4.nr new file mode 100644 index 0000000..b67bf03 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail4.nr @@ -0,0 +1,437 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail4.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "More about sending mail" +.sh 2 "Tilde escapes" +.pp +While typing in a message to be sent to others, it is often +useful to be able to invoke the text editor on the partial message, +print the message, execute a shell command, or do some other +auxiliary function. +.i Mail +provides these capabilities through +.i "tilde escapes" , +which consist of a tilde (~) at the beginning of a line, followed by +a single character which indicates the function to be performed. For +example, to print the text of the message so far, use: +.(l +~p +.)l +which will print a line of dashes, the recipients of your message, and +the text of the message so far. +Since +.i Mail +requires two consecutive \s-2RUBOUT\s0's to abort a letter, you +can use a single \s-2RUBOUT\s0 to abort the output of ~p or any other +~ escape without killing your letter. +.pp +If you are dissatisfied with the message as +it stands, you can invoke the text editor on it using the escape +.(l +~e +.)l +which causes the message to be copied into a temporary file and an +instance of the editor to be spawned. After modifying the message to +your satisfaction, write it out and quit the editor. +.i Mail +will respond +by typing +.(l +(continue) +.)l +after which you may continue typing text which will be appended to your +message, or type <control-d> to end the message. +A standard text editor is provided by +.i Mail . +You can override this default by setting the valued option +.q EDITOR +to something else. For example, you might prefer: +.(l +set EDITOR=/usr/ucb/ex +.)l +.pp +Many systems offer a screen editor as an alternative to the standard +text editor, such as the +.i vi +editor from UC Berkeley. +To use the screen, or +.i visual +editor, on your current message, you can use the escape, +.(l +~v +.)l +~v works like ~e, except that the screen editor is invoked instead. +A default screen editor is defined by +.i Mail . +If it does not suit you, you can set the valued option +.q VISUAL +to the path name of a different editor. +.pp +It is often useful to be able to include the contents of some +file in your message; the escape +.(l +~r filename +.)l +is provided for this purpose, and causes the named file to be appended +to your current message. +.i Mail +complains if the file doesn't exist +or can't be read. If the read is successful, the number of lines and +characters appended to your message is printed, after which you may continue +appending text. The filename may contain shell metacharacters like * and ? +which are expanded according to the conventions of your shell. +.pp +As a special case of ~r, the escape +.(l +~d +.)l +reads in the file +.q dead.letter +in your home directory. This is often useful since +.i Mail +copies the text +of your message there when you abort a message with \s-2RUBOUT\s0. +.pp +To save the current text of your message on a file you may use the +.(l +~w filename +.)l +escape. +.i Mail +will print out the number of lines and characters written +to the file, after which you may continue appending text to your message. +Shell metacharacters may be used in the filename, as in ~r and are expanded +with the conventions of your shell. +.pp +If you are sending mail from within +.i Mail's +command mode +you can read a message sent to you into the message +you are constructing with the escape: +.(l +~m 4 +.)l +which will read message 4 into the current message, shifted right by +one tab stop. You can name any non-deleted message, or list of messages. +Messages can also be forwarded without shifting by a tab stop with ~f. +This is the usual way to forward a message. +.pp +If, in the process of composing a message, you decide to add additional +people to the list of message recipients, you can do so with the escape +.(l +~t name1 name2 ... +.)l +You may name as few or many additional recipients as you wish. Note +that the users originally on the recipient list will still receive +the message; you cannot remove someone from the recipient +list with ~t. +.pp +If you wish, you can associate a subject with your message by using the +escape +.(l +~s Arbitrary string of text +.)l +which replaces any previous subject with +.q "Arbitrary string of text." +The subject, if given, is sent near the +top of the message prefixed with +.q "Subject:" +You can see what the message will look like by using ~p. +.pp +For political reasons, one occasionally prefers to list certain +people as recipients of carbon copies of a message rather than +direct recipients. The escape +.(l +~c name1 name2 ... +.)l +adds the named people to the +.q "Cc:" +list, similar to ~t. +Again, you can execute ~p to see what the message will look like. +.pp +The escape +.(l +~b name1 name2 ... +.)l +adds the named people to the +.q "Cc:" +list, but does not make the names visible in the +.q "Cc:" +line ("blind" carbon copy). +.pp +The recipients of the message together constitute the +.q "To:" +field, the subject the +.q "Subject:" +field, and the carbon copies the +.q "Cc:" +field. If you wish to edit these in ways impossible with the ~t, ~s, ~c +and ~b escapes, you can use the escape +.(l +~h +.)l +which prints +.q "To:" +followed by the current list of recipients and leaves the cursor +(or printhead) at the end of the line. If you type in ordinary +characters, they are appended to the end of the current list of +recipients. You can also use your erase character to erase back into +the list of recipients, or your kill character to erase them altogether. +Thus, for example, if your erase and kill characters are the standard +(on printing terminals) # and @ symbols, +.(l +~h +To: root kurt####bill +.)l +would change the initial recipients +.q "root kurt" +to +.q "root bill." +When you type a newline, +.i Mail +advances to the +.q "Subject:" +field, where the same rules apply. Another newline brings you to +the +.q "Cc:" +field, which may be edited in the same fashion. Another newline +brings you to the +.q "Bcc:" +("blind" carbon copy) field, which follows the same rules as the "Cc:" +field. Another newline +leaves you appending text to the end of your message. You can use +~p to print the current text of the header fields and the body +of the message. +.pp +To effect a temporary escape to the shell, the escape +.(l +~!command +.)l +is used, which executes +.i command +and returns you to mailing mode without altering the text of +your message. If you wish, instead, to filter the body of your +message through a shell command, then you can use +.(l +~|command +.)l +which pipes your message through the command and uses the output +as the new text of your message. If the command produces no output, +.i Mail +assumes that something is amiss and retains the old version +of your message. A frequently-used filter is the command +.i fmt , +designed to format outgoing mail. +.pp +To effect a temporary escape to +.i Mail +command mode instead, you can use the +.(l +~:\fIMail command\fP +.)l +escape. This is especially useful for retyping the message you are +replying to, using, for example: +.(l +~:t +.)l +It is also useful for setting options and modifying aliases. +.pp +If you wish abort the current message, you can use the escape +.(l +~q +.)l +This will terminate the current message and return you to the +shell (or \fIMail\fP if you were using the \fBmail\fP command). +If the \fBsave\fP option is set, the message will be copied +to the file +.q dead.letter +in your home directory. +.pp +If you wish (for some reason) to send a message that contains +a line beginning with a tilde, you must double it. Thus, for example, +.(l +~~This line begins with a tilde. +.)l +sends the line +.(l +~This line begins with a tilde. +.)l +.pp +Finally, the escape +.(l +~? +.)l +prints out a brief summary of the available tilde escapes. +.pp +On some terminals (particularly ones with no lower case) +tilde's are difficult to type. +.i Mail +allows you to change the escape character with the +.q escape +option. For example, I set +.(l +set escape=] +.)l +and use a right bracket instead of a tilde. If I ever need to +send a line beginning with right bracket, I double it, just as for ~. +Changing the escape character removes the special meaning of ~. +.sh 2 "Network access" +.pp +This section describes how to send mail to people on other machines. +Recall that sending to a plain login name sends mail to that person +on your machine. If your machine is directly (or sometimes, even, +indirectly) connected to the Arpanet, you can send messages to people +on the Arpanet using a name of the form +.(l +name@host.domain +.)l +where +.i name +is the login name of the person you're trying to reach, +.i host +is the name of the machine on the Arpanet, +and +.i domain +is the higher-level scope within which the hostname is known, e.g. EDU (for educational +institutions), COM (for commercial entities), GOV (for governmental agencies), +ARPA for many other things, BITNET or CSNET for those networks. +.pp +If your recipient logs in on a machine connected to yours by +UUCP (the Bell Laboratories supplied network that communicates +over telephone lines), sending mail can be a bit more complicated. +You must know the list of machines through which your message must +travel to arrive at his site. So, if his machine is directly connected +to yours, you can send mail to him using the syntax: +.(l +host!name +.)l +where, again, +.i host +is the name of the machine and +.i name +is the login name. +If your message must go through an intermediary machine first, you +must use the syntax: +.(l +intermediary!host!name +.)l +and so on. It is actually a feature of UUCP that the map of all +the systems in the network is not known anywhere (except where people +decide to write it down for convenience). Talk to your system administrator +about good ways to get places; the +.i uuname +command will tell you systems whose names are recognized, but not which +ones are frequently called or well-connected. +.pp +When you use the +.b reply +command to respond to a letter, there is a problem of figuring out the +names of the users in the +.q "To:" +and +.q "Cc:" +lists +.i "relative to the current machine" . +If the original letter was sent to you by someone on the local machine, +then this problem does not exist, but if the message came from a remote +machine, the problem must be dealt with. +.i Mail +uses a heuristic to build the correct name for each user relative +to the local machine. So, when you +.b reply +to remote mail, the names in the +.q "To:" +and +.q "Cc:" +lists may change somewhat. +.sh 2 "Special recipients" +.pp +As described previously, you can send mail to either user names or +.b alias +names. It is also possible to send messages directly to files or to +programs, using special conventions. If a recipient name has a +`/' in it or begins with a `+', it is assumed to be the +path name of a file into which +to send the message. If the file already exists, the message is +appended to the end of the file. If you want to name a file in +your current directory (ie, one for which a `/' would not usually +be needed) you can precede the name with `./' +So, to send mail to the file +.q memo +in the current directory, you can give the command: +.(l +% Mail ./memo +.)l +If the name begins with a `+,' it is expanded into the full path name +of the folder name in your folder directory. +This ability to send mail to files can be used for a variety of +purposes, such as maintaining a journal and keeping a record of +mail sent to a certain group of users. The second example can be +done automatically by including the full pathname of the record +file in the +.b alias +command for the group. Using our previous +.b alias +example, you might give the command: +.(l +alias project sam sally steve susan /usr/project/mail_record +.)l +Then, all mail sent to "project" would be saved on the file +.q /usr/project/mail_record +as well as being sent to the members of the project. This file +can be examined using +.i "Mail \-f" . +.pp +It is sometimes useful to send mail directly to a program, for +example one might write a project billboard program and want to access +it using +.i Mail . +To send messages to the billboard program, one can send mail +to the special name `|billboard' for example. +.i Mail +treats recipient names that begin with a `|' as a program to send +the mail to. An +.b alias +can be set up to reference a `|' prefaced name if desired. +.i Caveats : +the shell treats `|' specially, so it must be quoted on the command +line. Also, the `| program' must be presented as a single argument to +mail. The safest course is to surround the entire name with double +quotes. This also applies to usage in the +.b alias +command. For example, if we wanted to alias `rmsgs' to `rmsgs \-s' +we would need to say: +.(l +alias rmsgs "| rmsgs -s" +.)l diff --git a/usr.bin/mail/USD.doc/mail5.nr b/usr.bin/mail/USD.doc/mail5.nr new file mode 100644 index 0000000..b70ce95 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail5.nr @@ -0,0 +1,1041 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail5.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Additional features" +.pp +This section describes some additional commands useful for +reading your mail, setting options, and handling lists of messages. +.sh 2 "Message lists" +.pp +Several +.i Mail +commands accept a list of messages as an argument. +Along with +.b type +and +.b delete , +described in section 2, +there is the +.b from +command, which prints the message headers associated with the +message list passed to it. +The +.b from +command is particularly useful in conjunction with some of the +message list features described below. +.pp +A +.i "message list" +consists of a list of message numbers, ranges, and names, +separated by spaces or tabs. Message numbers may be either +decimal numbers, which directly specify messages, or one of the +special characters +.q \(ua +.q "." +or +.q "$" +to specify the first relevant, current, or last +relevant message, respectively. +.i Relevant +here means, for most commands +.q "not deleted" +and +.q "deleted" +for the +.b undelete +command. +.pp +A range of messages consists of two message numbers (of the form +described in the previous paragraph) separated by a dash. +Thus, to print the first four messages, use +.(l +type 1\-4 +.)l +and to print all the messages from the current message to the last +message, use +.(l +type .\-$ +.)l +.pp +A +.i name +is a user name. The user names given in the message list are +collected together and each message selected by other means +is checked to make sure it was sent by one of the named users. +If the message consists entirely of user names, then every +message sent by one of those users that is +.i relevant +(in the sense described earlier) +is selected. Thus, to print every message sent to you by +.q root, +do +.(l +type root +.)l +.pp +As a shorthand notation, you can specify simply +.q * +to get every +.i relevant +(same sense) +message. Thus, +.(l +type * +.)l +prints all undeleted messages, +.(l +delete * +.)l +deletes all undeleted messages, and +.(l +undelete * +.)l +undeletes all deleted messages. +.pp +You can search for the presence of a word in subject lines with +.b / . +For example, to print the headers of all messages that contain the +word +.q PASCAL, +do: +.(l +from /pascal +.)l +Note that subject searching ignores upper/lower case differences. +.sh 2 "List of commands" +.pp +This section describes all the +.i Mail +commands available when +receiving mail. +.ip "\fB\-\fP\ \ " +The +.rb \- +command goes to the previous message and prints it. The +.rb \- +command may be given a decimal number +.i n +as an argument, in which case the +.i n th +previous message is gone to and printed. +.ip "\fB?\fP\ \ " +Prints a brief summary of commands. +.ip "\fB!\fP\ \ " +Used to preface a command to be executed by the shell. +.ip "\fBPrint\fP\ \ " +Like +.b print , +but also print out ignored header fields. See also +\fBprint\fP, \fBignore\fP and \fBretain\fP. +\fBPrint\fP can be abbreviated to \fBP\fP. +.ip "\fBReply\fP or \fBRespond\fP\ \ " +Note the capital \fBR\fP in the name. +Frame a reply to a one or more messages. +The reply (or replies if you are using this on multiple messages) +will be sent ONLY to the person who sent you the message +(respectively, the set of people who sent the messages you are +replying to). +You can +add people using the \fB~t\fP, \fB~c\fP and \fB~b\fP +tilde escapes. The subject in your reply is formed by prefacing the +subject in the original message with +.q "Re:" +unless it already began thus. +If the original message included a +.q "reply-to" +header field, the reply will go +.i only +to the recipient named by +.q "reply-to." +You type in your message using the same conventions available to you +through the +.b mail +command. +The +.b Reply +command is especially useful for replying to messages that were sent +to enormous distribution groups when you really just want to +send a message to the originator. Use it often. +\fBReply\fP (and \fBRespond\fP) can be abbreviated to \fBR\fP. +.ip "\fBType\fP\ \ " +Identical to the +.b Print +command. +\fBType\fP can be abbreviated to \fBT\fP. +.ip "\fBalias\fP\ \ " +Define a name to stand for a set of other names. +This is used when you want to send messages to a certain +group of people and want to avoid retyping their names. +For example +.(l +alias project john sue willie kathryn +.)l +creates an alias +.i project +which expands to the four people John, Sue, Willie, and Kathryn. +If no arguments are given, all currently-defined aliases are printed. +If one argument is given, that alias is printed (if it exists). +\fBAlias\fP can be abbreviated to \fBa\fP. +.ip "\fBalternates\fP\ \ " +If you have accounts on several machines, you may find it convenient +to use the /usr/lib/aliases on all the machines except one to direct +your mail to a single account. +The +.b alternates +command is used to inform +.i Mail +that each of these other addresses is really +.i you . +.i Alternates +takes a list of user names and remembers that they are all actually you. +When you +.b reply +to messages that were sent to one of these alternate names, +.i Mail +will not bother to send a copy of the message to this other address (which +would simply be directed back to you by the alias mechanism). +If +.i alternates +is given no argument, it lists the current set of alternate names. +.b Alternates +is usually used in the .mailrc file. +\fBAlternates\fP can be abbreviated to \fBalt\fP. +.ip "\fBchdir\fP\ \ " +The +.b chdir +command allows you to change your current directory. +.b Chdir +takes a single argument, which is taken to be the pathname of +the directory to change to. If no argument is given, +.b chdir +changes to your home directory. +\fBChdir\fP can be abbreviated to \fBc\fP. +.ip "\fBcopy\fP\ \ " +The +.b copy +command does the same thing that +.b save +does, except that it does not mark the messages it is used on +for deletion when you quit. +\fBCopy\fP can be abbreviated to \fBco\fP. +.ip "\fBdelete\fP\ \ " +Deletes a list of messages. Deleted messages can be reclaimed +with the +.b undelete +command. +\fBDelete\fP can be abbreviated to \fBd\fP. +.ip "\fBdp\fP or \fBdt\fP\ \ " +These +commands delete the current message and print the next message. +They are useful for quickly reading and disposing of mail. +If there is no next message, \fImail\fP says ``at EOF.'' +.ip "\fBedit\fP\ \ " +To edit individual messages using the text editor, the +.b edit +command is provided. The +.b edit +command takes a list of messages as described under the +.b type +command and processes each by writing it into the file +Message\c +.i x +where +.i x +is the message number being edited and executing the text editor on it. +When you have edited the message to your satisfaction, write the message +out and quit, upon which +.i Mail +will read the message back and remove the file. +.b Edit +can be abbreviated to +.b e . +.ip "\fBelse\fP\ \ " +Marks the end of the then-part of an +.b if +statement and the beginning of the +part to take effect if the condition of the +.b if +statement is false. +.ip "\fBendif\fP\ \ " +Marks the end of an +.b if +statement. +.ip "\fBexit\fP or \fBxit\fP\ \ " +Leave +.i Mail +without updating the system mailbox or the file your were reading. +Thus, if you accidentally delete several messages, you can use +.b exit +to avoid scrambling your mailbox. +\fBExit\fP can be abbreviated to \fBex\fP or \fBx\fP. +.ip "\fBfile\fP\ \ " +The same as +.b folder . +\fBFile\fP can be abbreviated to \fBfi\fP. +.ip "\fBfolders\fP\ \ " +List the names of the folders in your folder directory. +.ip "\fBfolder\fP\ \ " +The +.b folder +command switches to a new mail file or folder. With no arguments, it +tells you which file you are currently reading. If you give +it an argument, it will write out changes (such as deletions) +you have made in the current file and read the new file. +Some special conventions are recognized for the name: +.(b +.TS +center; +c c +l a. +Name Meaning +_ +# Previous file read +% Your system mailbox +%name \fIName\fP's system mailbox +& Your ~/mbox file ++folder A file in your folder directory +.TE +.)b +\fBFolder\fP can be abbreviated to \fBfo\fP. +.ip "\fBfrom\fP\ \ " +The +.b from +command takes a list of messages and prints out the header lines for each one; +hence +.(l +from joe +.)l +is the easy way to display all the message headers from \*(lqjoe.\*(rq +\fBFrom\fP can be abbreviated to \fBf\fP. +.ip "\fBheaders\fP\ \ " +When you start up +.i Mail +to read your mail, it lists the message headers that you have. +These headers tell you who each message is from, when they were +received, how many lines and characters each message is, and the +.q "Subject:" +header field of each message, if present. In addition, +.i Mail +tags the message header of each message that has been the object +of the +.b preserve +command with a +.q P. +Messages that have been +.b saved +or +.b written +are flagged with a +.q *. +Finally, +.b deleted +messages are not printed at all. If you wish to reprint the current +list of message headers, you can do so with the +.b headers +command. The +.b headers +command (and thus the initial header listing) +only lists the first so many message headers. +The number of headers listed depends on the speed of your +terminal. +This can be overridden by specifying the number of headers you +want with the +.i window +option. +.i Mail +maintains a notion of the current +.q window +into your messages for the purposes of printing headers. +Use the +.b z +command to move forward and back a window. +You can move +.i Mail's +notion of the current window directly to a particular message by +using, for example, +.(l +headers 40 +.)l +to move +.i Mail's +attention to the messages around message 40. +If a ``+'' argument is given, then the next screenful of message headers is +printed, and if a ``\-'' argument is given, the previous screenful of message +headers is printed. +\fBHeaders\fP can be abbreviated to \fBh\fP. +.ip "\fBhelp\fP\ \ " +Print a brief and usually out of date help message about the commands +in +.i Mail . +The +.i man +page for +.i mail +is usually more up-to-date than either the help message or this manual. +It is also a synonym for \fB?\fP. +.ip "\fBhold\fP\ \ " +Arrange to hold a list of messages in the system mailbox, instead +of moving them to the file +.i mbox +in your home directory. If you set the binary option +.i hold , +this will happen by default. +It does not override the \fBdelete\fP command. +\fBHold\fP can be abbreviated to \fBho\fP. +.ip "\fBif\fP\ \ " +Commands in your +.q .mailrc +file can be executed conditionally depending on whether you are +sending or receiving mail with the +.b if +command. For example, you can do: +.(l +if receive + \fIcommands\fP... +endif +.)l +An +.b else +form is also available: +.(l +if send + \fIcommands\fP... +else + \fIcommands\fP... +endif +.)l +Note that the only allowed conditions are +.b receive +and +.b send . +.ip "\fBignore\fP \ \ " +.b N.B.: +.i Ignore +has been superseded by +.i retain. +.br +Add the list of header fields named to the +.i "ignore list" . +Header fields in the ignore list are not printed on your +terminal when you print a message. This allows you to suppress +printing of certain machine-generated header fields, such as +.i Via +which are not usually of interest. The +.b Type +and +.b Print +commands can be used to print a message in its entirety, including +ignored fields. +If +.b ignore +is executed with no arguments, it lists the current set of ignored fields. +.ip "\fBlist\fP\ \ " +List the valid +.i Mail +commands. +\fBList\fP can be abbreviated to \fBl\fP. +.. .ip \fBlocal\fP +.. Define a list of local names for this host. This command is useful +.. when the host is known by more than one name. Names in the list +.. may be qualified be the domain of the host. The first name on the local +.. list is the +.. .i distinguished +.. name of the host. +.. The names on the local list are used by +.. .i Mail +.. to decide which addresses are local to the host. +.. For example: +.. .(l +.. local ucbarpa.BERKELEY.ARPA arpa.BERKELEY.ARPA \\ +.. arpavax.BERKELEY.ARPA r.BERKELEY.ARPA \\ +.. ucb-arpa.ARPA +.. .)l +.. From this list we see that +.. .i "fred@ucbarpa.BERKELEY.ARPA", +.. .i "harold@arpa.BERKELEY", +.. and +.. .i "larry@r" +.. are all addresses of users on the local host. +.. The +.. .b local +.. command is usually not used be general users since it is designed for +.. local configuration; it is usually found in the file /usr/lib/Mail.rc. +.ip "\fBmail\fP\ \ " +Send mail to one or more people. If you have the +.i ask +option set, +.i Mail +will prompt you for a subject to your message. Then you +can type in your message, using tilde escapes as described in +section 4 to edit, print, or modify your message. To signal your +satisfaction with the message and send it, type control-d at the +beginning of a line, or a . alone on a line if you set the option +.i dot . +To abort the message, type two interrupt characters (\s-2RUBOUT\s0 +by default) in a row or use the +.b ~q +escape. +The \fBmail\fP command can be abbreviated to \fBm\fP. +.ip "\fBmbox\fP\ \ " +Indicate that a list of messages be sent to +.i mbox +in your home directory when you quit. This is the default +action for messages if you do +.i not +have the +.i hold +option set. +.ip "\fBnext\fP or \fB+\fP\ \ " +The +.b next +command goes to the next message and types it. If given a message list, +.b next +goes to the first such message and types it. Thus, +.(l +next root +.)l +goes to the next message sent by +.q root +and types it. The +.b next +command can be abbreviated to simply a newline, which means that one +can go to and type a message by simply giving its message number or +one of the magic characters +.q "^" +.q "." +or +.q "$". +Thus, +.(l +\&. +.)l +prints the current message and +.(l +4 +.)l +prints message 4, as described previously. +\fBNext\fP can be abbreviated to \fBn\fP. +.ip "\fBpreserve\fP\ \ " +Same as +.b hold . +Cause a list of messages to be held in your system mailbox when you quit. +\fBPreserve\fP can be abbreviated to \fBpre\fP. +.ip "\fBprint\fP\ \ " +Print the specified messages. If the +.b crt +variable is set, messages longer than the number of lines it indicates +are paged through the command specified by the \fBPAGER\fP variable. +The \fBprint\fP command can be abbreviated to \fBp\fP. +.ip "\fBquit\fP\ \ " +Terminates the session, saving all undeleted, unsaved and unwritten messages +in the user's \fImbox\fP file in their login directory +(messages marked as having been read), preserving all +messages marked with \fBhold\fP or \fBpreserve\fP or never referenced +in their system mailbox. +Any messages that were deleted, saved, written or saved to \fImbox\fP are +removed from their system mailbox. +If new mail has arrived during the session, the message +``You have new mail'' is given. If given while editing a mailbox file +with the \fB\-f\fP flag, then the edit file is rewritten. +A return to the Shell is effected, unless the rewrite of edit file fails, +in which case the user can escape with the \fBexit\fP command. +\fBQuit\fP can be abbreviated to \fBq\fP. +.ip "\fBreply\fP or \fBrespond\fP\ \ " +Frame a reply to a single message. +The reply will be sent to the +person who sent you the message (to which you are replying), plus all +the people who received the original message, except you. You can +add people using the \fB~t\fP, \fB~c\fP and \fB~b\fP +tilde escapes. The subject in your reply is formed by prefacing the +subject in the original message with +.q "Re:" +unless it already began thus. +If the original message included a +.q "reply-to" +header field, the reply will go +.i only +to the recipient named by +.q "reply-to." +You type in your message using the same conventions available to you +through the +.b mail +command. +The \fBreply\fP (and \fBrespond\fP) command can be abbreviated to \fBr\fP. +.ip "\fBretain\fP\ \ " +Add the list of header fields named to the \fIretained list\fP. +Only the header fields in the retain list +are shown on your terminal when you print a message. +All other header fields are suppressed. +The +.b Type +and +.b Print +commands can be used to print a message in its entirety. +If +.b retain +is executed with no arguments, it lists the current set of +retained fields. +.ip "\fBsave\fP\ \ " +It is often useful to be able to save messages on related topics +in a file. The +.b save +command gives you the ability to do this. The +.b save +command takes as an argument a list of message numbers, followed by +the name of the file in which to save the messages. The messages +are appended to the named file, thus allowing one to keep several +messages in the file, stored in the order they were put there. +The filename in quotes, followed by the line +count and character count is echoed on the user's terminal. +An example of the +.b save +command relative to our running example is: +.(l +s 1 2 tuitionmail +.)l +.b Saved +messages are not automatically saved in +.i mbox +at quit time, nor are they selected by the +.b next +command described above, unless explicitly specified. +\fBSave\fP can be abbreviated to \fBs\fP. +.ip "\fBset\fP\ \ " +Set an option or give an option a value. Used to customize +.i Mail . +Section 5.3 contains a list of the options. Options can be +.i binary , +in which case they are +.i on +or +.i off , +or +.i valued . +To set a binary option +.i option +.i on , +do +.(l +set option +.)l +To give the valued option +.i option +the value +.i value , +do +.(l +set option=value +.)l +There must be no space before or after the ``='' sign. +If no arguments are given, all variable values are printed. +Several options can be specified in a single +.b set +command. +\fBSet\fP can be abbreviated to \fBse\fP. +.ip "\fBshell\fP\ \ " +The +.b shell +command allows you to +escape to the shell. +.b Shell +invokes an interactive shell and allows you to type commands to it. +When you leave the shell, you will return to +.i Mail . +The shell used is a default assumed by +.i Mail ; +you can override this default by setting the valued option +.q SHELL, +eg: +.(l +set SHELL=/bin/csh +.)l +\fBShell\fP can be abbreviated to \fBsh\fP. +.ip "\fBsize\fP\ \ " +Takes a message list and prints out the size in characters of each +message. +.ip "\fBsource\fP\ \ " +The +.b source +command reads +.i mail +commands from a file. It is useful when you are trying to fix your +.q .mailrc +file and you need to re-read it. +\fBSource\fP can be abbreviated to \fBso\fP. +.ip "\fBtop\fP\ \ " +The +.b top +command takes a message list and prints the first five lines +of each addressed message. +If you wish, you can change the number of lines that +.b top +prints out by setting the valued option +.q "toplines." +On a CRT terminal, +.(l +set toplines=10 +.)l +might be preferred. +\fBTop\fP can be abbreviated to \fBto\fP. +.ip "\fBtype\fP\ \ " +Same as \fBprint\fP. +Takes a message list and types out each message on the terminal. +The \fBtype\fP command can be abbreviated to \fBt\fP. +.ip "\fBundelete\fP \ \" +Takes a message list and marks each message as \fInot\fP +being deleted. +\fBUndelete\fP can be abbreviated to \fBu\fP. +.ip "\fBunread\fP\ \ " +Takes a message list and marks each message as +.i not +having been read. +\fBUnread\fP can be abbreviated to \fBU\fP. +.ip "\fBunset\fP\ \ " +Takes a list of option names and discards their remembered values; +the inverse of \fBset\fP . +.ip "\fBvisual\fP\ \ " +It is often useful to be able to invoke one of two editors, +based on the type of terminal one is using. To invoke +a display oriented editor, you can use the +.b visual +command. The operation of the +.b visual +command is otherwise identical to that of the +.b edit +command. +.ne 2v+\n(psu +.sp \n(psu +Both the +.b edit +and +.b visual +commands assume some default text editors. These default editors +can be overridden by the valued options +.q EDITOR +and +.q VISUAL +for the standard and screen editors. You might want to do: +.(l +set EDITOR=/usr/ucb/ex VISUAL=/usr/ucb/vi +.)l +\fBVisual\fP can be abbreviated to \fBv\fP. +.ip "\fBwrite\fP\ \ " +The +.b save +command always writes the entire message, including the headers, +into the file. If you want to write just the message itself, you +can use the +.b write +command. The +.b write +command has the same syntax as the +.b save +command, and can be abbreviated to simply +.b w . +Thus, we could write the second message by doing: +.(l +w 2 file.c +.)l +As suggested by this example, the +.b write +command is useful for such tasks as sending and receiving +source program text over the message system. +The filename in quotes, followed by the line +count and character count is echoed on the user's terminal. +.ip "\fBz\fP\ \ " +.i Mail +presents message headers in windowfuls as described under +the +.b headers +command. +You can move +.i Mail's +attention forward to the next window by giving the +.(l +z+ +.)l +command. Analogously, you can move to the previous window with: +.(l +z\- +.)l +.sh 2 "Custom options" +.pp +Throughout this manual, we have seen examples of binary and valued options. +This section describes each of the options in alphabetical order, including +some that you have not seen yet. +To avoid confusion, please note that the options are either +all lower case letters or all upper case letters. When I start a sentence +such as: +.q "Ask" +causes +.i Mail +to prompt you for a subject header, +I am only capitalizing +.q ask +as a courtesy to English. +.ip "\fBEDITOR\fP\ \ " +The valued option +.q EDITOR +defines the pathname of the text editor to be used in the +.b edit +command and ~e. If not defined, a standard editor is used. +.ip "\fBPAGER\fP\ \ " +Pathname of the program to use for paginating output when +it exceeds \fIcrt\fP lines. +A default paginator is used if this option is not defined. +.ip "\fBSHELL\fP\ \ " +The valued option +.q SHELL +gives the path name of your shell. This shell is used for the +.b ! +command and ~! escape. In addition, this shell expands +file names with shell metacharacters like * and ? in them. +.ip "\fBVISUAL\fP\ \ " +The valued option +.q VISUAL +defines the pathname of the screen editor to be used in the +.b visual +command +and ~v escape. A standard screen editor is used if you do not define one. +.ip "\fBappend\fP\ \ " +The +.q append +option is binary and +causes messages saved in +.i mbox +to be appended to the end rather than prepended. +Normally, \fIMail\fP will put messages in \fImbox\fP +in the same order that the system puts messages in your system mailbox. +By setting +.q append, +you are requesting that +.i mbox +be appended to regardless. It is in any event quicker to append. +.ip "\fBask\fP\ \ " +.q "Ask" +is a binary option which +causes +.i Mail +to prompt you for the subject of each message you send. +If you respond with simply a newline, no subject field will be sent. +.ip "\fBaskcc\fP\ \ " +.q Askcc +is a binary option which +causes you to be prompted for additional carbon copy recipients at the +end of each message. Responding with a newline shows your +satisfaction with the current list. +.ip "\fBautoprint\fP\ \ " +.q Autoprint +is a binary option which +causes the +.b delete +command to behave like +.b dp +\*- thus, after deleting a message, the next one will be typed +automatically. This is useful when quickly scanning and deleting +messages in your mailbox. +.ip "\fBcrt\fP \ \ " +The valued option +.I crt +is used as a threshold to determine how long a message must +be before +.b PAGER +is used to read it. +.ip "\fBdebug\fP \ \ " +The binary option +.q debug +causes debugging information to be displayed. Use of this +option is the same as using the \fB\-d\fP command line flag. +.ip "\fBdot\fP\ \ " +.q Dot +is a binary option which, if set, causes +.i Mail +to interpret a period alone on a line as the terminator +of the message you are sending. +.ip "\fBescape\fP\ \ " +To allow you to change the escape character used when sending +mail, you can set the valued option +.q escape. +Only the first character of the +.q escape +option is used, and it must be doubled if it is to appear as +the first character of a line of your message. If you change your escape +character, then ~ loses all its special meaning, and need no longer be doubled +at the beginning of a line. +.ip "\fBfolder\fP\ \ " +The name of the directory to use for storing folders of messages. +If this name begins with a `/' +.i Mail +considers it to be an absolute pathname; otherwise, the folder directory +is found relative to your home directory. +.ip "\fBhold\fP\ \ " +The binary option +.q hold +causes messages that have been read but not manually dealt with +to be held in the system mailbox. This prevents such messages from +being automatically swept into your \fImbox\fP file. +.ip "\fBignore\fP\ \ " +The binary option +.q ignore +causes \s-2RUBOUT\s0 characters from your terminal to be ignored and echoed +as @'s while you are sending mail. \s-2RUBOUT\s0 characters retain their +original meaning in +.i Mail +command mode. +Setting the +.q ignore +option is equivalent to supplying the +.b \-i +flag on the command line as described in section 6. +.ip "\fBignoreeof\fP\ \ " +An option related to +.q dot +is +.q ignoreeof +which makes +.i Mail +refuse to accept a control\-d as the end of a message. +.q Ignoreeof +also applies to +.i Mail +command mode. +.ip "\fBkeep\fP\ \ " +The +.q keep +option causes +.i Mail +to truncate your system mailbox instead of deleting it when it +is empty. This is useful if you elect to protect your mailbox, which +you would do with the shell command: +.(l +chmod 600 /usr/spool/mail/yourname +.)l +where +.i yourname +is your login name. If you do not do this, anyone can probably read +your mail, although people usually don't. +.ip "\fBkeepsave\fP\ \ " +When you +.b save +a message, +.i Mail +usually discards it when you +.b quit . +To retain all saved messages, set the +.q keepsave +option. +.ip "\fBmetoo\fP\ \ " +When sending mail to an alias, +.i Mail +makes sure that if you are included in the alias, that mail will not +be sent to you. This is useful if a single alias is being used by +all members of the group. If however, you wish to receive a copy of +all the messages you send to the alias, you can set the binary option +.q metoo. +.ip "\fBnoheader\fP\ \ " +The binary option +.q noheader +suppresses the printing of the version and headers when +.i Mail +is first invoked. Setting this option is the same as using +.b \-N +on the command line. +.ip "\fBnosave\fP\ \ " +Normally, +when you abort a message with two \s-2RUBOUTs\s0, +.i Mail +copies the partial letter to the file +.q dead.letter +in your home directory. Setting the binary option +.q nosave +prevents this. +.ip "\fBReplyall\fP\ \ " +Reverses the sense of +.i reply +and +.i Reply +commands. +.ip "\fBquiet\fP\ \ " +The binary option +.q quiet +suppresses the printing of the version when +.i Mail +is first invoked, +as well as printing the for example +.q "Message 4:" +from the +.b type +command. +.ip "\fBrecord\fP\ \ " +If you love to keep records, then the +valued option +.q record +can be set to the name of a file to save your outgoing mail. +Each new message you send is appended to the end of the file. +.ip "\fBscreen\fP\ \ " +When +.i Mail +initially prints the message headers, it determines the number to +print by looking at the speed of your terminal. The faster your +terminal, the more it prints. +The valued option +.q screen +overrides this calculation and +specifies how many message headers you want printed. +This number is also used for scrolling with the +.b z +command. +.ip "\fBsendmail\fP\ \ " +To use an alternate mail delivery system, set the +.q sendmail +option to the full pathname of the program to use. Note: this is not +for everyone! Most people should use the default delivery system. +.ip "\fBtoplines\fP\ \ " +The valued option +.q toplines +defines the number of lines that the +.q top +command will print out instead of the default five lines. +.ip "\fBverbose\fP\ \ " +The binary option "verbose" causes +.i Mail +to invoke sendmail with the +.b \-v +flag, which causes it to go into verbose mode and announce expansion +of aliases, etc. Setting the "verbose" option is equivalent to +invoking +.i Mail +with the +.b \-v +flag as described in section 6. diff --git a/usr.bin/mail/USD.doc/mail6.nr b/usr.bin/mail/USD.doc/mail6.nr new file mode 100644 index 0000000..e016234 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail6.nr @@ -0,0 +1,125 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail6.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Command line options" +.pp +This section describes command line options for +.i Mail +and what they are used for. +.ip \-N +Suppress the initial printing of headers. +.ip \-d +Turn on debugging information. Not of general interest. +.ip "\-f file\ \ " +Show the messages in +.i file +instead of your system mailbox. If +.i file +is omitted, +.i Mail +reads +.i mbox +in your home directory. +.ip \-i +Ignore tty interrupt signals. Useful on noisy phone lines, which +generate spurious RUBOUT or DELETE characters. It's usually +more effective to change your interrupt character to control\-c, +for which see the +.i stty +shell command. +.ip \-n +Inhibit reading of /usr/lib/Mail.rc. Not generally useful, since +/usr/lib/Mail.rc is usually empty. +.ip "\-s string" +Used for sending mail. +.i String +is used as the subject of the message being composed. If +.i string +contains blanks, you must surround it with quote marks. +.ip "\-u name" +Read +.i names's +mail instead of your own. Unwitting others often neglect to protect +their mailboxes, but discretion is advised. Essentially, +.b "\-u user" +is a shorthand way of doing +.b "\-f /usr/spool/mail/user". +.ip "\-v" +Use the +.b \-v +flag when invoking sendmail. This feature may also be enabled +by setting the the option "verbose". +.pp +The following command line flags are also recognized, but are +intended for use by programs invoking +.i Mail +and not for people. +.ip "\-T file" +Arrange to print on +.i file +the contents of the +.i article-id +fields of all messages that were either read or deleted. +.b \-T +is for the +.i readnews +program and should NOT be used for reading your mail. +.ip "\-h number" +Pass on hop count information. +.i Mail +will take the number, increment it, and pass it with +.b \-h +to the mail delivery system. +.b \-h +only has effect when sending mail and is used for network mail +forwarding. +.ip "\-r name" +Used for network mail forwarding: interpret +.i name +as the sender of the message. The +.i name +and +.b \-r +are simply sent along to the mail delivery system. Also, +.i Mail +will wait for the message to be sent and return the exit status. +Also restricts formatting of message. +.pp +Note that +.b \-h +and +.b \-r , +which are for network mail forwarding, are not used in practice +since mail forwarding is now handled separately. They may +disappear soon. diff --git a/usr.bin/mail/USD.doc/mail7.nr b/usr.bin/mail/USD.doc/mail7.nr new file mode 100644 index 0000000..0b2590b --- /dev/null +++ b/usr.bin/mail/USD.doc/mail7.nr @@ -0,0 +1,107 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail7.nr 8.1 (Berkeley) 6/8/93 +.\" +.sh 1 "Format of messages" +.pp +This section describes the format of messages. +Messages begin with a +.i from +line, which consists of the word +.q From +followed by a user name, followed by anything, followed by +a date in the format returned by the +.i ctime +library routine described in section 3 of the Unix Programmer's +Manual. A possible +.i ctime +format date is: +.(l +Tue Dec 1 10:58:23 1981 +.)l +The +.i ctime +date may be optionally followed by a single space and a +time zone indication, which +should be three capital letters, such as PDT. +.pp +Following the +.i from +line are zero or more +.i "header field" +lines. +Each header field line is of the form: +.(l +name: information +.)l +.i Name +can be anything, but only certain header fields are recognized as +having any meaning. The recognized header fields are: +.i article-id , +.i bcc , +.i cc , +.i from , +.i reply-to , +.i sender , +.i subject , +and +.i to . +Other header fields are also significant to other systems; see, +for example, the current Arpanet message standard for much more +information on this topic. +A header field can be continued onto following lines by making the +first character on the following line a space or tab character. +.pp +If any headers are present, they must be followed by a blank line. +The part that follows is called the +.i body +of the message, and must be ASCII text, not containing null characters. +Each line in the message body must be no longer than 512 characters and +terminated with an ASCII newline character. +If binary data must be passed through the mail system, it is suggested +that this data be encoded in a system which encodes six bits into +a printable character (i.e.: uuencode). +For example, one could use the upper and lower case letters, the digits, +and the characters comma and period to make up the 64 characters. +Then, one can send a 16-bit binary number +as three characters. These characters should be packed into lines, +preferably lines about 70 characters long as long lines are transmitted +more efficiently. +.pp +The message delivery system always adds a blank line to the end of +each message. This blank line must not be deleted. +.pp +The UUCP message delivery system sometimes adds a blank line to +the end of a message each time it is forwarded through a machine. +.pp +It should be noted that some network transport protocols enforce +limits to the lengths of messages. diff --git a/usr.bin/mail/USD.doc/mail8.nr b/usr.bin/mail/USD.doc/mail8.nr new file mode 100644 index 0000000..e8e056b --- /dev/null +++ b/usr.bin/mail/USD.doc/mail8.nr @@ -0,0 +1,75 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail8.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Glossary" +.pp +This section contains the definitions of a few phrases +peculiar to +.i Mail . +.ip "\fIalias\fP" +An alternative name for a person or list of people. +.ip "\fIflag\fP" +An option, given on the command line of +.i Mail , +prefaced with a \-. For example, +.b \-f +is a flag. +.ip "\fIheader field\fP" +At the beginning of a message, a line which contains information +that is part of the structure of the message. Popular header fields +include +.i to , +.i cc , +and +.i subject . +.ip "\fImail\ \ \fP" +A collection of messages. Often used in the phrase, +.q "Have you read your mail?" +.ip "\fImailbox\fP" +The place where your mail is stored, typically in the directory +/usr/spool/mail. +.ip "\fImessage\fP" +A single letter from someone, initially stored in your +.i mailbox . +.ip "\fImessage list\fP" +A string used in +.i Mail +command mode to describe a sequence of messages. +.ip "\fIoption\fP" +A piece of special purpose information used to tailor +.i Mail +to your taste. +Options are specified with the +.b set +command. diff --git a/usr.bin/mail/USD.doc/mail9.nr b/usr.bin/mail/USD.doc/mail9.nr new file mode 100644 index 0000000..99f7518 --- /dev/null +++ b/usr.bin/mail/USD.doc/mail9.nr @@ -0,0 +1,203 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail9.nr 8.1 (Berkeley) 6/8/93 +.\" +.bp +.sh 1 "Summary of commands, options, and escapes" +.pp +This section gives a quick summary of the +.i Mail +commands, binary and valued options, and tilde escapes. +.pp +The following table describes the commands: +.TS +center ; +c ci +lb l. +Command Description +_ ++ Same as \fBnext\fP +- Back up to previous message +? Print brief summary of \fIMail\fP commands +! Single command escape to shell +Print Type message with ignored fields +Reply Reply to author of message only +Respond Same as \fBReply\fP +Type Type message with ignored fields +alias Define an alias as a set of user names +alternates List other names you are known by +chdir Change working directory, home by default +copy Copy a message to a file or folder +delete Delete a list of messages +dp Same as \fBdt\fP +dt Delete current message, type next message +edit Edit a list of messages +else Start of else part of conditional; see \fBif\fP +endif End of conditional statement; see \fBif\fP +exit Leave mail without changing anything +file Interrogate/change current mail file +folder Same as \fBfile\fP +folders List the folders in your folder directory +from List headers of a list of messages +headers List current window of messages +help Same as \fB?\fP +hold Same as \fBpreserve\fP +if Conditional execution of \fIMail\fP commands +ignore Set/examine list of ignored header fields +list List valid \fIMail\fP commands +local List other names for the local host +mail Send mail to specified names +mbox Arrange to save a list of messages in \fImbox\fP +next Go to next message and type it +preserve Arrange to leave list of messages in system mailbox +print Print messages +quit Leave \fIMail\fP; update system mailbox, \fImbox\fP as appropriate +reply Compose a reply to a message +respond Same as \fBreply\fP +retain Supersedes \fBignore\fP +save Append messages, headers included, on a file +set Set binary or valued options +shell Invoke an interactive shell +size Prints out size of message list +source Read \fImail\fP commands from a file +top Print first so many (5 by default) lines of list of messages +type Same as \fBprint\fP +undelete Undelete list of messages +unread Marks list of messages as not been read +unset Undo the operation of a \fBset\fP +visual Invoke visual editor on a list of messages +write Append messages to a file, don't include headers +xit Same as \fBexit\fP +z Scroll to next/previous screenful of headers +.TE +.bp +.(b +.pp +The following table describes the options. Each option is +shown as being either a binary or valued option. +.TS +center; +c ci ci +l ci l. +Option Type Description +_ +EDITOR valued Pathname of editor for ~e and \fBedit\fP +PAGER valued Pathname of paginator for \fBPrint\fP, \fBprint\fP, \fBType\fP and \fBtype\fP +SHELL valued Pathname of shell for \fBshell\fP, ~! and \fB!\fP +VISUAL valued Pathname of screen editor for ~v, \fBvisual\fP +append binary Always append messages to end of \fImbox\fP +ask binary Prompt user for Subject: field when sending +askcc binary Prompt user for additional Cc's at end of message +autoprint binary Print next message after \fBdelete\fP +crt valued Minimum number of lines before using \fBPAGER\fP +debug binary Print out debugging information +dot binary Accept . alone on line to terminate message input +escape valued Escape character to be used instead of\ \ ~ +folder valued Directory to store folders in +hold binary Hold messages in system mailbox by default +ignore binary Ignore \s-2RUBOUT\s0 while sending mail +ignoreeof binary Don't terminate letters/command input with \fB\(uaD\fP +keep binary Don't unlink system mailbox when empty +keepsave binary Don't delete \fBsave\fPd messages by default +metoo binary Include sending user in aliases +noheader binary Suppress initial printing of version and headers +nosave binary Don't save partial letter in \fIdead.letter\fP +quiet binary Suppress printing of \fIMail\fP version and message numbers +record valued File to save all outgoing mail in +screen valued Size of window of message headers for \fBz\fP, etc. +sendmail valued Choose alternate mail delivery system +toplines valued Number of lines to print in \fBtop\fP +verbose binary Invoke sendmail with the \fB\-v\fP flag +.TE +.)b +.(b +.pp +The following table summarizes the tilde escapes available +while sending mail. +.TS +center; +c ci ci +l li l. +Escape Arguments Description +_ +~! command Execute shell command +~b name ... Add names to "blind" Cc: list +~c name ... Add names to Cc: field +~d Read \fIdead.letter\fP into message +~e Invoke text editor on partial message +~f messages Read named messages +~h Edit the header fields +~m messages Read named messages, right shift by tab +~p Print message entered so far +~q Abort entry of letter; like \s-2RUBOUT\s0 +~r filename Read file into message +~s string Set Subject: field to \fIstring\fP +~t name ... Add names to To: field +~v Invoke screen editor on message +~w filename Write message on file +~| command Pipe message through \fIcommand\fP +~: Mail command Execute a \fIMail\fP command +~~ string Quote a ~ in front of \fIstring\fP +.TE +.)b +.(b +.pp +The following table shows the command line flags that +.i Mail +accepts: +.TS +center; +c c +l a. +Flag Description +_ +\-N Suppress the initial printing of headers +\-T \fIfile\fP Article-id's of read/deleted messages to \fIfile\fP +\-d Turn on debugging +\-f \fIfile\fP Show messages in \fIfile\fP or \fI~/mbox\fP +\-h \fInumber\fP Pass on hop count for mail forwarding +\-i Ignore tty interrupt signals +\-n Inhibit reading of /usr/lib/Mail.rc +\-r \fIname\fP Pass on \fIname\fP for mail forwarding +\-s \fIstring\fP Use \fIstring\fP as subject in outgoing mail +\-u \fIname\fP Read \fIname's\fP mail instead of your own +\-v Invoke sendmail with the \fB\-v\fP flag +.TE +.)b +.lp +Notes: +.b \-T , +.b \-d , +.b \-h , +and +.b \-r +are not for human use. diff --git a/usr.bin/mail/USD.doc/maila.nr b/usr.bin/mail/USD.doc/maila.nr new file mode 100644 index 0000000..84b01fe --- /dev/null +++ b/usr.bin/mail/USD.doc/maila.nr @@ -0,0 +1,33 @@ +.\" Copyright (c) 1980, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)maila.nr 8.1 (Berkeley) 6/8/93 +.\" diff --git a/usr.bin/mail/aux.c b/usr.bin/mail/aux.c new file mode 100644 index 0000000..f4c2acd --- /dev/null +++ b/usr.bin/mail/aux.c @@ -0,0 +1,705 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Auxiliary functions. + */ + +/* + * Return a pointer to a dynamic copy of the argument. + */ +char * +savestr(str) + char *str; +{ + char *new; + int size = strlen(str) + 1; + + if ((new = salloc(size)) != NOSTR) + bcopy(str, new, size); + return new; +} + +/* + * Make a copy of new argument incorporating old one. + */ +char * +save2str(str, old) + char *str, *old; +{ + char *new; + int newsize = strlen(str) + 1; + int oldsize = old ? strlen(old) + 1 : 0; + + if ((new = salloc(newsize + oldsize)) != NOSTR) { + if (oldsize) { + bcopy(old, new, oldsize); + new[oldsize - 1] = ' '; + } + bcopy(str, new + oldsize, newsize); + } + return new; +} + +/* + * Announce a fatal error and die. + */ +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +void +#if __STDC__ +panic(const char *fmt, ...) +#else +panic(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "panic: "); + vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + fflush(stderr); + abort(); +} + +/* + * Touch the named message by setting its MTOUCH flag. + * Touched messages have the effect of not being sent + * back to the system mailbox on exit. + */ +void +touch(mp) + register struct message *mp; +{ + + mp->m_flag |= MTOUCH; + if ((mp->m_flag & MREAD) == 0) + mp->m_flag |= MREAD|MSTATUS; +} + +/* + * Test to see if the passed file name is a directory. + * Return true if it is. + */ +int +isdir(name) + char name[]; +{ + struct stat sbuf; + + if (stat(name, &sbuf) < 0) + return(0); + return((sbuf.st_mode & S_IFMT) == S_IFDIR); +} + +/* + * Count the number of arguments in the given string raw list. + */ +int +argcount(argv) + char **argv; +{ + register char **ap; + + for (ap = argv; *ap++ != NOSTR;) + ; + return ap - argv - 1; +} + +/* + * Return the desired header line from the passed message + * pointer (or NOSTR if the desired header field is not available). + */ +char * +hfield(field, mp) + char field[]; + struct message *mp; +{ + register FILE *ibuf; + char linebuf[LINESIZE]; + register int lc; + register char *hfield; + char *colon, *oldhfield = NOSTR; + + ibuf = setinput(mp); + if ((lc = mp->m_lines - 1) < 0) + return NOSTR; + if (readline(ibuf, linebuf, LINESIZE) < 0) + return NOSTR; + while (lc > 0) { + if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) + return oldhfield; + if (hfield = ishfield(linebuf, colon, field)) + oldhfield = save2str(hfield, oldhfield); + } + return oldhfield; +} + +/* + * Return the next header field found in the given message. + * Return >= 0 if something found, < 0 elsewise. + * "colon" is set to point to the colon in the header. + * Must deal with \ continuations & other such fraud. + */ +int +gethfield(f, linebuf, rem, colon) + register FILE *f; + char linebuf[]; + register int rem; + char **colon; +{ + char line2[LINESIZE]; + register char *cp, *cp2; + register int c; + + for (;;) { + if (--rem < 0) + return -1; + if ((c = readline(f, linebuf, LINESIZE)) <= 0) + return -1; + for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':'; + cp++) + ; + if (*cp != ':' || cp == linebuf) + continue; + /* + * I guess we got a headline. + * Handle wraparounding + */ + *colon = cp; + cp = linebuf + c; + for (;;) { + while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) + ; + cp++; + if (rem <= 0) + break; + ungetc(c = getc(f), f); + if (c != ' ' && c != '\t') + break; + if ((c = readline(f, line2, LINESIZE)) < 0) + break; + rem--; + for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) + ; + c -= cp2 - line2; + if (cp + c >= linebuf + LINESIZE - 2) + break; + *cp++ = ' '; + bcopy(cp2, cp, c); + cp += c; + } + *cp = 0; + return rem; + } + /* NOTREACHED */ +} + +/* + * Check whether the passed line is a header line of + * the desired breed. Return the field body, or 0. + */ + +char* +ishfield(linebuf, colon, field) + char linebuf[], field[]; + char *colon; +{ + register char *cp = colon; + + *cp = 0; + if (strcasecmp(linebuf, field) != 0) { + *cp = ':'; + return 0; + } + *cp = ':'; + for (cp++; *cp == ' ' || *cp == '\t'; cp++) + ; + return cp; +} + +/* + * Copy a string, lowercasing it as we go. + */ +void +istrcpy(dest, src) + register char *dest, *src; +{ + + do { + if (isupper(*src)) + *dest++ = tolower(*src); + else + *dest++ = *src; + } while (*src++ != 0); +} + +/* + * The following code deals with input stacking to do source + * commands. All but the current file pointer are saved on + * the stack. + */ + +static int ssp; /* Top of file stack */ +struct sstack { + FILE *s_file; /* File we were in. */ + int s_cond; /* Saved state of conditionals */ + int s_loading; /* Loading .mailrc, etc. */ +} sstack[NOFILE]; + +/* + * Pushdown current input file and switch to a new one. + * Set the global flag "sourcing" so that others will realize + * that they are no longer reading from a tty (in all probability). + */ +int +source(arglist) + char **arglist; +{ + FILE *fi; + char *cp; + + if ((cp = expand(*arglist)) == NOSTR) + return(1); + if ((fi = Fopen(cp, "r")) == NULL) { + perror(cp); + return(1); + } + if (ssp >= NOFILE - 1) { + printf("Too much \"sourcing\" going on.\n"); + Fclose(fi); + return(1); + } + sstack[ssp].s_file = input; + sstack[ssp].s_cond = cond; + sstack[ssp].s_loading = loading; + ssp++; + loading = 0; + cond = CANY; + input = fi; + sourcing++; + return(0); +} + +/* + * Pop the current input back to the previous level. + * Update the "sourcing" flag as appropriate. + */ +int +unstack() +{ + if (ssp <= 0) { + printf("\"Source\" stack over-pop.\n"); + sourcing = 0; + return(1); + } + Fclose(input); + if (cond != CANY) + printf("Unmatched \"if\"\n"); + ssp--; + cond = sstack[ssp].s_cond; + loading = sstack[ssp].s_loading; + input = sstack[ssp].s_file; + if (ssp == 0) + sourcing = loading; + return(0); +} + +/* + * Touch the indicated file. + * This is nifty for the shell. + */ +void +alter(name) + char *name; +{ + struct stat sb; + struct timeval tv[2]; + time_t time(); + + if (stat(name, &sb)) + return; + tv[0].tv_sec = time((time_t *)0) + 1; + tv[1].tv_sec = sb.st_mtime; + tv[0].tv_usec = tv[1].tv_usec = 0; + (void)utimes(name, tv); +} + +/* + * Examine the passed line buffer and + * return true if it is all blanks and tabs. + */ +int +blankline(linebuf) + char linebuf[]; +{ + register char *cp; + + for (cp = linebuf; *cp; cp++) + if (*cp != ' ' && *cp != '\t') + return(0); + return(1); +} + +/* + * Get sender's name from this message. If the message has + * a bunch of arpanet stuff in it, we may have to skin the name + * before returning it. + */ +char * +nameof(mp, reptype) + register struct message *mp; + int reptype; +{ + register char *cp, *cp2; + + cp = skin(name1(mp, reptype)); + if (reptype != 0 || charcount(cp, '!') < 2) + return(cp); + cp2 = rindex(cp, '!'); + cp2--; + while (cp2 > cp && *cp2 != '!') + cp2--; + if (*cp2 == '!') + return(cp2 + 1); + return(cp); +} + +/* + * Start of a "comment". + * Ignore it. + */ +char * +skip_comment(cp) + register char *cp; +{ + register nesting = 1; + + for (; nesting > 0 && *cp; cp++) { + switch (*cp) { + case '\\': + if (cp[1]) + cp++; + break; + case '(': + nesting++; + break; + case ')': + nesting--; + break; + } + } + return cp; +} + +/* + * Skin an arpa net address according to the RFC 822 interpretation + * of "host-phrase." + */ +char * +skin(name) + char *name; +{ + register int c; + register char *cp, *cp2; + char *bufend; + int gotlt, lastsp; + char nbuf[BUFSIZ]; + + if (name == NOSTR) + return(NOSTR); + if (index(name, '(') == NOSTR && index(name, '<') == NOSTR + && index(name, ' ') == NOSTR) + return(name); + gotlt = 0; + lastsp = 0; + bufend = nbuf; + for (cp = name, cp2 = bufend; c = *cp++; ) { + switch (c) { + case '(': + cp = skip_comment(cp); + lastsp = 0; + break; + + case '"': + /* + * Start of a "quoted-string". + * Copy it in its entirety. + */ + while (c = *cp) { + cp++; + if (c == '"') + break; + if (c != '\\') + *cp2++ = c; + else if (c = *cp) { + *cp2++ = c; + cp++; + } + } + lastsp = 0; + break; + + case ' ': + if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') + cp += 3, *cp2++ = '@'; + else + if (cp[0] == '@' && cp[1] == ' ') + cp += 2, *cp2++ = '@'; + else + lastsp = 1; + break; + + case '<': + cp2 = bufend; + gotlt++; + lastsp = 0; + break; + + case '>': + if (gotlt) { + gotlt = 0; + while ((c = *cp) && c != ',') { + cp++; + if (c == '(') + cp = skip_comment(cp); + else if (c == '"') + while (c = *cp) { + cp++; + if (c == '"') + break; + if (c == '\\' && *cp) + cp++; + } + } + lastsp = 0; + break; + } + /* Fall into . . . */ + + default: + if (lastsp) { + lastsp = 0; + *cp2++ = ' '; + } + *cp2++ = c; + if (c == ',' && !gotlt) { + *cp2++ = ' '; + for (; *cp == ' '; cp++) + ; + lastsp = 0; + bufend = cp2; + } + } + } + *cp2 = 0; + + return(savestr(nbuf)); +} + +/* + * Fetch the sender's name from the passed message. + * Reptype can be + * 0 -- get sender's name for display purposes + * 1 -- get sender's name for reply + * 2 -- get sender's name for Reply + */ +char * +name1(mp, reptype) + register struct message *mp; + int reptype; +{ + char namebuf[LINESIZE]; + char linebuf[LINESIZE]; + register char *cp, *cp2; + register FILE *ibuf; + int first = 1; + + if ((cp = hfield("from", mp)) != NOSTR) + return cp; + if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR) + return cp; + ibuf = setinput(mp); + namebuf[0] = 0; + if (readline(ibuf, linebuf, LINESIZE) < 0) + return(savestr(namebuf)); +newname: + for (cp = linebuf; *cp && *cp != ' '; cp++) + ; + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + for (cp2 = &namebuf[strlen(namebuf)]; + *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;) + *cp2++ = *cp++; + *cp2 = '\0'; + if (readline(ibuf, linebuf, LINESIZE) < 0) + return(savestr(namebuf)); + if ((cp = index(linebuf, 'F')) == NULL) + return(savestr(namebuf)); + if (strncmp(cp, "From", 4) != 0) + return(savestr(namebuf)); + while ((cp = index(cp, 'r')) != NULL) { + if (strncmp(cp, "remote", 6) == 0) { + if ((cp = index(cp, 'f')) == NULL) + break; + if (strncmp(cp, "from", 4) != 0) + break; + if ((cp = index(cp, ' ')) == NULL) + break; + cp++; + if (first) { + strcpy(namebuf, cp); + first = 0; + } else + strcpy(rindex(namebuf, '!')+1, cp); + strcat(namebuf, "!"); + goto newname; + } + cp++; + } + return(savestr(namebuf)); +} + +/* + * Count the occurances of c in str + */ +int +charcount(str, c) + char *str; + int c; +{ + register char *cp; + register int i; + + for (i = 0, cp = str; *cp; cp++) + if (*cp == c) + i++; + return(i); +} + +/* + * Are any of the characters in the two strings the same? + */ +int +anyof(s1, s2) + register char *s1, *s2; +{ + + while (*s1) + if (index(s2, *s1++)) + return 1; + return 0; +} + +/* + * Convert c to upper case + */ +int +raise(c) + register int c; +{ + + if (islower(c)) + return toupper(c); + return c; +} + +/* + * Copy s1 to s2, return pointer to null in s2. + */ +char * +copy(s1, s2) + register char *s1, *s2; +{ + + while (*s2++ = *s1++) + ; + return s2 - 1; +} + +/* + * See if the given header field is supposed to be ignored. + */ +int +isign(field, ignore) + char *field; + struct ignoretab ignore[2]; +{ + char realfld[BUFSIZ]; + + if (ignore == ignoreall) + return 1; + /* + * Lower-case the string, so that "Status" and "status" + * will hash to the same place. + */ + istrcpy(realfld, field); + if (ignore[1].i_count > 0) + return (!member(realfld, ignore + 1)); + else + return (member(realfld, ignore)); +} + +int +member(realfield, table) + register char *realfield; + struct ignoretab *table; +{ + register struct ignore *igp; + + for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link) + if (*igp->i_field == *realfield && + equal(igp->i_field, realfield)) + return (1); + return (0); +} diff --git a/usr.bin/mail/cmd1.c b/usr.bin/mail/cmd1.c new file mode 100644 index 0000000..e83a036 --- /dev/null +++ b/usr.bin/mail/cmd1.c @@ -0,0 +1,451 @@ +/*- + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)cmd1.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * User commands. + */ + +/* + * Print the current active headings. + * Don't change dot if invoker didn't give an argument. + */ + +static int screen; + +int +headers(msgvec) + int *msgvec; +{ + register int n, mesg, flag; + register struct message *mp; + int size; + + size = screensize(); + n = msgvec[0]; + if (n != 0) + screen = (n-1)/size; + if (screen < 0) + screen = 0; + mp = &message[screen * size]; + if (mp >= &message[msgCount]) + mp = &message[msgCount - size]; + if (mp < &message[0]) + mp = &message[0]; + flag = 0; + mesg = mp - &message[0]; + if (dot != &message[n-1]) + dot = mp; + for (; mp < &message[msgCount]; mp++) { + mesg++; + if (mp->m_flag & MDELETED) + continue; + if (flag++ >= size) + break; + printhead(mesg); + } + if (flag == 0) { + printf("No more mail.\n"); + return(1); + } + return(0); +} + +/* + * Scroll to the next/previous screen + */ +int +scroll(arg) + char arg[]; +{ + register int s, size; + int cur[1]; + + cur[0] = 0; + size = screensize(); + s = screen; + switch (*arg) { + case 0: + case '+': + s++; + if (s * size > msgCount) { + printf("On last screenful of messages\n"); + return(0); + } + screen = s; + break; + + case '-': + if (--s < 0) { + printf("On first screenful of messages\n"); + return(0); + } + screen = s; + break; + + default: + printf("Unrecognized scrolling command \"%s\"\n", arg); + return(1); + } + return(headers(cur)); +} + +/* + * Compute screen size. + */ +int +screensize() +{ + int s; + char *cp; + + if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0) + return s; + return screenheight - 4; +} + +/* + * Print out the headlines for each message + * in the passed message list. + */ +int +from(msgvec) + int *msgvec; +{ + register int *ip; + + for (ip = msgvec; *ip != NULL; ip++) + printhead(*ip); + if (--ip >= msgvec) + dot = &message[*ip - 1]; + return(0); +} + +/* + * Print out the header of a specific message. + * This is a slight improvement to the standard one. + */ +void +printhead(mesg) + int mesg; +{ + struct message *mp; + char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; + char pbuf[BUFSIZ]; + struct headline hl; + int subjlen; + char *name; + + mp = &message[mesg-1]; + (void) readline(setinput(mp), headline, LINESIZE); + if ((subjline = hfield("subject", mp)) == NOSTR) + subjline = hfield("subj", mp); + /* + * Bletch! + */ + curind = dot == mp ? '>' : ' '; + dispc = ' '; + if (mp->m_flag & MSAVED) + dispc = '*'; + if (mp->m_flag & MPRESERVE) + dispc = 'P'; + if ((mp->m_flag & (MREAD|MNEW)) == MNEW) + dispc = 'N'; + if ((mp->m_flag & (MREAD|MNEW)) == 0) + dispc = 'U'; + if (mp->m_flag & MBOX) + dispc = 'M'; + parse(headline, &hl, pbuf); + sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size); + subjlen = screenwidth - 50 - strlen(wcount); + name = value("show-rcpt") != NOSTR ? + skin(hfield("to", mp)) : nameof(mp, 0); + if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */ + printf("%c%c%3d %-20.20s %16.16s %s\n", + curind, dispc, mesg, name, hl.l_date, wcount); + else + printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", + curind, dispc, mesg, name, hl.l_date, wcount, + subjlen, subjline); +} + +/* + * Print out the value of dot. + */ +int +pdot() +{ + printf("%d\n", dot - &message[0] + 1); + return(0); +} + +/* + * Print out all the possible commands. + */ +int +pcmdlist() +{ + register struct cmd *cp; + register int cc; + extern struct cmd cmdtab[]; + + printf("Commands are:\n"); + for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { + cc += strlen(cp->c_name) + 2; + if (cc > 72) { + printf("\n"); + cc = strlen(cp->c_name) + 2; + } + if ((cp+1)->c_name != NOSTR) + printf("%s, ", cp->c_name); + else + printf("%s\n", cp->c_name); + } + return(0); +} + +/* + * Paginate messages, honor ignored fields. + */ +int +more(msgvec) + int *msgvec; +{ + return (type1(msgvec, 1, 1)); +} + +/* + * Paginate messages, even printing ignored fields. + */ +int +More(msgvec) + int *msgvec; +{ + + return (type1(msgvec, 0, 1)); +} + +/* + * Type out messages, honor ignored fields. + */ +int +type(msgvec) + int *msgvec; +{ + + return(type1(msgvec, 1, 0)); +} + +/* + * Type out messages, even printing ignored fields. + */ +int +Type(msgvec) + int *msgvec; +{ + + return(type1(msgvec, 0, 0)); +} + +/* + * Type out the messages requested. + */ +jmp_buf pipestop; +int +type1(msgvec, doign, page) + int *msgvec; + int doign, page; +{ + register *ip; + register struct message *mp; + register char *cp; + int nlines; + FILE *obuf; + + obuf = stdout; + if (setjmp(pipestop)) + goto close_pipe; + if (value("interactive") != NOSTR && + (page || (cp = value("crt")) != NOSTR)) { + nlines = 0; + if (!page) { + for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) + nlines += message[*ip - 1].m_lines; + } + if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { + cp = value("PAGER"); + if (cp == NULL || *cp == '\0') + cp = _PATH_MORE; + obuf = Popen(cp, "w"); + if (obuf == NULL) { + perror(cp); + obuf = stdout; + } else + signal(SIGPIPE, brokpipe); + } + } + for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { + mp = &message[*ip - 1]; + touch(mp); + dot = mp; + if (value("quiet") == NOSTR) + fprintf(obuf, "Message %d:\n", *ip); + (void) send(mp, obuf, doign ? ignore : 0, NOSTR); + } +close_pipe: + if (obuf != stdout) { + /* + * Ignore SIGPIPE so it can't cause a duplicate close. + */ + signal(SIGPIPE, SIG_IGN); + Pclose(obuf); + signal(SIGPIPE, SIG_DFL); + } + return(0); +} + +/* + * Respond to a broken pipe signal -- + * probably caused by quitting more. + */ +void +brokpipe(signo) + int signo; +{ + longjmp(pipestop, 1); +} + +/* + * Print the top so many lines of each desired message. + * The number of lines is taken from the variable "toplines" + * and defaults to 5. + */ +int +top(msgvec) + int *msgvec; +{ + register int *ip; + register struct message *mp; + int c, topl, lines, lineb; + char *valtop, linebuf[LINESIZE]; + FILE *ibuf; + + topl = 5; + valtop = value("toplines"); + if (valtop != NOSTR) { + topl = atoi(valtop); + if (topl < 0 || topl > 10000) + topl = 5; + } + lineb = 1; + for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { + mp = &message[*ip - 1]; + touch(mp); + dot = mp; + if (value("quiet") == NOSTR) + printf("Message %d:\n", *ip); + ibuf = setinput(mp); + c = mp->m_lines; + if (!lineb) + printf("\n"); + for (lines = 0; lines < c && lines <= topl; lines++) { + if (readline(ibuf, linebuf, LINESIZE) < 0) + break; + puts(linebuf); + lineb = blankline(linebuf); + } + } + return(0); +} + +/* + * Touch all the given messages so that they will + * get mboxed. + */ +int +stouch(msgvec) + int msgvec[]; +{ + register int *ip; + + for (ip = msgvec; *ip != 0; ip++) { + dot = &message[*ip-1]; + dot->m_flag |= MTOUCH; + dot->m_flag &= ~MPRESERVE; + } + return(0); +} + +/* + * Make sure all passed messages get mboxed. + */ +int +mboxit(msgvec) + int msgvec[]; +{ + register int *ip; + + for (ip = msgvec; *ip != 0; ip++) { + dot = &message[*ip-1]; + dot->m_flag |= MTOUCH|MBOX; + dot->m_flag &= ~MPRESERVE; + } + return(0); +} + +/* + * List the folders the user currently has. + */ +int +folders() +{ + char dirname[BUFSIZ]; + char *cmd; + + if (getfold(dirname) < 0) { + printf("No value set for \"folder\"\n"); + return 1; + } + if ((cmd = value("LISTER")) == NOSTR) + cmd = "ls"; + (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR); + return 0; +} diff --git a/usr.bin/mail/cmd2.c b/usr.bin/mail/cmd2.c new file mode 100644 index 0000000..abe3ca9 --- /dev/null +++ b/usr.bin/mail/cmd2.c @@ -0,0 +1,530 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include <sys/wait.h> +#include "extern.h" + +/* + * Mail -- a mail program + * + * More user commands. + */ + +/* + * If any arguments were given, go to the next applicable argument + * following dot, otherwise, go to the next applicable message. + * If given as first command with no arguments, print first message. + */ +int +next(msgvec) + int *msgvec; +{ + register struct message *mp; + register int *ip, *ip2; + int list[2], mdot; + + if (*msgvec != NULL) { + + /* + * If some messages were supplied, find the + * first applicable one following dot using + * wrap around. + */ + + mdot = dot - &message[0] + 1; + + /* + * Find the first message in the supplied + * message list which follows dot. + */ + + for (ip = msgvec; *ip != NULL; ip++) + if (*ip > mdot) + break; + if (*ip == NULL) + ip = msgvec; + ip2 = ip; + do { + mp = &message[*ip2 - 1]; + if ((mp->m_flag & MDELETED) == 0) { + dot = mp; + goto hitit; + } + if (*ip2 != NULL) + ip2++; + if (*ip2 == NULL) + ip2 = msgvec; + } while (ip2 != ip); + printf("No messages applicable\n"); + return(1); + } + + /* + * If this is the first command, select message 1. + * Note that this must exist for us to get here at all. + */ + + if (!sawcom) + goto hitit; + + /* + * Just find the next good message after dot, no + * wraparound. + */ + + for (mp = dot+1; mp < &message[msgCount]; mp++) + if ((mp->m_flag & (MDELETED|MSAVED)) == 0) + break; + if (mp >= &message[msgCount]) { + printf("At EOF\n"); + return(0); + } + dot = mp; +hitit: + /* + * Print dot. + */ + + list[0] = dot - &message[0] + 1; + list[1] = NULL; + return(type(list)); +} + +/* + * Save a message in a file. Mark the message as saved + * so we can discard when the user quits. + */ +int +save(str) + char str[]; +{ + + return save1(str, 1, "save", saveignore); +} + +/* + * Copy a message to a file without affected its saved-ness + */ +int +copycmd(str) + char str[]; +{ + + return save1(str, 0, "copy", saveignore); +} + +/* + * Save/copy the indicated messages at the end of the passed file name. + * If mark is true, mark the message "saved." + */ +int +save1(str, mark, cmd, ignore) + char str[]; + int mark; + char *cmd; + struct ignoretab *ignore; +{ + register int *ip; + register struct message *mp; + char *file, *disp; + int f, *msgvec; + FILE *obuf; + + msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec); + if ((file = snarf(str, &f)) == NOSTR) + return(1); + if (!f) { + *msgvec = first(0, MMNORM); + if (*msgvec == NULL) { + printf("No messages to %s.\n", cmd); + return(1); + } + msgvec[1] = NULL; + } + if (f && getmsglist(str, msgvec, 0) < 0) + return(1); + if ((file = expand(file)) == NOSTR) + return(1); + printf("\"%s\" ", file); + fflush(stdout); + if (access(file, 0) >= 0) + disp = "[Appended]"; + else + disp = "[New file]"; + if ((obuf = Fopen(file, "a")) == NULL) { + perror(NOSTR); + return(1); + } + for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { + mp = &message[*ip - 1]; + touch(mp); + if (send(mp, obuf, ignore, NOSTR) < 0) { + perror(file); + Fclose(obuf); + return(1); + } + if (mark) + mp->m_flag |= MSAVED; + } + fflush(obuf); + if (ferror(obuf)) + perror(file); + Fclose(obuf); + printf("%s\n", disp); + return(0); +} + +/* + * Write the indicated messages at the end of the passed + * file name, minus header and trailing blank line. + */ +int +swrite(str) + char str[]; +{ + + return save1(str, 1, "write", ignoreall); +} + +/* + * Snarf the file from the end of the command line and + * return a pointer to it. If there is no file attached, + * just return NOSTR. Put a null in front of the file + * name so that the message list processing won't see it, + * unless the file name is the only thing on the line, in + * which case, return 0 in the reference flag variable. + */ + +char * +snarf(linebuf, flag) + char linebuf[]; + int *flag; +{ + register char *cp; + + *flag = 1; + cp = strlen(linebuf) + linebuf - 1; + + /* + * Strip away trailing blanks. + */ + + while (cp > linebuf && isspace(*cp)) + cp--; + *++cp = 0; + + /* + * Now search for the beginning of the file name. + */ + + while (cp > linebuf && !isspace(*cp)) + cp--; + if (*cp == '\0') { + printf("No file specified.\n"); + return(NOSTR); + } + if (isspace(*cp)) + *cp++ = 0; + else + *flag = 0; + return(cp); +} + +/* + * Delete messages. + */ +int +delete(msgvec) + int msgvec[]; +{ + delm(msgvec); + return 0; +} + +/* + * Delete messages, then type the new dot. + */ +int +deltype(msgvec) + int msgvec[]; +{ + int list[2]; + int lastdot; + + lastdot = dot - &message[0] + 1; + if (delm(msgvec) >= 0) { + list[0] = dot - &message[0] + 1; + if (list[0] > lastdot) { + touch(dot); + list[1] = NULL; + return(type(list)); + } + printf("At EOF\n"); + } else + printf("No more messages\n"); + return(0); +} + +/* + * Delete the indicated messages. + * Set dot to some nice place afterwards. + * Internal interface. + */ +int +delm(msgvec) + int *msgvec; +{ + register struct message *mp; + register *ip; + int last; + + last = NULL; + for (ip = msgvec; *ip != NULL; ip++) { + mp = &message[*ip - 1]; + touch(mp); + mp->m_flag |= MDELETED|MTOUCH; + mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); + last = *ip; + } + if (last != NULL) { + dot = &message[last-1]; + last = first(0, MDELETED); + if (last != NULL) { + dot = &message[last-1]; + return(0); + } + else { + dot = &message[0]; + return(-1); + } + } + + /* + * Following can't happen -- it keeps lint happy + */ + + return(-1); +} + +/* + * Undelete the indicated messages. + */ +int +undelete(msgvec) + int *msgvec; +{ + register struct message *mp; + register *ip; + + for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { + mp = &message[*ip - 1]; + touch(mp); + dot = mp; + mp->m_flag &= ~MDELETED; + } + return 0; +} + +/* + * Interactively dump core on "core" + */ +int +core() +{ + int pid; + extern union wait wait_status; + + switch (pid = vfork()) { + case -1: + perror("fork"); + return(1); + case 0: + abort(); + _exit(1); + } + printf("Okie dokie"); + fflush(stdout); + wait_child(pid); + if (wait_status.w_coredump) + printf(" -- Core dumped.\n"); + else + printf(" -- Can't dump core.\n"); + return 0; +} + +/* + * Clobber as many bytes of stack as the user requests. + */ +int +clobber(argv) + char **argv; +{ + register int times; + + if (argv[0] == 0) + times = 1; + else + times = (atoi(argv[0]) + 511) / 512; + clob1(times); + return 0; +} + +/* + * Clobber the stack. + */ +void +clob1(n) + int n; +{ + char buf[512]; + register char *cp; + + if (n <= 0) + return; + for (cp = buf; cp < &buf[512]; *cp++ = 0xFF) + ; + clob1(n - 1); +} + +/* + * Add the given header fields to the retained list. + * If no arguments, print the current list of retained fields. + */ +int +retfield(list) + char *list[]; +{ + + return ignore1(list, ignore + 1, "retained"); +} + +/* + * Add the given header fields to the ignored list. + * If no arguments, print the current list of ignored fields. + */ +int +igfield(list) + char *list[]; +{ + + return ignore1(list, ignore, "ignored"); +} + +int +saveretfield(list) + char *list[]; +{ + + return ignore1(list, saveignore + 1, "retained"); +} + +int +saveigfield(list) + char *list[]; +{ + + return ignore1(list, saveignore, "ignored"); +} + +int +ignore1(list, tab, which) + char *list[]; + struct ignoretab *tab; + char *which; +{ + char field[BUFSIZ]; + register int h; + register struct ignore *igp; + char **ap; + + if (*list == NOSTR) + return igshow(tab, which); + for (ap = list; *ap != 0; ap++) { + istrcpy(field, *ap); + if (member(field, tab)) + continue; + h = hash(field); + igp = (struct ignore *) calloc(1, sizeof (struct ignore)); + igp->i_field = calloc((unsigned) strlen(field) + 1, + sizeof (char)); + strcpy(igp->i_field, field); + igp->i_link = tab->i_head[h]; + tab->i_head[h] = igp; + tab->i_count++; + } + return 0; +} + +/* + * Print out all currently retained fields. + */ +int +igshow(tab, which) + struct ignoretab *tab; + char *which; +{ + register int h; + struct ignore *igp; + char **ap, **ring; + int igcomp(); + + if (tab->i_count == 0) { + printf("No fields currently being %s.\n", which); + return 0; + } + ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); + ap = ring; + for (h = 0; h < HSHSIZE; h++) + for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) + *ap++ = igp->i_field; + *ap = 0; + qsort(ring, tab->i_count, sizeof (char *), igcomp); + for (ap = ring; *ap != 0; ap++) + printf("%s\n", *ap); + return 0; +} + +/* + * Compare two names for sorting ignored field list. + */ +int +igcomp(l, r) + const void *l, *r; +{ + return (strcmp(*(char **)l, *(char **)r)); +} diff --git a/usr.bin/mail/cmd3.c b/usr.bin/mail/cmd3.c new file mode 100644 index 0000000..54a5d5e --- /dev/null +++ b/usr.bin/mail/cmd3.c @@ -0,0 +1,730 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)cmd3.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Still more user commands. + */ + +/* + * Process a shell escape by saving signals, ignoring signals, + * and forking a sh -c + */ +int +shell(str) + char *str; +{ + sig_t sigint = signal(SIGINT, SIG_IGN); + char *shell; + char cmd[BUFSIZ]; + + (void) strcpy(cmd, str); + if (bangexp(cmd) < 0) + return 1; + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + (void) run_command(shell, 0, -1, -1, "-c", cmd, NOSTR); + (void) signal(SIGINT, sigint); + printf("!\n"); + return 0; +} + +/* + * Fork an interactive shell. + */ +/*ARGSUSED*/ +int +dosh(str) + char *str; +{ + sig_t sigint = signal(SIGINT, SIG_IGN); + char *shell; + + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + (void) run_command(shell, 0, -1, -1, NOSTR, NOSTR, NOSTR); + (void) signal(SIGINT, sigint); + putchar('\n'); + return 0; +} + +/* + * Expand the shell escape by expanding unescaped !'s into the + * last issued command where possible. + */ + +char lastbang[128]; + +int +bangexp(str) + char *str; +{ + char bangbuf[BUFSIZ]; + register char *cp, *cp2; + register int n; + int changed = 0; + + cp = str; + cp2 = bangbuf; + n = BUFSIZ; + while (*cp) { + if (*cp == '!') { + if (n < strlen(lastbang)) { +overf: + printf("Command buffer overflow\n"); + return(-1); + } + changed++; + strcpy(cp2, lastbang); + cp2 += strlen(lastbang); + n -= strlen(lastbang); + cp++; + continue; + } + if (*cp == '\\' && cp[1] == '!') { + if (--n <= 1) + goto overf; + *cp2++ = '!'; + cp += 2; + changed++; + } + if (--n <= 1) + goto overf; + *cp2++ = *cp++; + } + *cp2 = 0; + if (changed) { + printf("!%s\n", bangbuf); + fflush(stdout); + } + strcpy(str, bangbuf); + strncpy(lastbang, bangbuf, 128); + lastbang[127] = 0; + return(0); +} + +/* + * Print out a nice help message from some file or another. + */ + +int +help() +{ + register c; + register FILE *f; + + if ((f = Fopen(_PATH_HELP, "r")) == NULL) { + perror(_PATH_HELP); + return(1); + } + while ((c = getc(f)) != EOF) + putchar(c); + Fclose(f); + return(0); +} + +/* + * Change user's working directory. + */ +int +schdir(arglist) + char **arglist; +{ + char *cp; + + if (*arglist == NOSTR) + cp = homedir; + else + if ((cp = expand(*arglist)) == NOSTR) + return(1); + if (chdir(cp) < 0) { + perror(cp); + return(1); + } + return 0; +} + +int +respond(msgvec) + int *msgvec; +{ + if (value("Replyall") == NOSTR) + return (_respond(msgvec)); + else + return (_Respond(msgvec)); +} + +/* + * Reply to a list of messages. Extract each name from the + * message header and send them off to mail1() + */ +int +_respond(msgvec) + int *msgvec; +{ + struct message *mp; + char *cp, *rcv, *replyto; + char **ap; + struct name *np; + struct header head; + + if (msgvec[1] != 0) { + printf("Sorry, can't reply to multiple messages at once\n"); + return(1); + } + mp = &message[msgvec[0] - 1]; + touch(mp); + dot = mp; + if ((rcv = skin(hfield("from", mp))) == NOSTR) + rcv = skin(nameof(mp, 1)); + if ((replyto = skin(hfield("reply-to", mp))) != NOSTR) + np = extract(replyto, GTO); + else if ((cp = skin(hfield("to", mp))) != NOSTR) + np = extract(cp, GTO); + else + np = NIL; + np = elide(np); + /* + * Delete my name from the reply list, + * and with it, all my alternate names. + */ + np = delname(np, myname); + if (altnames) + for (ap = altnames; *ap; ap++) + np = delname(np, *ap); + if (np != NIL && replyto == NOSTR) + np = cat(np, extract(rcv, GTO)); + else if (np == NIL) { + if (replyto != NOSTR) + printf("Empty reply-to field -- replying to author\n"); + np = extract(rcv, GTO); + } + head.h_to = np; + if ((head.h_subject = hfield("subject", mp)) == NOSTR) + head.h_subject = hfield("subj", mp); + head.h_subject = reedit(head.h_subject); + if (replyto == NOSTR && (cp = skin(hfield("cc", mp))) != NOSTR) { + np = elide(extract(cp, GCC)); + np = delname(np, myname); + if (altnames != 0) + for (ap = altnames; *ap; ap++) + np = delname(np, *ap); + head.h_cc = np; + } else + head.h_cc = NIL; + head.h_bcc = NIL; + head.h_smopts = NIL; + mail1(&head, 1); + return(0); +} + +/* + * Modify the subject we are replying to to begin with Re: if + * it does not already. + */ +char * +reedit(subj) + register char *subj; +{ + char *newsubj; + + if (subj == NOSTR) + return NOSTR; + if ((subj[0] == 'r' || subj[0] == 'R') && + (subj[1] == 'e' || subj[1] == 'E') && + subj[2] == ':') + return subj; + newsubj = salloc(strlen(subj) + 5); + strcpy(newsubj, "Re: "); + strcpy(newsubj + 4, subj); + return newsubj; +} + +/* + * Preserve the named messages, so that they will be sent + * back to the system mailbox. + */ +int +preserve(msgvec) + int *msgvec; +{ + register struct message *mp; + register int *ip, mesg; + + if (edit) { + printf("Cannot \"preserve\" in edit mode\n"); + return(1); + } + for (ip = msgvec; *ip != NULL; ip++) { + mesg = *ip; + mp = &message[mesg-1]; + mp->m_flag |= MPRESERVE; + mp->m_flag &= ~MBOX; + dot = mp; + } + return(0); +} + +/* + * Mark all given messages as unread. + */ +int +unread(msgvec) + int msgvec[]; +{ + register int *ip; + + for (ip = msgvec; *ip != NULL; ip++) { + dot = &message[*ip-1]; + dot->m_flag &= ~(MREAD|MTOUCH); + dot->m_flag |= MSTATUS; + } + return(0); +} + +/* + * Print the size of each message. + */ +int +messize(msgvec) + int *msgvec; +{ + register struct message *mp; + register int *ip, mesg; + + for (ip = msgvec; *ip != NULL; ip++) { + mesg = *ip; + mp = &message[mesg-1]; + printf("%d: %d/%ld\n", mesg, mp->m_lines, mp->m_size); + } + return(0); +} + +/* + * Quit quickly. If we are sourcing, just pop the input level + * by returning an error. + */ +int +rexit(e) + int e; +{ + if (sourcing) + return(1); + exit(e); + /*NOTREACHED*/ +} + +/* + * Set or display a variable value. Syntax is similar to that + * of csh. + */ +int +set(arglist) + char **arglist; +{ + register struct var *vp; + register char *cp, *cp2; + char varbuf[BUFSIZ], **ap, **p; + int errs, h, s; + + if (*arglist == NOSTR) { + for (h = 0, s = 1; h < HSHSIZE; h++) + for (vp = variables[h]; vp != NOVAR; vp = vp->v_link) + s++; + ap = (char **) salloc(s * sizeof *ap); + for (h = 0, p = ap; h < HSHSIZE; h++) + for (vp = variables[h]; vp != NOVAR; vp = vp->v_link) + *p++ = vp->v_name; + *p = NOSTR; + sort(ap); + for (p = ap; *p != NOSTR; p++) + printf("%s\t%s\n", *p, value(*p)); + return(0); + } + errs = 0; + for (ap = arglist; *ap != NOSTR; ap++) { + cp = *ap; + cp2 = varbuf; + while (*cp != '=' && *cp != '\0') + *cp2++ = *cp++; + *cp2 = '\0'; + if (*cp == '\0') + cp = ""; + else + cp++; + if (equal(varbuf, "")) { + printf("Non-null variable name required\n"); + errs++; + continue; + } + assign(varbuf, cp); + } + return(errs); +} + +/* + * Unset a bunch of variable values. + */ +int +unset(arglist) + char **arglist; +{ + register struct var *vp, *vp2; + int errs, h; + char **ap; + + errs = 0; + for (ap = arglist; *ap != NOSTR; ap++) { + if ((vp2 = lookup(*ap)) == NOVAR) { + if (!sourcing) { + printf("\"%s\": undefined variable\n", *ap); + errs++; + } + continue; + } + h = hash(*ap); + if (vp2 == variables[h]) { + variables[h] = variables[h]->v_link; + vfree(vp2->v_name); + vfree(vp2->v_value); + free((char *)vp2); + continue; + } + for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link) + ; + vp->v_link = vp2->v_link; + vfree(vp2->v_name); + vfree(vp2->v_value); + free((char *) vp2); + } + return(errs); +} + +/* + * Put add users to a group. + */ +int +group(argv) + char **argv; +{ + register struct grouphead *gh; + register struct group *gp; + register int h; + int s; + char **ap, *gname, **p; + + if (*argv == NOSTR) { + for (h = 0, s = 1; h < HSHSIZE; h++) + for (gh = groups[h]; gh != NOGRP; gh = gh->g_link) + s++; + ap = (char **) salloc(s * sizeof *ap); + for (h = 0, p = ap; h < HSHSIZE; h++) + for (gh = groups[h]; gh != NOGRP; gh = gh->g_link) + *p++ = gh->g_name; + *p = NOSTR; + sort(ap); + for (p = ap; *p != NOSTR; p++) + printgroup(*p); + return(0); + } + if (argv[1] == NOSTR) { + printgroup(*argv); + return(0); + } + gname = *argv; + h = hash(gname); + if ((gh = findgroup(gname)) == NOGRP) { + gh = (struct grouphead *) calloc(sizeof *gh, 1); + gh->g_name = vcopy(gname); + gh->g_list = NOGE; + gh->g_link = groups[h]; + groups[h] = gh; + } + + /* + * Insert names from the command list into the group. + * Who cares if there are duplicates? They get tossed + * later anyway. + */ + + for (ap = argv+1; *ap != NOSTR; ap++) { + gp = (struct group *) calloc(sizeof *gp, 1); + gp->ge_name = vcopy(*ap); + gp->ge_link = gh->g_list; + gh->g_list = gp; + } + return(0); +} + +/* + * Sort the passed string vecotor into ascending dictionary + * order. + */ +void +sort(list) + char **list; +{ + register char **ap; + int diction(); + + for (ap = list; *ap != NOSTR; ap++) + ; + if (ap-list < 2) + return; + qsort(list, ap-list, sizeof(*list), diction); +} + +/* + * Do a dictionary order comparison of the arguments from + * qsort. + */ +int +diction(a, b) + const void *a, *b; +{ + return(strcmp(*(char **)a, *(char **)b)); +} + +/* + * The do nothing command for comments. + */ + +/*ARGSUSED*/ +int +null(e) + int e; +{ + return 0; +} + +/* + * Change to another file. With no argument, print information about + * the current file. + */ +int +file(argv) + register char **argv; +{ + + if (argv[0] == NOSTR) { + newfileinfo(); + return 0; + } + if (setfile(*argv) < 0) + return 1; + announce(); + return 0; +} + +/* + * Expand file names like echo + */ +int +echo(argv) + char **argv; +{ + register char **ap; + register char *cp; + + for (ap = argv; *ap != NOSTR; ap++) { + cp = *ap; + if ((cp = expand(cp)) != NOSTR) { + if (ap != argv) + putchar(' '); + printf("%s", cp); + } + } + putchar('\n'); + return 0; +} + +int +Respond(msgvec) + int *msgvec; +{ + if (value("Replyall") == NOSTR) + return (_Respond(msgvec)); + else + return (_respond(msgvec)); +} + +/* + * Reply to a series of messages by simply mailing to the senders + * and not messing around with the To: and Cc: lists as in normal + * reply. + */ +int +_Respond(msgvec) + int msgvec[]; +{ + struct header head; + struct message *mp; + register int *ap; + register char *cp; + + head.h_to = NIL; + for (ap = msgvec; *ap != 0; ap++) { + mp = &message[*ap - 1]; + touch(mp); + dot = mp; + if ((cp = skin(hfield("from", mp))) == NOSTR) + cp = skin(nameof(mp, 2)); + head.h_to = cat(head.h_to, extract(cp, GTO)); + } + if (head.h_to == NIL) + return 0; + mp = &message[msgvec[0] - 1]; + if ((head.h_subject = hfield("subject", mp)) == NOSTR) + head.h_subject = hfield("subj", mp); + head.h_subject = reedit(head.h_subject); + head.h_cc = NIL; + head.h_bcc = NIL; + head.h_smopts = NIL; + mail1(&head, 1); + return 0; +} + +/* + * Conditional commands. These allow one to parameterize one's + * .mailrc and do some things if sending, others if receiving. + */ +int +ifcmd(argv) + char **argv; +{ + register char *cp; + + if (cond != CANY) { + printf("Illegal nested \"if\"\n"); + return(1); + } + cond = CANY; + cp = argv[0]; + switch (*cp) { + case 'r': case 'R': + cond = CRCV; + break; + + case 's': case 'S': + cond = CSEND; + break; + + default: + printf("Unrecognized if-keyword: \"%s\"\n", cp); + return(1); + } + return(0); +} + +/* + * Implement 'else'. This is pretty simple -- we just + * flip over the conditional flag. + */ +int +elsecmd() +{ + + switch (cond) { + case CANY: + printf("\"Else\" without matching \"if\"\n"); + return(1); + + case CSEND: + cond = CRCV; + break; + + case CRCV: + cond = CSEND; + break; + + default: + printf("Mail's idea of conditions is screwed up\n"); + cond = CANY; + break; + } + return(0); +} + +/* + * End of if statement. Just set cond back to anything. + */ +int +endifcmd() +{ + + if (cond == CANY) { + printf("\"Endif\" without matching \"if\"\n"); + return(1); + } + cond = CANY; + return(0); +} + +/* + * Set the list of alternate names. + */ +int +alternates(namelist) + char **namelist; +{ + register int c; + register char **ap, **ap2, *cp; + + c = argcount(namelist) + 1; + if (c == 1) { + if (altnames == 0) + return(0); + for (ap = altnames; *ap; ap++) + printf("%s ", *ap); + printf("\n"); + return(0); + } + if (altnames != 0) + free((char *) altnames); + altnames = (char **) calloc((unsigned) c, sizeof (char *)); + for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) { + cp = (char *) calloc((unsigned) strlen(*ap) + 1, sizeof (char)); + strcpy(cp, *ap); + *ap2 = cp; + } + *ap2 = 0; + return(0); +} diff --git a/usr.bin/mail/cmdtab.c b/usr.bin/mail/cmdtab.c new file mode 100644 index 0000000..94e33a0 --- /dev/null +++ b/usr.bin/mail/cmdtab.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "def.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Define all of the command names and bindings. + */ + +struct cmd cmdtab[] = { + "next", next, NDMLIST, 0, MMNDEL, + "alias", group, M|RAWLIST, 0, 1000, + "print", type, MSGLIST, 0, MMNDEL, + "type", type, MSGLIST, 0, MMNDEL, + "Type", Type, MSGLIST, 0, MMNDEL, + "Print", Type, MSGLIST, 0, MMNDEL, + "visual", visual, I|MSGLIST, 0, MMNORM, + "top", top, MSGLIST, 0, MMNDEL, + "touch", stouch, W|MSGLIST, 0, MMNDEL, + "preserve", preserve, W|MSGLIST, 0, MMNDEL, + "delete", delete, W|P|MSGLIST, 0, MMNDEL, + "dp", deltype, W|MSGLIST, 0, MMNDEL, + "dt", deltype, W|MSGLIST, 0, MMNDEL, + "undelete", undelete, P|MSGLIST, MDELETED,MMNDEL, + "unset", unset, M|RAWLIST, 1, 1000, + "mail", sendmail, R|M|I|STRLIST, 0, 0, + "mbox", mboxit, W|MSGLIST, 0, 0, + "more", more, MSGLIST, 0, MMNDEL, + "page", more, MSGLIST, 0, MMNDEL, + "More", More, MSGLIST, 0, MMNDEL, + "Page", More, MSGLIST, 0, MMNDEL, + "unread", unread, MSGLIST, 0, MMNDEL, + "!", shell, I|STRLIST, 0, 0, + "copy", copycmd, M|STRLIST, 0, 0, + "chdir", schdir, M|RAWLIST, 0, 1, + "cd", schdir, M|RAWLIST, 0, 1, + "save", save, STRLIST, 0, 0, + "source", source, M|RAWLIST, 1, 1, + "set", set, M|RAWLIST, 0, 1000, + "shell", dosh, I|NOLIST, 0, 0, + "version", pversion, M|NOLIST, 0, 0, + "group", group, M|RAWLIST, 0, 1000, + "write", swrite, STRLIST, 0, 0, + "from", from, MSGLIST, 0, MMNORM, + "file", file, T|M|RAWLIST, 0, 1, + "folder", file, T|M|RAWLIST, 0, 1, + "folders", folders, T|M|NOLIST, 0, 0, + "?", help, M|NOLIST, 0, 0, + "z", scroll, M|STRLIST, 0, 0, + "headers", headers, MSGLIST, 0, MMNDEL, + "help", help, M|NOLIST, 0, 0, + "=", pdot, NOLIST, 0, 0, + "Reply", Respond, R|I|MSGLIST, 0, MMNDEL, + "Respond", Respond, R|I|MSGLIST, 0, MMNDEL, + "reply", respond, R|I|MSGLIST, 0, MMNDEL, + "respond", respond, R|I|MSGLIST, 0, MMNDEL, + "edit", editor, I|MSGLIST, 0, MMNORM, + "echo", echo, M|RAWLIST, 0, 1000, + "quit", quitcmd, NOLIST, 0, 0, + "list", pcmdlist, M|NOLIST, 0, 0, + "xit", rexit, M|NOLIST, 0, 0, + "exit", rexit, M|NOLIST, 0, 0, + "size", messize, MSGLIST, 0, MMNDEL, + "hold", preserve, W|MSGLIST, 0, MMNDEL, + "if", ifcmd, F|M|RAWLIST, 1, 1, + "else", elsecmd, F|M|RAWLIST, 0, 0, + "endif", endifcmd, F|M|RAWLIST, 0, 0, + "alternates", alternates, M|RAWLIST, 0, 1000, + "ignore", igfield, M|RAWLIST, 0, 1000, + "discard", igfield, M|RAWLIST, 0, 1000, + "retain", retfield, M|RAWLIST, 0, 1000, + "saveignore", saveigfield, M|RAWLIST, 0, 1000, + "savediscard", saveigfield, M|RAWLIST, 0, 1000, + "saveretain", saveretfield, M|RAWLIST, 0, 1000, +/* "Header", Header, STRLIST, 0, 1000, */ + "core", core, M|NOLIST, 0, 0, + "#", null, M|NOLIST, 0, 0, + "clobber", clobber, M|RAWLIST, 0, 1, + 0, 0, 0, 0, 0 +}; diff --git a/usr.bin/mail/collect.c b/usr.bin/mail/collect.c new file mode 100644 index 0000000..9d54fd3 --- /dev/null +++ b/usr.bin/mail/collect.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * Collect input from standard input, handling + * ~ escapes. + */ + +#include "rcv.h" +#include "extern.h" + +/* + * Read a message from standard output and return a read file to it + * or NULL on error. + */ + +/* + * The following hokiness with global variables is so that on + * receipt of an interrupt signal, the partial message can be salted + * away on dead.letter. + */ + +static sig_t saveint; /* Previous SIGINT value */ +static sig_t savehup; /* Previous SIGHUP value */ +static sig_t savetstp; /* Previous SIGTSTP value */ +static sig_t savettou; /* Previous SIGTTOU value */ +static sig_t savettin; /* Previous SIGTTIN value */ +static FILE *collf; /* File for saving away */ +static int hadintr; /* Have seen one SIGINT so far */ + +static jmp_buf colljmp; /* To get back to work */ +static int colljmp_p; /* whether to long jump */ +static jmp_buf collabort; /* To end collection with error */ + +FILE * +collect(hp, printheaders) + struct header *hp; + int printheaders; +{ + FILE *fbuf; + int lc, cc, escape, eofcount; + register int c, t; + char linebuf[LINESIZE], *cp; + extern char tempMail[]; + char getsub; + int omask; + void collint(), collhup(), collstop(); + + collf = NULL; + /* + * Start catching signals from here, but we're still die on interrupts + * until we're in the main loop. + */ + omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); + if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) + signal(SIGINT, collint); + if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) + signal(SIGHUP, collhup); + savetstp = signal(SIGTSTP, collstop); + savettou = signal(SIGTTOU, collstop); + savettin = signal(SIGTTIN, collstop); + if (setjmp(collabort) || setjmp(colljmp)) { + rm(tempMail); + goto err; + } + sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP))); + + noreset++; + if ((collf = Fopen(tempMail, "w+")) == NULL) { + perror(tempMail); + goto err; + } + unlink(tempMail); + + /* + * If we are going to prompt for a subject, + * refrain from printing a newline after + * the headers (since some people mind). + */ + t = GTO|GSUBJECT|GCC|GNL; + getsub = 0; + if (hp->h_subject == NOSTR && value("interactive") != NOSTR && + (value("ask") != NOSTR || value("asksub") != NOSTR)) + t &= ~GNL, getsub++; + if (printheaders) { + puthead(hp, stdout, t); + fflush(stdout); + } + if ((cp = value("escape")) != NOSTR) + escape = *cp; + else + escape = ESCAPE; + eofcount = 0; + hadintr = 0; + + if (!setjmp(colljmp)) { + if (getsub) + grabh(hp, GSUBJECT); + } else { + /* + * Come here for printing the after-signal message. + * Duplicate messages won't be printed because + * the write is aborted if we get a SIGTTOU. + */ +cont: + if (hadintr) { + fflush(stdout); + fprintf(stderr, + "\n(Interrupt -- one more to kill letter)\n"); + } else { + printf("(continue)\n"); + fflush(stdout); + } + } + for (;;) { + colljmp_p = 1; + c = readline(stdin, linebuf, LINESIZE); + colljmp_p = 0; + if (c < 0) { + if (value("interactive") != NOSTR && + value("ignoreeof") != NOSTR && ++eofcount < 25) { + printf("Use \".\" to terminate letter\n"); + continue; + } + break; + } + eofcount = 0; + hadintr = 0; + if (linebuf[0] == '.' && linebuf[1] == '\0' && + value("interactive") != NOSTR && + (value("dot") != NOSTR || value("ignoreeof") != NOSTR)) + break; + if (linebuf[0] != escape || value("interactive") == NOSTR) { + if (putline(collf, linebuf) < 0) + goto err; + continue; + } + c = linebuf[1]; + switch (c) { + default: + /* + * On double escape, just send the single one. + * Otherwise, it's an error. + */ + if (c == escape) { + if (putline(collf, &linebuf[1]) < 0) + goto err; + else + break; + } + printf("Unknown tilde escape.\n"); + break; + case 'C': + /* + * Dump core. + */ + core(); + break; + case '!': + /* + * Shell escape, send the balance of the + * line to sh -c. + */ + shell(&linebuf[2]); + break; + case ':': + /* + * Escape to command mode, but be nice! + */ + execute(&linebuf[2], 1); + goto cont; + case '.': + /* + * Simulate end of file on input. + */ + goto out; + case 'q': + /* + * Force a quit of sending mail. + * Act like an interrupt happened. + */ + hadintr++; + collint(SIGINT); + exit(1); + case 'h': + /* + * Grab a bunch of headers. + */ + grabh(hp, GTO|GSUBJECT|GCC|GBCC); + goto cont; + case 't': + /* + * Add to the To list. + */ + hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); + break; + case 's': + /* + * Set the Subject list. + */ + cp = &linebuf[2]; + while (isspace(*cp)) + cp++; + hp->h_subject = savestr(cp); + break; + case 'c': + /* + * Add to the CC list. + */ + hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); + break; + case 'b': + /* + * Add stuff to blind carbon copies list. + */ + hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); + break; + case 'd': + strcpy(linebuf + 2, getdeadletter()); + /* fall into . . . */ + case 'r': + /* + * Invoke a file: + * Search for the file name, + * then open it and copy the contents to collf. + */ + cp = &linebuf[2]; + while (isspace(*cp)) + cp++; + if (*cp == '\0') { + printf("Interpolate what file?\n"); + break; + } + cp = expand(cp); + if (cp == NOSTR) + break; + if (isdir(cp)) { + printf("%s: Directory\n", cp); + break; + } + if ((fbuf = Fopen(cp, "r")) == NULL) { + perror(cp); + break; + } + printf("\"%s\" ", cp); + fflush(stdout); + lc = 0; + cc = 0; + while (readline(fbuf, linebuf, LINESIZE) >= 0) { + lc++; + if ((t = putline(collf, linebuf)) < 0) { + Fclose(fbuf); + goto err; + } + cc += t; + } + Fclose(fbuf); + printf("%d/%d\n", lc, cc); + break; + case 'w': + /* + * Write the message on a file. + */ + cp = &linebuf[2]; + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\0') { + fprintf(stderr, "Write what file!?\n"); + break; + } + if ((cp = expand(cp)) == NOSTR) + break; + rewind(collf); + exwrite(cp, collf, 1); + break; + case 'm': + case 'M': + case 'f': + case 'F': + /* + * Interpolate the named messages, if we + * are in receiving mail mode. Does the + * standard list processing garbage. + * If ~f is given, we don't shift over. + */ + if (forward(linebuf + 2, collf, c) < 0) + goto err; + goto cont; + case '?': + if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { + perror(_PATH_TILDE); + break; + } + while ((t = getc(fbuf)) != EOF) + (void) putchar(t); + Fclose(fbuf); + break; + case 'p': + /* + * Print out the current state of the + * message without altering anything. + */ + rewind(collf); + printf("-------\nMessage contains:\n"); + puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); + while ((t = getc(collf)) != EOF) + (void) putchar(t); + goto cont; + case '|': + /* + * Pipe message through command. + * Collect output as new message. + */ + rewind(collf); + mespipe(collf, &linebuf[2]); + goto cont; + case 'v': + case 'e': + /* + * Edit the current message. + * 'e' means to use EDITOR + * 'v' means to use VISUAL + */ + rewind(collf); + mesedit(collf, c); + goto cont; + } + } + goto out; +err: + if (collf != NULL) { + Fclose(collf); + collf = NULL; + } +out: + if (collf != NULL) + rewind(collf); + noreset--; + sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); + signal(SIGINT, saveint); + signal(SIGHUP, savehup); + signal(SIGTSTP, savetstp); + signal(SIGTTOU, savettou); + signal(SIGTTIN, savettin); + sigsetmask(omask); + return collf; +} + +/* + * Write a file, ex-like if f set. + */ +int +exwrite(name, fp, f) + char name[]; + FILE *fp; + int f; +{ + register FILE *of; + register int c; + long cc; + int lc; + struct stat junk; + + if (f) { + printf("\"%s\" ", name); + fflush(stdout); + } + if (stat(name, &junk) >= 0 && (junk.st_mode & S_IFMT) == S_IFREG) { + if (!f) + fprintf(stderr, "%s: ", name); + fprintf(stderr, "File exists\n"); + return(-1); + } + if ((of = Fopen(name, "w")) == NULL) { + perror(NOSTR); + return(-1); + } + lc = 0; + cc = 0; + while ((c = getc(fp)) != EOF) { + cc++; + if (c == '\n') + lc++; + (void) putc(c, of); + if (ferror(of)) { + perror(name); + Fclose(of); + return(-1); + } + } + Fclose(of); + printf("%d/%ld\n", lc, cc); + fflush(stdout); + return(0); +} + +/* + * Edit the message being collected on fp. + * On return, make the edit file the new temp file. + */ +void +mesedit(fp, c) + FILE *fp; + int c; +{ + sig_t sigint = signal(SIGINT, SIG_IGN); + FILE *nf = run_editor(fp, (off_t)-1, c, 0); + + if (nf != NULL) { + fseek(nf, 0L, 2); + collf = nf; + Fclose(fp); + } + (void) signal(SIGINT, sigint); +} + +/* + * Pipe the message through the command. + * Old message is on stdin of command; + * New message collected from stdout. + * Sh -c must return 0 to accept the new message. + */ +void +mespipe(fp, cmd) + FILE *fp; + char cmd[]; +{ + FILE *nf; + sig_t sigint = signal(SIGINT, SIG_IGN); + extern char tempEdit[]; + char *shell; + + if ((nf = Fopen(tempEdit, "w+")) == NULL) { + perror(tempEdit); + goto out; + } + (void) unlink(tempEdit); + /* + * stdin = current message. + * stdout = new message. + */ + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + if (run_command(shell, + 0, fileno(fp), fileno(nf), "-c", cmd, NOSTR) < 0) { + (void) Fclose(nf); + goto out; + } + if (fsize(nf) == 0) { + fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); + (void) Fclose(nf); + goto out; + } + /* + * Take new files. + */ + (void) fseek(nf, 0L, 2); + collf = nf; + (void) Fclose(fp); +out: + (void) signal(SIGINT, sigint); +} + +/* + * Interpolate the named messages into the current + * message, preceding each line with a tab. + * Return a count of the number of characters now in + * the message, or -1 if an error is encountered writing + * the message temporary. The flag argument is 'm' if we + * should shift over and 'f' if not. + */ +int +forward(ms, fp, f) + char ms[]; + FILE *fp; + int f; +{ + register int *msgvec; + extern char tempMail[]; + struct ignoretab *ig; + char *tabst; + + msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec); + if (msgvec == (int *) NOSTR) + return(0); + if (getmsglist(ms, msgvec, 0) < 0) + return(0); + if (*msgvec == 0) { + *msgvec = first(0, MMNORM); + if (*msgvec == NULL) { + printf("No appropriate messages\n"); + return(0); + } + msgvec[1] = NULL; + } + if (f == 'f' || f == 'F') + tabst = NOSTR; + else if ((tabst = value("indentprefix")) == NOSTR) + tabst = "\t"; + ig = isupper(f) ? NULL : ignore; + printf("Interpolating:"); + for (; *msgvec != 0; msgvec++) { + struct message *mp = message + *msgvec - 1; + + touch(mp); + printf(" %d", *msgvec); + if (send(mp, fp, ig, tabst) < 0) { + perror(tempMail); + return(-1); + } + } + printf("\n"); + return(0); +} + +/* + * Print (continue) when continued after ^Z. + */ +/*ARGSUSED*/ +void +collstop(s) + int s; +{ + sig_t old_action = signal(s, SIG_DFL); + + sigsetmask(sigblock(0) & ~sigmask(s)); + kill(0, s); + sigblock(sigmask(s)); + signal(s, old_action); + if (colljmp_p) { + colljmp_p = 0; + hadintr = 0; + longjmp(colljmp, 1); + } +} + +/* + * On interrupt, come here to save the partial message in ~/dead.letter. + * Then jump out of the collection loop. + */ +/*ARGSUSED*/ +void +collint(s) + int s; +{ + /* + * the control flow is subtle, because we can be called from ~q. + */ + if (!hadintr) { + if (value("ignore") != NOSTR) { + puts("@"); + fflush(stdout); + clearerr(stdin); + return; + } + hadintr = 1; + longjmp(colljmp, 1); + } + rewind(collf); + if (value("nosave") == NOSTR) + savedeadletter(collf); + longjmp(collabort, 1); +} + +/*ARGSUSED*/ +void +collhup(s) + int s; +{ + rewind(collf); + savedeadletter(collf); + /* + * Let's pretend nobody else wants to clean up, + * a true statement at this time. + */ + exit(1); +} + +void +savedeadletter(fp) + register FILE *fp; +{ + register FILE *dbuf; + register int c; + char *cp; + + if (fsize(fp) == 0) + return; + cp = getdeadletter(); + c = umask(077); + dbuf = Fopen(cp, "a"); + (void) umask(c); + if (dbuf == NULL) + return; + while ((c = getc(fp)) != EOF) + (void) putc(c, dbuf); + Fclose(dbuf); + rewind(fp); +} diff --git a/usr.bin/mail/def.h b/usr.bin/mail/def.h new file mode 100644 index 0000000..f843914 --- /dev/null +++ b/usr.bin/mail/def.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)def.h 8.2 (Berkeley) 3/21/94 + */ + +/* + * Mail -- a mail program + * + * Author: Kurt Shoens (UCB) March 25, 1978 + */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> + +#include <signal.h> +#include <sgtty.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include "pathnames.h" + +#define APPEND /* New mail goes to end of mailbox */ + +#define ESCAPE '~' /* Default escape for sending */ +#define NMLSIZE 1024 /* max names in a message list */ +#define PATHSIZE MAXPATHLEN /* Size of pathnames throughout */ +#define HSHSIZE 59 /* Hash size for aliases and vars */ +#define LINESIZE BUFSIZ /* max readable line width */ +#define STRINGSIZE ((unsigned) 128)/* Dynamic allocation units */ +#define MAXARGC 1024 /* Maximum list of raw strings */ +#define NOSTR ((char *) 0) /* Null string pointer */ +#define MAXEXP 25 /* Maximum expansion of aliases */ + +#define equal(a, b) (strcmp(a,b)==0)/* A nice function to string compare */ + +struct message { + short m_flag; /* flags, see below */ + short m_block; /* block number of this message */ + short m_offset; /* offset in block of message */ + long m_size; /* Bytes in the message */ + short m_lines; /* Lines in the message */ +}; + +/* + * flag bits. + */ + +#define MUSED (1<<0) /* entry is used, but this bit isn't */ +#define MDELETED (1<<1) /* entry has been deleted */ +#define MSAVED (1<<2) /* entry has been saved */ +#define MTOUCH (1<<3) /* entry has been noticed */ +#define MPRESERVE (1<<4) /* keep entry in sys mailbox */ +#define MMARK (1<<5) /* message is marked! */ +#define MODIFY (1<<6) /* message has been modified */ +#define MNEW (1<<7) /* message has never been seen */ +#define MREAD (1<<8) /* message has been read sometime. */ +#define MSTATUS (1<<9) /* message status has changed */ +#define MBOX (1<<10) /* Send this to mbox, regardless */ + +/* + * Given a file address, determine the block number it represents. + */ +#define blockof(off) ((int) ((off) / 4096)) +#define offsetof(off) ((int) ((off) % 4096)) +#define positionof(block, offset) ((off_t)(block) * 4096 + (offset)) + +/* + * Format of the command description table. + * The actual table is declared and initialized + * in lex.c + */ +struct cmd { + char *c_name; /* Name of command */ + int (*c_func)(); /* Implementor of the command */ + short c_argtype; /* Type of arglist (see below) */ + short c_msgflag; /* Required flags of messages */ + short c_msgmask; /* Relevant flags of messages */ +}; + +/* Yechh, can't initialize unions */ + +#define c_minargs c_msgflag /* Minimum argcount for RAWLIST */ +#define c_maxargs c_msgmask /* Max argcount for RAWLIST */ + +/* + * Argument types. + */ + +#define MSGLIST 0 /* Message list type */ +#define STRLIST 1 /* A pure string */ +#define RAWLIST 2 /* Shell string list */ +#define NOLIST 3 /* Just plain 0 */ +#define NDMLIST 4 /* Message list, no defaults */ + +#define P 040 /* Autoprint dot after command */ +#define I 0100 /* Interactive command bit */ +#define M 0200 /* Legal from send mode bit */ +#define W 0400 /* Illegal when read only bit */ +#define F 01000 /* Is a conditional command */ +#define T 02000 /* Is a transparent command */ +#define R 04000 /* Cannot be called from collect */ + +/* + * Oft-used mask values + */ + +#define MMNORM (MDELETED|MSAVED)/* Look at both save and delete bits */ +#define MMNDEL MDELETED /* Look only at deleted bit */ + +/* + * Structure used to return a break down of a head + * line (hats off to Bill Joy!) + */ + +struct headline { + char *l_from; /* The name of the sender */ + char *l_tty; /* His tty string (if any) */ + char *l_date; /* The entire date string */ +}; + +#define GTO 1 /* Grab To: line */ +#define GSUBJECT 2 /* Likewise, Subject: line */ +#define GCC 4 /* And the Cc: line */ +#define GBCC 8 /* And also the Bcc: line */ +#define GMASK (GTO|GSUBJECT|GCC|GBCC) + /* Mask of places from whence */ + +#define GNL 16 /* Print blank line after */ +#define GDEL 32 /* Entity removed from list */ +#define GCOMMA 64 /* detract puts in commas */ + +/* + * Structure used to pass about the current + * state of the user-typed message header. + */ + +struct header { + struct name *h_to; /* Dynamic "To:" string */ + char *h_subject; /* Subject string */ + struct name *h_cc; /* Carbon copies string */ + struct name *h_bcc; /* Blind carbon copies */ + struct name *h_smopts; /* Sendmail options */ +}; + +/* + * Structure of namelist nodes used in processing + * the recipients of mail and aliases and all that + * kind of stuff. + */ + +struct name { + struct name *n_flink; /* Forward link in list. */ + struct name *n_blink; /* Backward list link */ + short n_type; /* From which list it came */ + char *n_name; /* This fella's name */ +}; + +/* + * Structure of a variable node. All variables are + * kept on a singly-linked list of these, rooted by + * "variables" + */ + +struct var { + struct var *v_link; /* Forward link to next variable */ + char *v_name; /* The variable's name */ + char *v_value; /* And it's current value */ +}; + +struct group { + struct group *ge_link; /* Next person in this group */ + char *ge_name; /* This person's user name */ +}; + +struct grouphead { + struct grouphead *g_link; /* Next grouphead in list */ + char *g_name; /* Name of this group */ + struct group *g_list; /* Users in group. */ +}; + +#define NIL ((struct name *) 0) /* The nil pointer for namelists */ +#define NONE ((struct cmd *) 0) /* The nil pointer to command tab */ +#define NOVAR ((struct var *) 0) /* The nil pointer to variables */ +#define NOGRP ((struct grouphead *) 0)/* The nil grouphead pointer */ +#define NOGE ((struct group *) 0) /* The nil group pointer */ + +/* + * Structure of the hash table of ignored header fields + */ +struct ignoretab { + int i_count; /* Number of entries */ + struct ignore { + struct ignore *i_link; /* Next ignored field in bucket */ + char *i_field; /* This ignored field */ + } *i_head[HSHSIZE]; +}; + +/* + * Token values returned by the scanner used for argument lists. + * Also, sizes of scanner-related things. + */ + +#define TEOL 0 /* End of the command line */ +#define TNUMBER 1 /* A message number */ +#define TDASH 2 /* A simple dash */ +#define TSTRING 3 /* A string (possibly containing -) */ +#define TDOT 4 /* A "." */ +#define TUP 5 /* An "^" */ +#define TDOLLAR 6 /* A "$" */ +#define TSTAR 7 /* A "*" */ +#define TOPEN 8 /* An '(' */ +#define TCLOSE 9 /* A ')' */ +#define TPLUS 10 /* A '+' */ +#define TERROR 11 /* A lexical error */ + +#define REGDEP 2 /* Maximum regret depth. */ +#define STRINGLEN 1024 /* Maximum length of string token */ + +/* + * Constants for conditional commands. These describe whether + * we should be executing stuff or not. + */ + +#define CANY 0 /* Execute in send or receive mode */ +#define CRCV 1 /* Execute in receive mode only */ +#define CSEND 2 /* Execute in send mode only */ + +/* + * Kludges to handle the change from setexit / reset to setjmp / longjmp + */ + +#define setexit() setjmp(srbuf) +#define reset(x) longjmp(srbuf, x) + +/* + * Truncate a file to the last character written. This is + * useful just before closing an old file that was opened + * for read/write. + */ +#define trunc(stream) { \ + (void)fflush(stream); \ + (void)ftruncate(fileno(stream), (long)ftell(stream)); \ +} diff --git a/usr.bin/mail/edit.c b/usr.bin/mail/edit.c new file mode 100644 index 0000000..97d3bd4 --- /dev/null +++ b/usr.bin/mail/edit.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include <fcntl.h> +#include "extern.h" + +/* + * Mail -- a mail program + * + * Perform message editing functions. + */ + +/* + * Edit a message list. + */ +int +editor(msgvec) + int *msgvec; +{ + + return edit1(msgvec, 'e'); +} + +/* + * Invoke the visual editor on a message list. + */ +int +visual(msgvec) + int *msgvec; +{ + + return edit1(msgvec, 'v'); +} + +/* + * Edit a message by writing the message into a funnily-named file + * (which should not exist) and forking an editor on it. + * We get the editor from the stuff above. + */ +int +edit1(msgvec, type) + int *msgvec; + int type; +{ + register int c; + int i; + FILE *fp; + register struct message *mp; + off_t size; + + /* + * Deal with each message to be edited . . . + */ + for (i = 0; msgvec[i] && i < msgCount; i++) { + sig_t sigint; + + if (i > 0) { + char buf[100]; + char *p; + + printf("Edit message %d [ynq]? ", msgvec[i]); + if (fgets(buf, sizeof buf, stdin) == 0) + break; + for (p = buf; *p == ' ' || *p == '\t'; p++) + ; + if (*p == 'q') + break; + if (*p == 'n') + continue; + } + dot = mp = &message[msgvec[i] - 1]; + touch(mp); + sigint = signal(SIGINT, SIG_IGN); + fp = run_editor(setinput(mp), mp->m_size, type, readonly); + if (fp != NULL) { + (void) fseek(otf, 0L, 2); + size = ftell(otf); + mp->m_block = blockof(size); + mp->m_offset = offsetof(size); + mp->m_size = fsize(fp); + mp->m_lines = 0; + mp->m_flag |= MODIFY; + rewind(fp); + while ((c = getc(fp)) != EOF) { + if (c == '\n') + mp->m_lines++; + if (putc(c, otf) == EOF) + break; + } + if (ferror(otf)) + perror("/tmp"); + (void) Fclose(fp); + } + (void) signal(SIGINT, sigint); + } + return 0; +} + +/* + * Run an editor on the file at "fpp" of "size" bytes, + * and return a new file pointer. + * Signals must be handled by the caller. + * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI. + */ +FILE * +run_editor(fp, size, type, readonly) + register FILE *fp; + off_t size; + int type, readonly; +{ + register FILE *nf = NULL; + register int t; + time_t modtime; + char *edit; + struct stat statb; + extern char tempEdit[]; + + if ((t = creat(tempEdit, readonly ? 0400 : 0600)) < 0) { + perror(tempEdit); + goto out; + } + if ((nf = Fdopen(t, "w")) == NULL) { + perror(tempEdit); + (void) unlink(tempEdit); + goto out; + } + if (size >= 0) + while (--size >= 0 && (t = getc(fp)) != EOF) + (void) putc(t, nf); + else + while ((t = getc(fp)) != EOF) + (void) putc(t, nf); + (void) fflush(nf); + if (fstat(fileno(nf), &statb) < 0) + modtime = 0; + else + modtime = statb.st_mtime; + if (ferror(nf)) { + (void) Fclose(nf); + perror(tempEdit); + (void) unlink(tempEdit); + nf = NULL; + goto out; + } + if (Fclose(nf) < 0) { + perror(tempEdit); + (void) unlink(tempEdit); + nf = NULL; + goto out; + } + nf = NULL; + if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NOSTR) + edit = type == 'e' ? _PATH_EX : _PATH_VI; + if (run_command(edit, 0, -1, -1, tempEdit, NOSTR, NOSTR) < 0) { + (void) unlink(tempEdit); + goto out; + } + /* + * If in read only mode or file unchanged, just remove the editor + * temporary and return. + */ + if (readonly) { + (void) unlink(tempEdit); + goto out; + } + if (stat(tempEdit, &statb) < 0) { + perror(tempEdit); + goto out; + } + if (modtime == statb.st_mtime) { + (void) unlink(tempEdit); + goto out; + } + /* + * Now switch to new file. + */ + if ((nf = Fopen(tempEdit, "a+")) == NULL) { + perror(tempEdit); + (void) unlink(tempEdit); + goto out; + } + (void) unlink(tempEdit); +out: + return nf; +} diff --git a/usr.bin/mail/extern.h b/usr.bin/mail/extern.h new file mode 100644 index 0000000..8b1babf --- /dev/null +++ b/usr.bin/mail/extern.h @@ -0,0 +1,253 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.1 (Berkeley) 6/6/93 + */ + +struct name *cat __P((struct name *, struct name *)); +struct name *delname __P((struct name *, char [])); +struct name *elide __P((struct name *)); +struct name *extract __P((char [], int)); +struct name *gexpand __P((struct name *, struct grouphead *, int, int)); +struct name *nalloc __P((char [], int)); +struct name *outof __P((struct name *, FILE *, struct header *)); +struct name *put __P((struct name *, struct name *)); +struct name *tailof __P((struct name *)); +struct name *usermap __P((struct name *)); +FILE *Fdopen __P((int, char *)); +FILE *Fopen __P((char *, char *)); +FILE *Popen __P((char *, char *)); +FILE *collect __P((struct header *, int)); +char *copy __P((char *, char *)); +char *copyin __P((char *, char **)); +char *detract __P((struct name *, int)); +char *expand __P((char *)); +char *getdeadletter __P((void)); +char *getname __P((int)); +char *hfield __P((char [], struct message *)); +FILE *infix __P((struct header *, FILE *)); +char *ishfield __P((char [], char[], char *)); +char *name1 __P((struct message *, int)); +char *nameof __P((struct message *, int)); +char *nextword __P((char *, char *)); +char *readtty __P((char [], char [])); +char *reedit __P((char *)); +FILE *run_editor __P((FILE *, off_t, int, int)); +char *salloc __P((int)); +char *savestr __P((char *)); +FILE *setinput __P((struct message *)); +char *skin __P((char *)); +char *skip_comment __P((char *)); +char *snarf __P((char [], int *)); +char *username __P((void)); +char *value __P((char [])); +char *vcopy __P((char [])); +char *yankword __P((char *, char [])); +int Fclose __P((FILE *)); +int More __P((int *)); +int Pclose __P((FILE *)); +int Respond __P((int *)); +int Type __P((int *)); +int _Respond __P((int [])); +int _respond __P((int *)); +void alter __P((char *)); +int alternates __P((char **)); +void announce __P((void)); +int anyof __P((char *, char *)); +int append __P((struct message *, FILE *)); +int argcount __P((char **)); +void assign __P((char [], char [])); +int bangexp __P((char *)); +int blankline __P((char [])); +void brokpipe __P((int)); +int charcount __P((char *, int)); +int check __P((int, int)); +void clob1 __P((int)); +int clobber __P((char **)); +void close_all_files __P((void)); +int cmatch __P((char *, char *)); +void collhup __P((int)); +void collint __P((int)); +void collstop __P((int)); +void commands __P((void)); +int copycmd __P((char [])); +int core __P((void)); +int count __P((struct name *)); +int delete __P((int [])); +int delm __P((int [])); +int deltype __P((int [])); +void demail __P((void)); +int diction __P((const void *, const void *)); +int dosh __P((char *)); +int echo __P((char **)); +int edit1 __P((int *, int)); +int editor __P((int *)); +void edstop __P((void)); +int elsecmd __P((void)); +int endifcmd __P((void)); +int evalcol __P((int)); +int execute __P((char [], int)); +int exwrite __P((char [], FILE *, int)); +void fail __P((char [], char [])); +int file __P((char **)); +struct grouphead * + findgroup __P((char [])); +void findmail __P((char *, char *)); +int first __P((int, int)); +void fixhead __P((struct header *, struct name *)); +void fmt __P((char *, struct name *, FILE *, int)); +int folders __P((void)); +int forward __P((char [], FILE *, int)); +void free_child __P((int)); +int from __P((int *)); +off_t fsize __P((FILE *)); +int getfold __P((char *)); +int gethfield __P((FILE *, char [], int, char **)); +int getmsglist __P((char *, int *, int)); +int getrawlist __P((char [], char **, int)); +int getuserid __P((char [])); +int grabh __P((struct header *, int)); +int group __P((char **)); +void hangup __P((int)); +int hash __P((char *)); +void hdrstop __P((int)); +int headers __P((int *)); +int help __P((void)); +void holdsigs __P((void)); +int ifcmd __P((char **)); +int igcomp __P((const void *, const void *)); +int igfield __P((char *[])); +int ignore1 __P((char *[], struct ignoretab *, char *)); +int igshow __P((struct ignoretab *, char *)); +void intr __P((int)); +int isdate __P((char [])); +int isdir __P((char [])); +int isfileaddr __P((char *)); +int ishead __P((char [])); +int isign __P((char *, struct ignoretab [])); +int isprefix __P((char *, char *)); +void istrcpy __P((char *, char *)); +struct cmd * + lex __P((char [])); +void load __P((char *)); +struct var * + lookup __P((char [])); +int mail __P((struct name *, + struct name *, struct name *, struct name *, char *)); +void mail1 __P((struct header *, int)); +void makemessage __P((FILE *)); +void mark __P((int)); +int markall __P((char [], int)); +int matchsender __P((char *, int)); +int matchsubj __P((char *, int)); +int mboxit __P((int [])); +int member __P((char *, struct ignoretab *)); +void mesedit __P((FILE *, int)); +void mespipe __P((FILE *, char [])); +int messize __P((int *)); +int metamess __P((int, int)); +int more __P((int *)); +int newfileinfo __P((void)); +int next __P((int *)); +int null __P((int)); +void panic __P((const char *, ...)); +void parse __P((char [], struct headline *, char [])); +int pcmdlist __P((void)); +int pdot __P((void)); +void prepare_child __P((int, int, int)); +int preserve __P((int *)); +void prettyprint __P((struct name *)); +void printgroup __P((char [])); +void printhead __P((int)); +int puthead __P((struct header *, FILE *, int)); +int putline __P((FILE *, char *)); +int pversion __P((int)); +void quit __P((void)); +int quitcmd __P((void)); +int raise __P((int)); +int readline __P((FILE *, char *, int)); +void register_file __P((FILE *, int, int)); +void regret __P((int)); +void relsesigs __P((void)); +int respond __P((int *)); +int retfield __P((char *[])); +int rexit __P((int)); +int rm __P((char *)); +int run_command __P((char *, int, int, int, char *, char *, char *)); +int save __P((char [])); +int save1 __P((char [], int, char *, struct ignoretab *)); +void savedeadletter __P((FILE *)); +int saveigfield __P((char *[])); +int savemail __P((char [], FILE *)); +int saveretfield __P((char *[])); +int scan __P((char **)); +void scaninit __P((void)); +int schdir __P((char **)); +int screensize __P((void)); +int scroll __P((char [])); +int send __P((struct message *, FILE *, struct ignoretab *, char *)); +int sendmail __P((char *)); +int set __P((char **)); +int setfile __P((char *)); +void setmsize __P((int)); +void setptr __P((FILE *)); +void setscreensize __P((void)); +int shell __P((char *)); +void sigchild __P((int)); +void sort __P((char **)); +int source __P((char **)); +void spreserve __P((void)); +void sreset __P((void)); +int start_command __P((char *, int, int, int, char *, char *, char *)); +void statusput __P((struct message *, FILE *, char *)); +void stop __P((int)); +int stouch __P((int [])); +int swrite __P((char [])); +void tinit __P((void)); +int top __P((int *)); +void touch __P((struct message *)); +void ttyint __P((int)); +void ttystop __P((int)); +int type __P((int *)); +int type1 __P((int *, int, int)); +int undelete __P((int *)); +void unmark __P((int)); +char **unpack __P((struct name *)); +int unread __P((int [])); +void unregister_file __P((FILE *)); +int unset __P((char **)); +int unstack __P((void)); +void vfree __P((char *)); +int visual __P((int *)); +int wait_child __P((int)); +int wait_command __P((int)); +int writeback __P((FILE *)); diff --git a/usr.bin/mail/fio.c b/usr.bin/mail/fio.c new file mode 100644 index 0000000..4f2a8a8 --- /dev/null +++ b/usr.bin/mail/fio.c @@ -0,0 +1,431 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)fio.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include <sys/file.h> +#include <sys/wait.h> + +#include <unistd.h> +#include <paths.h> +#include <errno.h> +#include "extern.h" + +/* + * Mail -- a mail program + * + * File I/O. + */ + +/* + * Set up the input pointers while copying the mail file into /tmp. + */ +void +setptr(ibuf) + register FILE *ibuf; +{ + extern char *tmpdir; + register int c, count; + register char *cp, *cp2; + struct message this; + FILE *mestmp; + off_t offset; + int maybe, inhead; + char linebuf[LINESIZE]; + + /* Get temporary file. */ + (void)sprintf(linebuf, "%s/mail.XXXXXX", tmpdir); + if ((c = mkstemp(linebuf)) == -1 || + (mestmp = Fdopen(c, "r+")) == NULL) { + (void)fprintf(stderr, "mail: can't open %s\n", linebuf); + exit(1); + } + (void)unlink(linebuf); + + msgCount = 0; + maybe = 1; + inhead = 0; + offset = 0; + this.m_flag = MUSED|MNEW; + this.m_size = 0; + this.m_lines = 0; + this.m_block = 0; + this.m_offset = 0; + for (;;) { + if (fgets(linebuf, LINESIZE, ibuf) == NULL) { + if (append(&this, mestmp)) { + perror("temporary file"); + exit(1); + } + makemessage(mestmp); + return; + } + count = strlen(linebuf); + (void) fwrite(linebuf, sizeof *linebuf, count, otf); + if (ferror(otf)) { + perror("/tmp"); + exit(1); + } + linebuf[count - 1] = 0; + if (maybe && linebuf[0] == 'F' && ishead(linebuf)) { + msgCount++; + if (append(&this, mestmp)) { + perror("temporary file"); + exit(1); + } + this.m_flag = MUSED|MNEW; + this.m_size = 0; + this.m_lines = 0; + this.m_block = blockof(offset); + this.m_offset = offsetof(offset); + inhead = 1; + } else if (linebuf[0] == 0) { + inhead = 0; + } else if (inhead) { + for (cp = linebuf, cp2 = "status";; cp++) { + if ((c = *cp2++) == 0) { + while (isspace(*cp++)) + ; + if (cp[-1] != ':') + break; + while (c = *cp++) + if (c == 'R') + this.m_flag |= MREAD; + else if (c == 'O') + this.m_flag &= ~MNEW; + inhead = 0; + break; + } + if (*cp != c && *cp != toupper(c)) + break; + } + } + offset += count; + this.m_size += count; + this.m_lines++; + maybe = linebuf[0] == 0; + } +} + +/* + * Drop the passed line onto the passed output buffer. + * If a write error occurs, return -1, else the count of + * characters written, including the newline. + */ +int +putline(obuf, linebuf) + FILE *obuf; + char *linebuf; +{ + register int c; + + c = strlen(linebuf); + (void) fwrite(linebuf, sizeof *linebuf, c, obuf); + (void) putc('\n', obuf); + if (ferror(obuf)) + return (-1); + return (c + 1); +} + +/* + * Read up a line from the specified input into the line + * buffer. Return the number of characters read. Do not + * include the newline at the end. + */ +int +readline(ibuf, linebuf, linesize) + FILE *ibuf; + char *linebuf; + int linesize; +{ + register int n; + + clearerr(ibuf); + if (fgets(linebuf, linesize, ibuf) == NULL) + return -1; + n = strlen(linebuf); + if (n > 0 && linebuf[n - 1] == '\n') + linebuf[--n] = '\0'; + return n; +} + +/* + * Return a file buffer all ready to read up the + * passed message pointer. + */ +FILE * +setinput(mp) + register struct message *mp; +{ + + fflush(otf); + if (fseek(itf, (long)positionof(mp->m_block, mp->m_offset), 0) < 0) { + perror("fseek"); + panic("temporary file seek"); + } + return (itf); +} + +/* + * Take the data out of the passed ghost file and toss it into + * a dynamically allocated message structure. + */ +void +makemessage(f) + FILE *f; +{ + register size = (msgCount + 1) * sizeof (struct message); + + if (message != 0) + free((char *) message); + if ((message = (struct message *) malloc((unsigned) size)) == 0) + panic("Insufficient memory for %d messages", msgCount); + dot = message; + size -= sizeof (struct message); + fflush(f); + (void) lseek(fileno(f), (off_t)sizeof *message, 0); + if (read(fileno(f), (char *) message, size) != size) + panic("Message temporary file corrupted"); + message[msgCount].m_size = 0; + message[msgCount].m_lines = 0; + Fclose(f); +} + +/* + * Append the passed message descriptor onto the temp file. + * If the write fails, return 1, else 0 + */ +int +append(mp, f) + struct message *mp; + FILE *f; +{ + return fwrite((char *) mp, sizeof *mp, 1, f) != 1; +} + +/* + * Delete a file, but only if the file is a plain file. + */ +int +rm(name) + char *name; +{ + struct stat sb; + + if (stat(name, &sb) < 0) + return(-1); + if (!S_ISREG(sb.st_mode)) { + errno = EISDIR; + return(-1); + } + return(unlink(name)); +} + +static int sigdepth; /* depth of holdsigs() */ +static int omask; +/* + * Hold signals SIGHUP, SIGINT, and SIGQUIT. + */ +void +holdsigs() +{ + + if (sigdepth++ == 0) + omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)); +} + +/* + * Release signals SIGHUP, SIGINT, and SIGQUIT. + */ +void +relsesigs() +{ + + if (--sigdepth == 0) + sigsetmask(omask); +} + +/* + * Determine the size of the file possessed by + * the passed buffer. + */ +off_t +fsize(iob) + FILE *iob; +{ + struct stat sbuf; + + if (fstat(fileno(iob), &sbuf) < 0) + return 0; + return sbuf.st_size; +} + +/* + * Evaluate the string given as a new mailbox name. + * Supported meta characters: + * % for my system mail box + * %user for user's system mail box + * # for previous file + * & invoker's mbox file + * +file file in folder directory + * any shell meta character + * Return the file name as a dynamic string. + */ +char * +expand(name) + register char *name; +{ + char xname[PATHSIZE]; + char cmdbuf[PATHSIZE]; /* also used for file names */ + register int pid, l; + register char *cp, *shell; + int pivec[2]; + struct stat sbuf; + extern union wait wait_status; + + /* + * The order of evaluation is "%" and "#" expand into constants. + * "&" can expand into "+". "+" can expand into shell meta characters. + * Shell meta characters expand into constants. + * This way, we make no recursive expansion. + */ + switch (*name) { + case '%': + findmail(name[1] ? name + 1 : myname, xname); + return savestr(xname); + case '#': + if (name[1] != 0) + break; + if (prevfile[0] == 0) { + printf("No previous file\n"); + return NOSTR; + } + return savestr(prevfile); + case '&': + if (name[1] == 0 && (name = value("MBOX")) == NOSTR) + name = "~/mbox"; + /* fall through */ + } + if (name[0] == '+' && getfold(cmdbuf) >= 0) { + sprintf(xname, "%s/%s", cmdbuf, name + 1); + name = savestr(xname); + } + /* catch the most common shell meta character */ + if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) { + sprintf(xname, "%s%s", homedir, name + 1); + name = savestr(xname); + } + if (!anyof(name, "~{[*?$`'\"\\")) + return name; + if (pipe(pivec) < 0) { + perror("pipe"); + return name; + } + sprintf(cmdbuf, "echo %s", name); + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NOSTR); + if (pid < 0) { + close(pivec[0]); + close(pivec[1]); + return NOSTR; + } + close(pivec[1]); + l = read(pivec[0], xname, BUFSIZ); + close(pivec[0]); + if (wait_child(pid) < 0 && wait_status.w_termsig != SIGPIPE) { + fprintf(stderr, "\"%s\": Expansion failed.\n", name); + return NOSTR; + } + if (l < 0) { + perror("read"); + return NOSTR; + } + if (l == 0) { + fprintf(stderr, "\"%s\": No match.\n", name); + return NOSTR; + } + if (l == BUFSIZ) { + fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name); + return NOSTR; + } + xname[l] = 0; + for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--) + ; + cp[1] = '\0'; + if (index(xname, ' ') && stat(xname, &sbuf) < 0) { + fprintf(stderr, "\"%s\": Ambiguous.\n", name); + return NOSTR; + } + return savestr(xname); +} + +/* + * Determine the current folder directory name. + */ +int +getfold(name) + char *name; +{ + char *folder; + + if ((folder = value("folder")) == NOSTR) + return (-1); + if (*folder == '/') + strcpy(name, folder); + else + sprintf(name, "%s/%s", homedir, folder); + return (0); +} + +/* + * Return the name of the dead.letter file. + */ +char * +getdeadletter() +{ + register char *cp; + + if ((cp = value("DEAD")) == NOSTR || (cp = expand(cp)) == NOSTR) + cp = expand("~/dead.letter"); + else if (*cp != '/') { + char buf[PATHSIZE]; + + (void) sprintf(buf, "~/%s", cp); + cp = expand(buf); + } + return cp; +} diff --git a/usr.bin/mail/getname.c b/usr.bin/mail/getname.c new file mode 100644 index 0000000..02a4131 --- /dev/null +++ b/usr.bin/mail/getname.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)getname.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include <pwd.h> +#include "extern.h" + +/* Getname / getuserid for those with hashed passwd data base). */ + +/* + * Search the passwd file for a uid. Return name through ref parameter + * if found, indicating success with 0 return. Return -1 on error. + */ +char * +getname(uid) + int uid; +{ + struct passwd *pw; + + if ((pw = getpwuid(uid)) == NULL) + return NOSTR; + return pw->pw_name; +} + +/* + * Convert the passed name to a user id and return it. Return -1 + * on error. + */ +int +getuserid(name) + char name[]; +{ + struct passwd *pw; + + if ((pw = getpwnam(name)) == NULL) + return -1; + return pw->pw_uid; +} diff --git a/usr.bin/mail/glob.h b/usr.bin/mail/glob.h new file mode 100644 index 0000000..a159aca --- /dev/null +++ b/usr.bin/mail/glob.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)glob.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * A bunch of global variable declarations lie herein. + * def.h must be included first. + */ + +int msgCount; /* Count of messages read in */ +int rcvmode; /* True if receiving mail */ +int sawcom; /* Set after first command */ +char *Tflag; /* -T temp file for netnews */ +int senderr; /* An error while checking */ +int edit; /* Indicates editing a file */ +int readonly; /* Will be unable to rewrite file */ +int noreset; /* String resets suspended */ +int sourcing; /* Currently reading variant file */ +int loading; /* Loading user definitions */ +int cond; /* Current state of conditional exc. */ +FILE *itf; /* Input temp file buffer */ +FILE *otf; /* Output temp file buffer */ +int image; /* File descriptor for image of msg */ +FILE *input; /* Current command input file */ +char mailname[PATHSIZE]; /* Name of current file */ +char prevfile[PATHSIZE]; /* Name of previous file */ +char *homedir; /* Path name of home directory */ +char *myname; /* My login name */ +off_t mailsize; /* Size of system mailbox */ +int lexnumber; /* Number of TNUMBER from scan() */ +char lexstring[STRINGLEN]; /* String from TSTRING, scan() */ +int regretp; /* Pointer to TOS of regret tokens */ +int regretstack[REGDEP]; /* Stack of regretted tokens */ +char *string_stack[REGDEP]; /* Stack of regretted strings */ +int numberstack[REGDEP]; /* Stack of regretted numbers */ +struct message *dot; /* Pointer to current message */ +struct message *message; /* The actual message structure */ +struct var *variables[HSHSIZE]; /* Pointer to active var list */ +struct grouphead *groups[HSHSIZE];/* Pointer to active groups */ +struct ignoretab ignore[2]; /* ignored and retained fields + 0 is ignore, 1 is retain */ +struct ignoretab saveignore[2]; /* ignored and retained fields + on save to folder */ +struct ignoretab ignoreall[2]; /* special, ignore all headers */ +char **altnames; /* List of alternate names for user */ +int debug; /* Debug flag set */ +int screenwidth; /* Screen width, or best guess */ +int screenheight; /* Screen height, or best guess, + for "header" command */ +int realscreenheight; /* the real screen height */ + +#include <setjmp.h> + +jmp_buf srbuf; + + +/* + * The pointers for the string allocation routines, + * there are NSPACE independent areas. + * The first holds STRINGSIZE bytes, the next + * twice as much, and so on. + */ + +#define NSPACE 25 /* Total number of string spaces */ +struct strings { + char *s_topFree; /* Beginning of this area */ + char *s_nextFree; /* Next alloctable place here */ + unsigned s_nleft; /* Number of bytes left here */ +} stringdope[NSPACE]; diff --git a/usr.bin/mail/head.c b/usr.bin/mail/head.c new file mode 100644 index 0000000..ca31ae1 --- /dev/null +++ b/usr.bin/mail/head.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)head.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Routines for processing and detecting headlines. + */ + +/* + * See if the passed line buffer is a mail header. + * Return true if yes. Note the extreme pains to + * accomodate all funny formats. + */ +int +ishead(linebuf) + char linebuf[]; +{ + register char *cp; + struct headline hl; + char parbuf[BUFSIZ]; + + cp = linebuf; + if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' || + *cp++ != ' ') + return (0); + parse(linebuf, &hl, parbuf); + if (hl.l_from == NOSTR || hl.l_date == NOSTR) { + fail(linebuf, "No from or date field"); + return (0); + } + if (!isdate(hl.l_date)) { + fail(linebuf, "Date field not legal date"); + return (0); + } + /* + * I guess we got it! + */ + return (1); +} + +/*ARGSUSED*/ +void +fail(linebuf, reason) + char linebuf[], reason[]; +{ + + /* + if (value("debug") == NOSTR) + return; + fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason); + */ +} + +/* + * Split a headline into its useful components. + * Copy the line into dynamic string space, then set + * pointers into the copied line in the passed headline + * structure. Actually, it scans. + */ +void +parse(line, hl, pbuf) + char line[], pbuf[]; + register struct headline *hl; +{ + register char *cp; + char *sp; + char word[LINESIZE]; + + hl->l_from = NOSTR; + hl->l_tty = NOSTR; + hl->l_date = NOSTR; + cp = line; + sp = pbuf; + /* + * Skip over "From" first. + */ + cp = nextword(cp, word); + cp = nextword(cp, word); + if (*word) + hl->l_from = copyin(word, &sp); + if (cp != NOSTR && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') { + cp = nextword(cp, word); + hl->l_tty = copyin(word, &sp); + } + if (cp != NOSTR) + hl->l_date = copyin(cp, &sp); +} + +/* + * Copy the string on the left into the string on the right + * and bump the right (reference) string pointer by the length. + * Thus, dynamically allocate space in the right string, copying + * the left string into it. + */ +char * +copyin(src, space) + register char *src; + char **space; +{ + register char *cp; + char *top; + + top = cp = *space; + while (*cp++ = *src++) + ; + *space = cp; + return (top); +} + +/* + * Test to see if the passed string is a ctime(3) generated + * date string as documented in the manual. The template + * below is used as the criterion of correctness. + * Also, we check for a possible trailing time zone using + * the tmztype template. + */ + +/* + * 'A' An upper case char + * 'a' A lower case char + * ' ' A space + * '0' A digit + * 'O' An optional digit or space + * ':' A colon + * 'N' A new line + */ +char ctype[] = "Aaa Aaa O0 00:00:00 0000"; +char tmztype[] = "Aaa Aaa O0 00:00:00 AAA 0000"; + +int +isdate(date) + char date[]; +{ + + return cmatch(date, ctype) || cmatch(date, tmztype); +} + +/* + * Match the given string (cp) against the given template (tp). + * Return 1 if they match, 0 if they don't + */ +int +cmatch(cp, tp) + register char *cp, *tp; +{ + + while (*cp && *tp) + switch (*tp++) { + case 'a': + if (!islower(*cp++)) + return 0; + break; + case 'A': + if (!isupper(*cp++)) + return 0; + break; + case ' ': + if (*cp++ != ' ') + return 0; + break; + case '0': + if (!isdigit(*cp++)) + return 0; + break; + case 'O': + if (*cp != ' ' && !isdigit(*cp)) + return 0; + cp++; + break; + case ':': + if (*cp++ != ':') + return 0; + break; + case 'N': + if (*cp++ != '\n') + return 0; + break; + } + if (*cp || *tp) + return 0; + return (1); +} + +/* + * Collect a liberal (space, tab delimited) word into the word buffer + * passed. Also, return a pointer to the next word following that, + * or NOSTR if none follow. + */ +char * +nextword(wp, wbuf) + register char *wp, *wbuf; +{ + register c; + + if (wp == NOSTR) { + *wbuf = 0; + return (NOSTR); + } + while ((c = *wp++) && c != ' ' && c != '\t') { + *wbuf++ = c; + if (c == '"') { + while ((c = *wp++) && c != '"') + *wbuf++ = c; + if (c == '"') + *wbuf++ = c; + else + wp--; + } + } + *wbuf = '\0'; + for (; c == ' ' || c == '\t'; c = *wp++) + ; + if (c == 0) + return (NOSTR); + return (wp - 1); +} diff --git a/usr.bin/mail/lex.c b/usr.bin/mail/lex.c new file mode 100644 index 0000000..3428203 --- /dev/null +++ b/usr.bin/mail/lex.c @@ -0,0 +1,665 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)lex.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include <errno.h> +#include <fcntl.h> +#include "extern.h" + +/* + * Mail -- a mail program + * + * Lexical processing of commands. + */ + +char *prompt = "& "; + +/* + * Set up editing on the given file name. + * If the first character of name is %, we are considered to be + * editing the file, otherwise we are reading our mail which has + * signficance for mbox and so forth. + */ +int +setfile(name) + char *name; +{ + FILE *ibuf; + int i; + struct stat stb; + char isedit = *name != '%'; + char *who = name[1] ? name + 1 : myname; + static int shudclob; + extern char tempMesg[]; + extern int errno; + + if ((name = expand(name)) == NOSTR) + return -1; + + if ((ibuf = Fopen(name, "r")) == NULL) { + if (!isedit && errno == ENOENT) + goto nomail; + perror(name); + return(-1); + } + + if (fstat(fileno(ibuf), &stb) < 0) { + perror("fstat"); + Fclose(ibuf); + return (-1); + } + + switch (stb.st_mode & S_IFMT) { + case S_IFDIR: + Fclose(ibuf); + errno = EISDIR; + perror(name); + return (-1); + + case S_IFREG: + break; + + default: + Fclose(ibuf); + errno = EINVAL; + perror(name); + return (-1); + } + + /* + * 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. + */ + + holdsigs(); + if (shudclob) + quit(); + + /* + * Copy the messages into /tmp + * and set pointers. + */ + + readonly = 0; + if ((i = open(name, 1)) < 0) + readonly++; + else + close(i); + if (shudclob) { + fclose(itf); + fclose(otf); + } + shudclob = 1; + edit = isedit; + strcpy(prevfile, mailname); + if (name != mailname) + strcpy(mailname, name); + mailsize = fsize(ibuf); + if ((otf = fopen(tempMesg, "w")) == NULL) { + perror(tempMesg); + exit(1); + } + (void) fcntl(fileno(otf), F_SETFD, 1); + if ((itf = fopen(tempMesg, "r")) == NULL) { + perror(tempMesg); + exit(1); + } + (void) fcntl(fileno(itf), F_SETFD, 1); + rm(tempMesg); + setptr(ibuf); + setmsize(msgCount); + Fclose(ibuf); + relsesigs(); + sawcom = 0; + if (!edit && msgCount == 0) { +nomail: + fprintf(stderr, "No mail for %s\n", who); + return -1; + } + return(0); +} + +int *msgvec; +int reset_on_stop; /* do a reset() if stopped */ + +/* + * Interpret user commands one by one. If standard input is not a tty, + * print no prompt. + */ +void +commands() +{ + int eofloop = 0; + register int n; + char linebuf[LINESIZE]; + void intr(), stop(), hangup(); + + if (!sourcing) { + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, intr); + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + signal(SIGHUP, hangup); + signal(SIGTSTP, stop); + signal(SIGTTOU, stop); + signal(SIGTTIN, stop); + } + setexit(); + for (;;) { + /* + * Print the prompt, if needed. Clear out + * string space, and flush the output. + */ + if (!sourcing && value("interactive") != NOSTR) { + reset_on_stop = 1; + printf(prompt); + } + fflush(stdout); + sreset(); + /* + * Read a line of commands from the current input + * and handle end of file specially. + */ + n = 0; + for (;;) { + if (readline(input, &linebuf[n], LINESIZE - n) < 0) { + if (n == 0) + n = -1; + break; + } + if ((n = strlen(linebuf)) == 0) + break; + n--; + if (linebuf[n] != '\\') + break; + linebuf[n++] = ' '; + } + reset_on_stop = 0; + if (n < 0) { + /* eof */ + if (loading) + break; + if (sourcing) { + unstack(); + continue; + } + if (value("interactive") != NOSTR && + value("ignoreeof") != NOSTR && + ++eofloop < 25) { + printf("Use \"quit\" to quit.\n"); + continue; + } + break; + } + eofloop = 0; + if (execute(linebuf, 0)) + break; + } +} + +/* + * Execute a single command. + * Command functions return 0 for success, 1 for error, and -1 + * for abort. A 1 or -1 aborts a load or source. A -1 aborts + * the interactive command loop. + * Contxt is non-zero if called while composing mail. + */ +int +execute(linebuf, contxt) + char linebuf[]; + int contxt; +{ + char word[LINESIZE]; + char *arglist[MAXARGC]; + struct cmd *com; + register char *cp, *cp2; + register int c; + int muvec[2]; + int e = 1; + + /* + * 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 + * lexical conventions. + */ + + for (cp = linebuf; isspace(*cp); cp++) + ; + if (*cp == '!') { + if (sourcing) { + printf("Can't \"!\" while sourcing\n"); + goto out; + } + shell(cp+1); + return(0); + } + cp2 = word; + while (*cp && index(" \t0123456789$^.:/-+*'\"", *cp) == NOSTR) + *cp2++ = *cp++; + *cp2 = '\0'; + + /* + * 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 + * confusion. + */ + + if (sourcing && *word == '\0') + return(0); + com = lex(word); + if (com == NONE) { + printf("Unknown command: \"%s\"\n", word); + goto out; + } + + /* + * 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) + return(0); + + /* + * 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 + * an error. + */ + + if (!rcvmode && (com->c_argtype & M) == 0) { + printf("May not execute \"%s\" while sending\n", + com->c_name); + goto out; + } + if (sourcing && com->c_argtype & I) { + printf("May not execute \"%s\" while sourcing\n", + com->c_name); + goto out; + } + if (readonly && com->c_argtype & W) { + printf("May not execute \"%s\" -- message file is read only\n", + com->c_name); + goto out; + } + if (contxt && com->c_argtype & R) { + printf("Cannot recursively invoke \"%s\"\n", com->c_name); + goto out; + } + switch (com->c_argtype & ~(F|P|I|M|T|W|R)) { + case MSGLIST: + /* + * A message list defaulting to nearest forward + * legal message. + */ + if (msgvec == 0) { + printf("Illegal use of \"message list\"\n"); + break; + } + if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0) + break; + if (c == 0) { + *msgvec = first(com->c_msgflag, + com->c_msgmask); + msgvec[1] = NULL; + } + if (*msgvec == NULL) { + printf("No applicable messages\n"); + break; + } + e = (*com->c_func)(msgvec); + break; + + case NDMLIST: + /* + * A message list with no defaults, but no error + * if none exist. + */ + if (msgvec == 0) { + printf("Illegal use of \"message list\"\n"); + break; + } + if (getmsglist(cp, msgvec, com->c_msgflag) < 0) + break; + e = (*com->c_func)(msgvec); + break; + + case STRLIST: + /* + * Just the straight string, with + * leading blanks removed. + */ + while (isspace(*cp)) + cp++; + e = (*com->c_func)(cp); + break; + + case RAWLIST: + /* + * A vector of strings, in shell style. + */ + if ((c = getrawlist(cp, arglist, + sizeof arglist / sizeof *arglist)) < 0) + break; + if (c < com->c_minargs) { + printf("%s requires at least %d arg(s)\n", + com->c_name, com->c_minargs); + break; + } + if (c > com->c_maxargs) { + printf("%s takes no more than %d arg(s)\n", + com->c_name, com->c_maxargs); + break; + } + e = (*com->c_func)(arglist); + break; + + case NOLIST: + /* + * Just the constant zero, for exiting, + * eg. + */ + e = (*com->c_func)(0); + break; + + default: + panic("Unknown argtype"); + } + +out: + /* + * Exit the current source file on + * error. + */ + if (e) { + if (e < 0) + return 1; + if (loading) + return 1; + if (sourcing) + unstack(); + return 0; + } + if (value("autoprint") != NOSTR && com->c_argtype & P) + if ((dot->m_flag & MDELETED) == 0) { + muvec[0] = dot - &message[0] + 1; + muvec[1] = 0; + type(muvec); + } + if (!sourcing && (com->c_argtype & T) == 0) + sawcom = 1; + return(0); +} + +/* + * Set the size of the message vector used to construct argument + * lists to message list functions. + */ +void +setmsize(sz) + int sz; +{ + + if (msgvec != 0) + free((char *) msgvec); + msgvec = (int *) calloc((unsigned) (sz + 1), sizeof *msgvec); +} + +/* + * Find the correct command in the command table corresponding + * to the passed command "word" + */ + +struct cmd * +lex(word) + char word[]; +{ + register struct cmd *cp; + extern struct cmd cmdtab[]; + + for (cp = &cmdtab[0]; cp->c_name != NOSTR; cp++) + if (isprefix(word, cp->c_name)) + return(cp); + return(NONE); +} + +/* + * Determine if as1 is a valid prefix of as2. + * Return true if yep. + */ +int +isprefix(as1, as2) + char *as1, *as2; +{ + register char *s1, *s2; + + s1 = as1; + s2 = as2; + while (*s1++ == *s2) + if (*s2++ == '\0') + return(1); + return(*--s1 == '\0'); +} + +/* + * The following gets called on receipt of an interrupt. 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. + * Also, unstack all source files. + */ + +int inithdr; /* am printing startup headers */ + +/*ARGSUSED*/ +void +intr(s) + int s; +{ + + noreset = 0; + if (!inithdr) + sawcom++; + inithdr = 0; + while (sourcing) + unstack(); + + close_all_files(); + + if (image >= 0) { + close(image); + image = -1; + } + fprintf(stderr, "Interrupt\n"); + reset(0); +} + +/* + * When we wake up after ^Z, reprint the prompt. + */ +void +stop(s) + int s; +{ + sig_t old_action = signal(s, SIG_DFL); + + sigsetmask(sigblock(0) & ~sigmask(s)); + kill(0, s); + sigblock(sigmask(s)); + signal(s, old_action); + if (reset_on_stop) { + reset_on_stop = 0; + reset(0); + } +} + +/* + * Branch here on hangup signal and simulate "exit". + */ +/*ARGSUSED*/ +void +hangup(s) + int s; +{ + + /* nothing to do? */ + exit(1); +} + +/* + * Announce the presence of the current Mail version, + * give the message count, and print a header listing. + */ +void +announce() +{ + int vec[2], mdot; + + mdot = newfileinfo(); + vec[0] = mdot; + vec[1] = 0; + dot = &message[mdot - 1]; + if (msgCount > 0 && value("noheader") == NOSTR) { + inithdr++; + headers(vec); + inithdr = 0; + } +} + +/* + * Announce information about the file we are editing. + * Return a likely place to set dot. + */ +int +newfileinfo() +{ + 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->m_flag & MNEW) + break; + if (mp >= &message[msgCount]) + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if ((mp->m_flag & MREAD) == 0) + break; + if (mp < &message[msgCount]) + mdot = mp - &message[0] + 1; + else + mdot = 1; + s = d = 0; + for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) { + if (mp->m_flag & MNEW) + n++; + if ((mp->m_flag & MREAD) == 0) + u++; + if (mp->m_flag & MDELETED) + d++; + if (mp->m_flag & MSAVED) + s++; + } + ename = mailname; + if (getfold(fname) >= 0) { + strcat(fname, "/"); + if (strncmp(fname, mailname, strlen(fname)) == 0) { + sprintf(zname, "+%s", mailname + strlen(fname)); + ename = zname; + } + } + printf("\"%s\": ", ename); + if (msgCount == 1) + printf("1 message"); + else + printf("%d messages", msgCount); + if (n > 0) + printf(" %d new", n); + if (u-n > 0) + printf(" %d unread", u); + if (d > 0) + printf(" %d deleted", d); + if (s > 0) + printf(" %d saved", s); + if (readonly) + printf(" [Read only]"); + printf("\n"); + return(mdot); +} + +/* + * Print the current version number. + */ + +/*ARGSUSED*/ +int +pversion(e) + int e; +{ + extern char *version; + + printf("Version %s\n", version); + return(0); +} + +/* + * Load a file of user definitions. + */ +void +load(name) + char *name; +{ + register FILE *in, *oldin; + + if ((in = Fopen(name, "r")) == NULL) + return; + oldin = input; + input = in; + loading = 1; + sourcing = 1; + commands(); + loading = 0; + sourcing = 0; + input = oldin; + Fclose(in); +} diff --git a/usr.bin/mail/list.c b/usr.bin/mail/list.c new file mode 100644 index 0000000..18cf1eb --- /dev/null +++ b/usr.bin/mail/list.c @@ -0,0 +1,801 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)list.c 8.2 (Berkeley) 4/19/94"; +#endif /* not lint */ + +#include "rcv.h" +#include <ctype.h> +#include "extern.h" + +/* + * Mail -- a mail program + * + * Message list handling. + */ + +/* + * Convert the user string of message numbers and + * store the numbers into vector. + * + * Returns the count of messages picked up or -1 on error. + */ +int +getmsglist(buf, vector, flags) + char *buf; + int *vector, flags; +{ + register int *ip; + register struct message *mp; + + if (msgCount == 0) { + *vector = 0; + return 0; + } + if (markall(buf, flags) < 0) + return(-1); + ip = vector; + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if (mp->m_flag & MMARK) + *ip++ = mp - &message[0] + 1; + *ip = 0; + return(ip - vector); +} + +/* + * Mark all messages that the user wanted from the command + * line in the message structure. Return 0 on success, -1 + * on error. + */ + +/* + * Bit values for colon modifiers. + */ + +#define CMNEW 01 /* New messages */ +#define CMOLD 02 /* Old messages */ +#define CMUNREAD 04 /* Unread messages */ +#define CMDELETED 010 /* Deleted messages */ +#define CMREAD 020 /* Read messages */ + +/* + * The following table describes the letters which can follow + * the colon and gives the corresponding modifier bit. + */ + +struct coltab { + char co_char; /* What to find past : */ + int co_bit; /* Associated modifier bit */ + int co_mask; /* m_status bits to mask */ + int co_equal; /* ... must equal this */ +} coltab[] = { + 'n', CMNEW, MNEW, MNEW, + 'o', CMOLD, MNEW, 0, + 'u', CMUNREAD, MREAD, 0, + 'd', CMDELETED, MDELETED, MDELETED, + 'r', CMREAD, MREAD, MREAD, + 0, 0, 0, 0 +}; + +static int lastcolmod; + +int +markall(buf, f) + char buf[]; + int f; +{ + register char **np; + register int i; + register struct message *mp; + char *namelist[NMLSIZE], *bufp; + int tok, beg, mc, star, other, valdot, colmod, colresult; + + valdot = dot - &message[0] + 1; + colmod = 0; + for (i = 1; i <= msgCount; i++) + unmark(i); + bufp = buf; + mc = 0; + np = &namelist[0]; + scaninit(); + tok = scan(&bufp); + star = 0; + other = 0; + beg = 0; + while (tok != TEOL) { + switch (tok) { + case TNUMBER: +number: + if (star) { + printf("No numbers mixed with *\n"); + return(-1); + } + mc++; + other++; + if (beg != 0) { + if (check(lexnumber, f)) + return(-1); + for (i = beg; i <= lexnumber; i++) + if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0) + mark(i); + beg = 0; + break; + } + beg = lexnumber; + if (check(beg, f)) + return(-1); + tok = scan(&bufp); + regret(tok); + if (tok != TDASH) { + mark(beg); + beg = 0; + } + break; + + case TPLUS: + if (beg != 0) { + printf("Non-numeric second argument\n"); + return(-1); + } + i = valdot; + do { + i++; + if (i > msgCount) { + printf("Referencing beyond EOF\n"); + return(-1); + } + } while ((message[i - 1].m_flag & MDELETED) != f); + mark(i); + break; + + case TDASH: + if (beg == 0) { + i = valdot; + do { + i--; + if (i <= 0) { + printf("Referencing before 1\n"); + return(-1); + } + } while ((message[i - 1].m_flag & MDELETED) != f); + mark(i); + } + break; + + case TSTRING: + if (beg != 0) { + printf("Non-numeric second argument\n"); + return(-1); + } + other++; + if (lexstring[0] == ':') { + colresult = evalcol(lexstring[1]); + if (colresult == 0) { + printf("Unknown colon modifier \"%s\"\n", + lexstring); + return(-1); + } + colmod |= colresult; + } + else + *np++ = savestr(lexstring); + break; + + case TDOLLAR: + case TUP: + case TDOT: + lexnumber = metamess(lexstring[0], f); + if (lexnumber == -1) + return(-1); + goto number; + + case TSTAR: + if (other) { + printf("Can't mix \"*\" with anything\n"); + return(-1); + } + star++; + break; + + case TERROR: + return -1; + } + tok = scan(&bufp); + } + lastcolmod = colmod; + *np = NOSTR; + mc = 0; + if (star) { + for (i = 0; i < msgCount; i++) + if ((message[i].m_flag & MDELETED) == f) { + mark(i+1); + mc++; + } + if (mc == 0) { + printf("No applicable messages.\n"); + return(-1); + } + return(0); + } + + /* + * If no numbers were given, mark all of the messages, + * so that we can unmark any whose sender was not selected + * if any user names were given. + */ + + if ((np > namelist || colmod != 0) && mc == 0) + for (i = 1; i <= msgCount; i++) + if ((message[i-1].m_flag & MDELETED) == f) + mark(i); + + /* + * If any names were given, go through and eliminate any + * messages whose senders were not requested. + */ + + if (np > namelist) { + for (i = 1; i <= msgCount; i++) { + for (mc = 0, np = &namelist[0]; *np != NOSTR; np++) + if (**np == '/') { + if (matchsubj(*np, i)) { + mc++; + break; + } + } + else { + if (matchsender(*np, i)) { + mc++; + break; + } + } + if (mc == 0) + unmark(i); + } + + /* + * Make sure we got some decent messages. + */ + + mc = 0; + for (i = 1; i <= msgCount; i++) + if (message[i-1].m_flag & MMARK) { + mc++; + break; + } + if (mc == 0) { + printf("No applicable messages from {%s", + namelist[0]); + for (np = &namelist[1]; *np != NOSTR; np++) + printf(", %s", *np); + printf("}\n"); + return(-1); + } + } + + /* + * If any colon modifiers were given, go through and + * unmark any messages which do not satisfy the modifiers. + */ + + if (colmod != 0) { + for (i = 1; i <= msgCount; i++) { + register struct coltab *colp; + + mp = &message[i - 1]; + for (colp = &coltab[0]; colp->co_char; colp++) + if (colp->co_bit & colmod) + if ((mp->m_flag & colp->co_mask) + != colp->co_equal) + unmark(i); + + } + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if (mp->m_flag & MMARK) + break; + if (mp >= &message[msgCount]) { + register struct coltab *colp; + + printf("No messages satisfy"); + for (colp = &coltab[0]; colp->co_char; colp++) + if (colp->co_bit & colmod) + printf(" :%c", colp->co_char); + printf("\n"); + return(-1); + } + } + return(0); +} + +/* + * Turn the character after a colon modifier into a bit + * value. + */ +int +evalcol(col) + int col; +{ + register struct coltab *colp; + + if (col == 0) + return(lastcolmod); + for (colp = &coltab[0]; colp->co_char; colp++) + if (colp->co_char == col) + return(colp->co_bit); + return(0); +} + +/* + * Check the passed message number for legality and proper flags. + * If f is MDELETED, then either kind will do. Otherwise, the message + * has to be undeleted. + */ +int +check(mesg, f) + int mesg, f; +{ + register struct message *mp; + + if (mesg < 1 || mesg > msgCount) { + printf("%d: Invalid message number\n", mesg); + return(-1); + } + mp = &message[mesg-1]; + if (f != MDELETED && (mp->m_flag & MDELETED) != 0) { + printf("%d: Inappropriate message\n", mesg); + return(-1); + } + return(0); +} + +/* + * Scan out the list of string arguments, shell style + * for a RAWLIST. + */ +int +getrawlist(line, argv, argc) + char line[]; + char **argv; + int argc; +{ + register char c, *cp, *cp2, quotec; + int argn; + char linebuf[BUFSIZ]; + + argn = 0; + cp = line; + for (;;) { + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + if (*cp == '\0') + break; + if (argn >= argc - 1) { + printf( + "Too many elements in the list; excess discarded.\n"); + break; + } + cp2 = linebuf; + quotec = '\0'; + while ((c = *cp) != '\0') { + cp++; + if (quotec != '\0') { + if (c == quotec) + quotec = '\0'; + else if (c == '\\') + switch (c = *cp++) { + case '\0': + *cp2++ = '\\'; + cp--; + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c -= '0'; + if (*cp >= '0' && *cp <= '7') + c = c * 8 + *cp++ - '0'; + if (*cp >= '0' && *cp <= '7') + c = c * 8 + *cp++ - '0'; + *cp2++ = c; + break; + case 'b': + *cp2++ = '\b'; + break; + case 'f': + *cp2++ = '\f'; + break; + case 'n': + *cp2++ = '\n'; + break; + case 'r': + *cp2++ = '\r'; + break; + case 't': + *cp2++ = '\t'; + break; + case 'v': + *cp2++ = '\v'; + break; + default: + *cp2++ = c; + } + else if (c == '^') { + c = *cp++; + if (c == '?') + *cp2++ = '\177'; + /* null doesn't show up anyway */ + else if (c >= 'A' && c <= '_' || + c >= 'a' && c <= 'z') + *cp2++ = c & 037; + else { + *cp2++ = '^'; + cp--; + } + } else + *cp2++ = c; + } else if (c == '"' || c == '\'') + quotec = c; + else if (c == ' ' || c == '\t') + break; + else + *cp2++ = c; + } + *cp2 = '\0'; + argv[argn++] = savestr(linebuf); + } + argv[argn] = NOSTR; + return argn; +} + +/* + * scan out a single lexical item and return its token number, + * updating the string pointer passed **p. Also, store the value + * of the number or string scanned in lexnumber or lexstring as + * appropriate. In any event, store the scanned `thing' in lexstring. + */ + +struct lex { + char l_char; + char l_token; +} singles[] = { + '$', TDOLLAR, + '.', TDOT, + '^', TUP, + '*', TSTAR, + '-', TDASH, + '+', TPLUS, + '(', TOPEN, + ')', TCLOSE, + 0, 0 +}; + +int +scan(sp) + char **sp; +{ + register char *cp, *cp2; + register int c; + register struct lex *lp; + int quotec; + + if (regretp >= 0) { + strcpy(lexstring, string_stack[regretp]); + lexnumber = numberstack[regretp]; + return(regretstack[regretp--]); + } + cp = *sp; + cp2 = lexstring; + c = *cp++; + + /* + * strip away leading white space. + */ + + while (c == ' ' || c == '\t') + c = *cp++; + + /* + * If no characters remain, we are at end of line, + * so report that. + */ + + if (c == '\0') { + *sp = --cp; + return(TEOL); + } + + /* + * If the leading character is a digit, scan + * the number and convert it on the fly. + * Return TNUMBER when done. + */ + + if (isdigit(c)) { + lexnumber = 0; + while (isdigit(c)) { + lexnumber = lexnumber*10 + c - '0'; + *cp2++ = c; + c = *cp++; + } + *cp2 = '\0'; + *sp = --cp; + return(TNUMBER); + } + + /* + * Check for single character tokens; return such + * if found. + */ + + for (lp = &singles[0]; lp->l_char != 0; lp++) + if (c == lp->l_char) { + lexstring[0] = c; + lexstring[1] = '\0'; + *sp = cp; + return(lp->l_token); + } + + /* + * We've got a string! Copy all the characters + * of the string into lexstring, until we see + * a null, space, or tab. + * If the lead character is a " or ', save it + * and scan until you get another. + */ + + quotec = 0; + if (c == '\'' || c == '"') { + quotec = c; + c = *cp++; + } + while (c != '\0') { + if (c == quotec) { + cp++; + break; + } + if (quotec == 0 && (c == ' ' || c == '\t')) + break; + if (cp2 - lexstring < STRINGLEN-1) + *cp2++ = c; + c = *cp++; + } + if (quotec && c == 0) { + fprintf(stderr, "Missing %c\n", quotec); + return TERROR; + } + *sp = --cp; + *cp2 = '\0'; + return(TSTRING); +} + +/* + * Unscan the named token by pushing it onto the regret stack. + */ +void +regret(token) + int token; +{ + if (++regretp >= REGDEP) + panic("Too many regrets"); + regretstack[regretp] = token; + lexstring[STRINGLEN-1] = '\0'; + string_stack[regretp] = savestr(lexstring); + numberstack[regretp] = lexnumber; +} + +/* + * Reset all the scanner global variables. + */ +void +scaninit() +{ + regretp = -1; +} + +/* + * Find the first message whose flags & m == f and return + * its message number. + */ +int +first(f, m) + int f, m; +{ + register struct message *mp; + + if (msgCount == 0) + return 0; + f &= MDELETED; + m &= MDELETED; + for (mp = dot; mp < &message[msgCount]; mp++) + if ((mp->m_flag & m) == f) + return mp - message + 1; + for (mp = dot-1; mp >= &message[0]; mp--) + if ((mp->m_flag & m) == f) + return mp - message + 1; + return 0; +} + +/* + * See if the passed name sent the passed message number. Return true + * if so. + */ +int +matchsender(str, mesg) + char *str; + int mesg; +{ + register char *cp, *cp2, *backup; + + if (!*str) /* null string matches nothing instead of everything */ + return 0; + backup = cp2 = nameof(&message[mesg - 1], 0); + cp = str; + while (*cp2) { + if (*cp == 0) + return(1); + if (raise(*cp++) != raise(*cp2++)) { + cp2 = ++backup; + cp = str; + } + } + return(*cp == 0); +} + +/* + * See if the given string matches inside the subject field of the + * given message. For the purpose of the scan, we ignore case differences. + * If it does, return true. The string search argument is assumed to + * have the form "/search-string." If it is of the form "/," we use the + * previous search string. + */ + +char lastscan[128]; +int +matchsubj(str, mesg) + char *str; + int mesg; +{ + register struct message *mp; + register char *cp, *cp2, *backup; + + str++; + if (strlen(str) == 0) + str = lastscan; + else + strcpy(lastscan, str); + mp = &message[mesg-1]; + + /* + * Now look, ignoring case, for the word in the string. + */ + + if (value("searchheaders") && (cp = index(str, ':'))) { + *cp++ = '\0'; + cp2 = hfield(str, mp); + cp[-1] = ':'; + str = cp; + } else { + cp = str; + cp2 = hfield("subject", mp); + } + if (cp2 == NOSTR) + return(0); + backup = cp2; + while (*cp2) { + if (*cp == 0) + return(1); + if (raise(*cp++) != raise(*cp2++)) { + cp2 = ++backup; + cp = str; + } + } + return(*cp == 0); +} + +/* + * Mark the named message by setting its mark bit. + */ +void +mark(mesg) + int mesg; +{ + register int i; + + i = mesg; + if (i < 1 || i > msgCount) + panic("Bad message number to mark"); + message[i-1].m_flag |= MMARK; +} + +/* + * Unmark the named message. + */ +void +unmark(mesg) + int mesg; +{ + register int i; + + i = mesg; + if (i < 1 || i > msgCount) + panic("Bad message number to unmark"); + message[i-1].m_flag &= ~MMARK; +} + +/* + * Return the message number corresponding to the passed meta character. + */ +int +metamess(meta, f) + int meta, f; +{ + register int c, m; + register struct message *mp; + + c = meta; + switch (c) { + case '^': + /* + * First 'good' message left. + */ + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if ((mp->m_flag & MDELETED) == f) + return(mp - &message[0] + 1); + printf("No applicable messages\n"); + return(-1); + + case '$': + /* + * Last 'good message left. + */ + for (mp = &message[msgCount-1]; mp >= &message[0]; mp--) + if ((mp->m_flag & MDELETED) == f) + return(mp - &message[0] + 1); + printf("No applicable messages\n"); + return(-1); + + case '.': + /* + * Current message. + */ + m = dot - &message[0] + 1; + if ((dot->m_flag & MDELETED) != f) { + printf("%d: Inappropriate message\n", m); + return(-1); + } + return(m); + + default: + printf("Unknown metachar (%c)\n", c); + return(-1); + } +} diff --git a/usr.bin/mail/mail.1 b/usr.bin/mail/mail.1 new file mode 100644 index 0000000..ecf5868 --- /dev/null +++ b/usr.bin/mail/mail.1 @@ -0,0 +1,1030 @@ +.\" Copyright (c) 1980, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)mail.1 8.2 (Berkeley) 12/30/93 +.\" +.Dd December 30, 1993 +.Dt MAIL 1 +.Os BSD 4 +.Sh NAME +.Nm mail +.Nd send and receive mail +.Sh SYNOPSIS +.Nm mail +.Op Fl iInv +.Op Fl s Ar subject +.Op Fl c Ar cc-addr +.Op Fl b Ar bcc-addr +.Ar to-addr... +.Nm mail +.Op Fl iInNv +.Fl f +.Op Ar name +.Nm mail +.Op Fl iInNv +.Op Fl u Ar user +.Sh INTRODUCTION +.Nm Mail +is an intelligent mail processing system, which has +a command syntax reminiscent of +.Xr \&ed 1 +with lines replaced by messages. +.Pp +.Bl -tag -width flag +.It Fl v +Verbose mode. +The details of +delivery are displayed on the user's terminal. +.It Fl i +Ignore tty interrupt signals. +This is +particularly useful when using +.Nm mail +on noisy phone lines. +.It Fl I +Forces mail to run in interactive mode even when +input isn't a terminal. +In particular, the +.Sq Ic \&~ +special +character when sending mail is only active in interactive mode. +.It Fl n +Inhibits reading +.Pa /usr/share/misc/Mail.rc +upon startup. +.It Fl N +Inhibits the initial display of message headers +when reading mail or editing a mail folder. +.It Fl s +Specify subject on command line +(only the first argument after the +.Fl s +flag is used as a subject; be careful to quote subjects +containing spaces.) +.It Fl c +Send carbon copies to +.Ar list +of users. +.It Fl b +Send blind carbon copies to +.Ar list . +List should be a comma-separated list of names. +.It Fl f +Read in the contents of your +.Ar mbox +(or the specified file) +for processing; when you +.Ar quit , +.Nm mail +writes undeleted messages back to this file. +.It Fl u +Is equivalent to: +.Pp +.Dl mail -f /var/spool/mail/user +.El +.Ss Sending mail +To send a message to one or more people, +.Nm mail +can be invoked with arguments which are the names of people to +whom the mail will be sent. +You are then expected to type in +your message, followed +by an +.Sq Li control\-D +at the beginning of a line. +The section below +.Ar Replying to or originating mail , +describes some features of +.Nm mail +available to help you compose your letter. +.Pp +.Ss Reading mail +In normal usage +.Nm mail +is given no arguments and checks your mail out of the +post office, then +prints out a one line header of each message found. +The current message is initially the first message (numbered 1) +and can be printed using the +.Ic print +command (which can be abbreviated +.Ql Ic p ) . +You can move among the messages much as you move between lines in +.Xr \&ed 1 , +with the commands +.Ql Ic \&+ +and +.Ql Ic \&\- +moving backwards and forwards, and +simple numbers. +.Pp +.Ss Disposing of mail. +After examining a message you can +.Ic delete +.Ql Ic d ) +the message or +.Ic reply +.Ql Ic r ) +to it. +Deletion causes the +.Nm mail +program to forget about the message. +This is not irreversible; the message can be +.Ic undeleted +.Ql Ic u ) +by giving its number, or the +.Nm mail +session can be aborted by giving the +.Ic exit +.Ql Ic x ) +command. +Deleted messages will, however, usually disappear never to be seen again. +.Pp +.Ss Specifying messages +Commands such as +.Ic print +and +.Ic delete +can be given a list of message numbers as arguments to apply +to a number of messages at once. +Thus +.Dq Li delete 1 2 +deletes messages 1 and 2, while +.Dq Li delete 1\-5 +deletes messages 1 through 5. +The special name +.Ql Li \&* +addresses all messages, and +.Ql Li \&$ +addresses +the last message; thus the command +.Ic top +which prints the first few lines of a message could be used in +.Dq Li top \&* +to print the first few lines of all messages. +.Pp +.Ss Replying to or originating mail. +You can use the +.Ic reply +command to +set up a response to a message, sending it back to the +person who it was from. +Text you then type in, up to an end-of-file, +defines the contents of the message. +While you are composing a message, +.Nm mail +treats lines beginning with the character +.Ql Ic \&~ +specially. +For instance, typing +.Ql Ic \&~m +(alone on a line) will place a copy +of the current message into the response right shifting it by a tabstop +(see +.Em indentprefix +variable, below). +Other escapes will set up subject fields, add and delete recipients +to the message and allow you to escape to an editor to revise the +message or to a shell to run some commands. +(These options +are given in the summary below.) +.Pp +.Ss Ending a mail processing session. +You can end a +.Nm mail +session with the +.Ic quit +.Ql Ic q ) +command. +Messages which have been examined go to your +.Ar mbox +file unless they have been deleted in which case they are discarded. +Unexamined messages go back to the post office. +(See the +.Fl f +option above). +.Pp +.Ss Personal and systemwide distribution lists. +It is also possible to create a personal distribution lists so that, +for instance, you can send mail to +.Dq Li cohorts +and have it go +to a group of people. +Such lists can be defined by placing a line like +.Pp +.Dl alias cohorts bill ozalp jkf mark kridle@ucbcory +.Pp +in the file +.Pa \&.mailrc +in your home directory. +The current list of such aliases can be displayed with the +.Ic alias +command in +.Nm mail . +System wide distribution lists can be created by editing +.Pa /etc/aliases , +see +.Xr aliases 5 +and +.Xr sendmail 8 ; +these are kept in a different syntax. +In mail you send, personal aliases will be expanded in mail sent +to others so that they will be able to +.Ic reply +to the recipients. +System wide +.Ic aliases +are not expanded when the mail is sent, +but any reply returned to the machine will have the system wide +alias expanded as all mail goes through +.Xr sendmail . +.Pp +.Ss Network mail (ARPA, UUCP, Berknet) +See +.Xr mailaddr 7 +for a description of network addresses. +.Pp +.Nm Mail +has a number of options which can be set in the +.Pa .mailrc +file to alter its behavior; thus +.Dq Li set askcc +enables the +.Ar askcc +feature. +(These options are summarized below.) +.Sh SUMMARY +(Adapted from the `Mail Reference Manual') +.Pp +Each command is typed on a line by itself, and may take arguments +following the command word. +The command need not be typed in its +entirety \- the first command which matches the typed prefix is used. +For commands which take message lists as arguments, if no message +list is given, then the next message forward which satisfies the +command's requirements is used. +If there are no messages forward of +the current message, the search proceeds backwards, and if there are no +good messages at all, +.Nm mail +types +.Dq Li No applicable messages +and +aborts the command. +.Bl -tag -width delete +.It Ic \&\- +Print out the preceding message. +If given a numeric +argument +.Ar n , +goes to the +.Ar n Ns 'th +previous message and prints it. +.It Ic \&? +Prints a brief summary of commands. +.It Ic \&! +Executes the shell +(see +.Xr sh 1 +and +.Xr csh 1 ) +command which follows. +.It Ic Print +.Pq Ic P +Like +.Ic print +but also prints out ignored header fields. +See also +.Ic print , +.Ic ignore +and +.Ic retain . +.It Ic Reply +.Pq Ic R +Reply to originator. +Does not reply to other +recipients of the original message. +.It Ic Type +.Pq Ic T +Identical to the +.Ic Print +command. +.It Ic alias +.Pq Ic a +With no arguments, prints out all currently-defined aliases. +With one +argument, prints out that alias. +With more than one argument, creates +a new alias or changes an old one. +.It Ic alternates +.Pq Ic alt +The +.Ic alternates +command is useful if you have accounts on several machines. +It can be used to inform +.Nm mail +that the listed addresses are really you. +When you +.Ic reply +to messages, +.Nm mail +will not send a copy of the message to any of the addresses +listed on the +.Ic alternates +list. +If the +.Ic alternates +command is given with no argument, the current set of alternate +names is displayed. +.It Ic chdir +.Pq Ic c +Changes the user's working directory to that specified, if given. +If +no directory is given, then changes to the user's login directory. +.It Ic copy +.Pq Ic co +The +.Ic copy +command does the same thing that +.Ic save +does, except that it does not mark the messages it +is used on for deletion when you quit. +.It Ic delete +.Pq Ic d +Takes a list of messages as argument and marks them all as deleted. +Deleted messages will not be saved in +.Ar mbox , +nor will they be available for most other commands. +.It Ic dp +(also +.Ic dt ) +Deletes the current message and prints the next message. +If there is no next message, +.Nm mail +says +.Dq Li "at EOF" . +.It Ic edit +.Pq Ic e +Takes a list of messages and points the text editor at each one in +turn. +On return from the editor, the message is read back in. +.It Ic exit +.Pf ( Ic ex +or +.Ic x ) +Effects an immediate return to the Shell without +modifying the user's system mailbox, his +.Ar mbox +file, or his edit file in +.Fl f . +.It Ic file +.Pq Ic fi +The same as +.Ic folder . +.It Ic folders +List the names of the folders in your folder directory. +.It Ic folder +.Pq Ic fo +The +.Ic folder +command switches to a new mail file or folder. +With no +arguments, it tells you which file you are currently reading. +If you give it an argument, it will write out changes (such +as deletions) you have made in the current file and read in +the new file. +Some special conventions are recognized for +the name. +# means the previous file, % means your system +mailbox, %user means user's system mailbox, & means +your +.Ar mbox +file, and +\&+\&folder means a file in your folder +directory. +.It Ic from +.Pq Ic f +Takes a list of messages and prints their message headers. +.It Ic headers +.Pq Ic h +Lists the current range of headers, which is an 18\-message group. +If +a +.Ql \&+ +argument is given, then the next 18\-message group is printed, and if +a +.Ql \&\- +argument is given, the previous 18\-message group is printed. +.It Ic help +A synonym for +.Ic \&? +.It Ic hold +.Pf ( Ic ho , +also +.Ic preserve ) +Takes a message list and marks each +message therein to be saved in the +user's system mailbox instead of in +.Ar mbox . +Does not override the +.Ic delete +command. +.It Ic ignore +Add the list of header fields named to the +.Ar ignored list . +Header fields in the ignore list are not printed +on your terminal when you print a message. +This +command is very handy for suppression of certain machine-generated +header fields. +The +.Ic Type +and +.Ic Print +commands can be used to print a message in its entirety, including +ignored fields. +If +.Ic ignore +is executed with no arguments, it lists the current set of +ignored fields. +.It Ic mail +.Pq Ic m +Takes as argument login names and distribution group names and sends +mail to those people. +.It Ic mbox +Indicate that a list of messages be sent to +.Ic mbox +in your home directory when you quit. +This is the default +action for messages if you do +.Em not +have the +.Ic hold +option set. +.It Ic next +.Pq Ic n +like +.Ic \&+ +or +.Tn CR ) +Goes to the next message in sequence and types it. +With an argument list, types the next matching message. +.It Ic preserve +.Pq Ic pre +A synonym for +.Ic hold . +.It Ic print +.Pq Ic p +Takes a message list and types out each message on the user's terminal. +.It Ic quit +.Pq Ic q +Terminates the session, saving all undeleted, unsaved messages in +the user's +.Ar mbox +file in his login directory, preserving all messages marked with +.Ic hold +or +.Ic preserve +or never referenced +in his system mailbox, and removing all other messages from his system +mailbox. +If new mail has arrived during the session, the message +.Dq Li "You have new mail" +is given. +If given while editing a +mailbox file with the +.Fl f +flag, then the edit file is rewritten. +A return to the Shell is +effected, unless the rewrite of edit file fails, in which case the user +can escape with the +.Ic exit +command. +.It Ic reply +.Pq Ic r +Takes a message list and sends mail to the sender and all +recipients of the specified message. +The default message must not be deleted. +.It Ic respond +A synonym for +.Ic reply . +.It Ic retain +Add the list of header fields named to the +.Ar retained list +Only the header fields in the retain list +are shown on your terminal when you print a message. +All other header fields are suppressed. +The +.Ic Type +and +.Ic Print +commands can be used to print a message in its entirety. +If +.Ic retain +is executed with no arguments, it lists the current set of +retained fields. +.It Ic save +.Pq Ic s +Takes a message list and a filename and appends each message in +turn to the end of the file. +The filename in quotes, followed by the line +count and character count is echoed on the user's terminal. +.It Ic set +.Pq Ic se +With no arguments, prints all variable values. +Otherwise, sets +option. +Arguments are of the form +.Ar option=value +(no space before or after =) or +.Ar option . +Quotation marks may be placed around any part of the assignment statement to +quote blanks or tabs, i.e. +.Dq Li "set indentprefix=\*q->\*q" +.It Ic saveignore +.Ic Saveignore +is to +.Ic save +what +.Ic ignore +is to +.Ic print +and +.Ic type . +Header fields thus marked are filtered out when +saving a message by +.Ic save +or when automatically saving to +.Ar mbox . +.It Ic saveretain +.Ic Saveretain +is to +.Ic save +what +.Ic retain +is to +.Ic print +and +.Ic type . +Header fields thus marked are the only ones saved +with a message when saving by +.Ic save +or when automatically saving to +.Ar mbox . +.Ic Saveretain +overrides +.Ic saveignore . +.It Ic shell +.Pq Ic sh +Invokes an interactive version of the shell. +.It Ic size +Takes a message list and prints out the size in characters of each +message. +.It Ic source +The +.Ic source +command reads +commands from a file. +.It Ic top +Takes a message list and prints the top few lines of each. +The number of +lines printed is controlled by the variable +.Ic toplines +and defaults to five. +.It Ic type +.Pq Ic t +A synonym for +.Ic print . +.It Ic unalias +Takes a list of names defined by +.Ic alias +commands and discards the remembered groups of users. +The group names +no longer have any significance. +.It Ic undelete +.Pq Ic u +Takes a message list and marks each message as +.Ic not +being deleted. +.It Ic unread +.Pq Ic U +Takes a message list and marks each message as +.Ic not +having been read. +.It Ic unset +Takes a list of option names and discards their remembered values; +the inverse of +.Ic set . +.It Ic visual +.Pq Ic v +Takes a message list and invokes the display editor on each message. +.It Ic write +.Pq Ic w +Similar to +.Ic save , +except that +.Ic only +the message body +.Pq Ar without +the header) is saved. +Extremely useful for such tasks as sending and receiving source +program text over the message system. +.It Ic xit +.Pq Ic x +A synonym for +.Ic exit . +.It Ic z +.Nm Mail +presents message headers in windowfuls as described under the +.Ic headers +command. +You can move +.Nm mail Ns 's +attention forward to the next window with the +.Ic \&z +command. +Also, you can move to the previous window by using +.Ic \&z\&\- . +.El +.Ss Tilde/Escapes +.Pp +Here is a summary of the tilde escapes, +which are used when composing messages to perform +special functions. +Tilde escapes are only recognized at the beginning +of lines. +The name +.Dq Em tilde\ escape +is somewhat of a misnomer since the actual escape character can be set +by the option +.Ic escape . +.Bl -tag -width Ds +.It Ic \&~! Ns Ar command +Execute the indicated shell command, then return to the message. +.It Ic \&~b Ns Ar name ... +Add the given names to the list of carbon copy recipients but do not make +the names visible in the Cc: line ("blind" carbon copy). +.It Ic \&~c Ns Ar name ... +Add the given names to the list of carbon copy recipients. +.It Ic \&~d +Read the file +.Dq Pa dead.letter +from your home directory into the message. +.It Ic \&~e +Invoke the text editor on the message collected so far. +After the +editing session is finished, you may continue appending text to the +message. +.It Ic \&~f Ns Ar messages +Read the named messages into the message being sent. +If no messages are specified, read in the current message. +Message headers currently being ignored (by the +.Ic ignore +or +.Ic retain +command) are not included. +.It Ic \&~F Ns Ar messages +Identical to +.Ic \&~f , +except all message headers are included. +.It Ic \&~h +Edit the message header fields by typing each one in turn and allowing +the user to append text to the end or modify the field by using the +current terminal erase and kill characters. +.It Ic \&~m Ns Ar messages +Read the named messages into the message being sent, indented by a +tab or by the value of +.Ar indentprefix . +If no messages are specified, +read the current message. +Message headers currently being ignored (by the +.Ic ignore +or +.Ic retain +command) are not included. +.It Ic \&~M Ns Ar messages +Identical to +.Ic \&~m , +except all message headers are included. +.It Ic \&~p +Print out the message collected so far, prefaced by the message header +fields. +.It Ic \&~q +Abort the message being sent, copying the message to +.Dq Pa dead.letter +in your home directory if +.Ic save +is set. +.It Ic \&~r Ns Ar filename +Read the named file into the message. +.It Ic \&~s Ns Ar string +Cause the named string to become the current subject field. +.It Ic \&~\&t Ns Ar name ... +Add the given names to the direct recipient list. +.It Ic \&~\&v +Invoke an alternate editor (defined by the +.Ev VISUAL +option) on the +message collected so far. +Usually, the alternate editor will be a +screen editor. +After you quit the editor, you may resume appending +text to the end of your message. +.It Ic \&~w Ns Ar filename +Write the message onto the named file. +.It Ic \&~\&| Ns Ar command +Pipe the message through the command as a filter. +If the command gives +no output or terminates abnormally, retain the original text of the +message. +The command +.Xr fmt 1 +is often used as +.Ic command +to rejustify the message. +.It Ic \&~: Ns Ar mail-command +Execute the given mail command. +Not all commands, however, are allowed. +.It Ic \&~~ Ns Ar string +Insert the string of text in the message prefaced by a single ~. +If +you have changed the escape character, then you should double +that character in order to send it. +.El +.Ss Mail Options +Options are controlled via +.Ic set +and +.Ic unset +commands. +Options may be either binary, in which case it is only +significant to see whether they are set or not; or string, in which +case the actual value is of interest. +The binary options include the following: +.Bl -tag -width append +.It Ar append +Causes messages saved in +.Ar mbox +to be appended to the end rather than prepended. +This should always be set (perhaps in +.Pa /usr/share/misc/Mail.rc ) . +.It Ar ask +Causes +.Nm mail +to prompt you for the subject of each message you send. +If +you respond with simply a newline, no subject field will be sent. +.It Ar askcc +Causes you to be prompted for additional carbon copy recipients at the +end of each message. +Responding with a newline indicates your +satisfaction with the current list. +.It Ar autoprint +Causes the +.Ic delete +command to behave like +.Ic dp +\- thus, after deleting a message, the next one will be typed +automatically. +.It Ar debug +Setting the binary option +.Ar debug +is the same as specifying +.Fl d +on the command line and causes +.Nm mail +to output all sorts of information useful for debugging +.Nm mail . +.It Ar dot +The binary option +.Ar dot +causes +.Nm mail +to interpret a period alone on a line as the terminator +of a message you are sending. +.It Ar hold +This option is used to hold messages in the system mailbox +by default. +.It Ar ignore +Causes interrupt signals from your terminal to be ignored and echoed as +@'s. +.It Ar ignoreeof +An option related to +.Ar dot +is +.Ar ignoreeof +which makes +.Nm mail +refuse to accept a control-d as the end of a message. +.Ar Ignoreeof +also applies to +.Nm mail +command mode. +.It Ar metoo +Usually, when a group is expanded that contains the sender, the sender +is removed from the expansion. +Setting this option causes the sender +to be included in the group. +.It Ar noheader +Setting the option +.Ar noheader +is the same as giving the +.Fl N +flag on the command line. +.It Ar nosave +Normally, when you abort a message with two +.Tn RUBOUT +(erase or delete) +.Nm mail +copies the partial letter to the file +.Dq Pa dead.letter +in your home directory. +Setting the binary option +.Ar nosave +prevents this. +.It Ar Replyall +Reverses the sense of +.Ic reply +and +.Ic Reply +commands. +.It Ar quiet +Suppresses the printing of the version when first invoked. +.It Ar searchheaders +If this option is set, then a message-list specifier in the form ``/x:y'' +will expand to all messages containing the substring ``y'' in the header +field ``x''. The string search is case insensitive. +.It Ar verbose +Setting the option +.Ar verbose +is the same as using the +.Fl v +flag on the command line. +When mail runs in verbose mode, +the actual delivery of messages is displayed on the user's +terminal. +.El +.Ss Option String Values +.Bl -tag -width Va +.It Ev EDITOR +Pathname of the text editor to use in the +.Ic edit +command and +.Ic \&~e +escape. +If not defined, then a default editor is used. +.It Ev LISTER +Pathname of the directory lister to use in the +.Ic folders +command. +Default is +.Pa /bin/ls . +.It Ev PAGER +Pathname of the program to use in the +.Ic more +command or when +.Ic crt +variable is set. +The default paginator +.Xr more 1 +is used if this option is not defined. +.It Ev SHELL +Pathname of the shell to use in the +.Ic \&! +command and the +.Ic \&~! +escape. +A default shell is used if this option is +not defined. +.It Ev VISUAL +Pathname of the text editor to use in the +.Ic visual +command and +.Ic \&~v +escape. +.It Va crt +The valued option +.Va crt +is used as a threshold to determine how long a message must +be before +.Ev PAGER +is used to read it. +If +.Va crt +is set without a value, +then the height of the terminal screen stored in the system +is used to compute the threshold (see +.Xr stty 1 ) . +.It Ar escape +If defined, the first character of this option gives the character to +use in the place of ~ to denote escapes. +.It Ar folder +The name of the directory to use for storing folders of +messages. +If this name begins with a `/', +.Nm mail +considers it to be an absolute pathname; otherwise, the +folder directory is found relative to your home directory. +.It Ev MBOX +The name of the +.Ar mbox +file. +It can be the name of a folder. +The default is +.Dq Li mbox +in the user's home directory. +.It Ar record +If defined, gives the pathname of the file used to record all outgoing +mail. +If not defined, then outgoing mail is not so saved. +.It Ar indentprefix +String used by the ``~m'' tilde escape for indenting messages, in place of +the normal tab character (^I). +Be sure to quote the value if it contains +spaces or tabs. +.It Ar toplines +If defined, gives the number of lines of a message to be printed out +with the +.Ic top +command; normally, the first five lines are printed. +.El +.Sh ENVIRONMENT +.Nm Mail +utilizes the +.Ev HOME +and +.Ev USER +environment variables. +.Sh FILES +.Bl -tag -width /usr/share/misc/Mail.help* -compact +.It Pa /var/spool/mail/* +Post office. +.It ~/mbox +User's old mail. +.It ~/.mailrc +File giving initial mail commands. +.It Pa /tmp/R* +Temporary files. +.It Pa /usr/share/misc/Mail.help* +Help files. +.It Pa /usr/share/misc/Mail.rc +System initialization file. +.El +.Sh SEE ALSO +.Xr fmt 1 , +.Xr newaliases 1 , +.Xr vacation 1 , +.Xr aliases 5 , +.Xr mailaddr 7 , +.Xr sendmail 8 +and +.Rs +.%T "The Mail Reference Manual" . +.Re +.Sh HISTORY +A +.Nm mail +command +appeared in +.At v6 . +This man page is derived from +.%T "The Mail Reference Manual" +originally written by Kurt Shoens. +.Sh BUGS +There are some flags that are not documented here. +Most are +not useful to the general user. +.Pp +Usually, +.Nm mail +is just a link to +.Nm Mail , +which can be confusing. diff --git a/usr.bin/mail/main.c b/usr.bin/mail/main.c new file mode 100644 index 0000000..1e1579b --- /dev/null +++ b/usr.bin/mail/main.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include <fcntl.h> +#include "extern.h" + +/* + * Mail -- a mail program + * + * Startup -- interface with user. + */ + +jmp_buf hdrjmp; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int i; + struct name *to, *cc, *bcc, *smopts; + char *subject; + char *ef; + char nosrc = 0; + void hdrstop(); + sig_t prevint; + void sigchild(); + + /* + * Set up a reasonable environment. + * Figure out whether we are being run interactively, + * start the SIGCHLD catcher, and so forth. + */ + (void) signal(SIGCHLD, sigchild); + if (isatty(0)) + assign("interactive", ""); + image = -1; + /* + * Now, determine how we are being used. + * We successively pick off - flags. + * If there is anything left, it is the base of the list + * of users to mail to. Argp will be set to point to the + * first of these users. + */ + ef = NOSTR; + to = NIL; + cc = NIL; + bcc = NIL; + smopts = NIL; + subject = NOSTR; + while ((i = getopt(argc, argv, "INT:b:c:dfins:u:v")) != EOF) { + switch (i) { + case 'T': + /* + * Next argument is temp file to write which + * articles have been read/deleted for netnews. + */ + Tflag = optarg; + if ((i = creat(Tflag, 0600)) < 0) { + perror(Tflag); + exit(1); + } + close(i); + break; + case 'u': + /* + * Next argument is person to pretend to be. + */ + myname = optarg; + break; + case 'i': + /* + * User wants to ignore interrupts. + * Set the variable "ignore" + */ + assign("ignore", ""); + break; + case 'd': + debug++; + break; + case 's': + /* + * Give a subject field for sending from + * non terminal + */ + subject = optarg; + break; + case 'f': + /* + * User is specifying file to "edit" with Mail, + * as opposed to reading system mailbox. + * If no argument is given after -f, we read his + * mbox file. + * + * getopt() can't handle optional arguments, so here + * is an ugly hack to get around it. + */ + if ((argv[optind]) && (argv[optind][0] != '-')) + ef = argv[optind++]; + else + ef = "&"; + break; + case 'n': + /* + * User doesn't want to source /usr/lib/Mail.rc + */ + nosrc++; + break; + case 'N': + /* + * Avoid initial header printing. + */ + assign("noheader", ""); + break; + case 'v': + /* + * Send mailer verbose flag + */ + assign("verbose", ""); + break; + case 'I': + /* + * We're interactive + */ + assign("interactive", ""); + break; + case 'c': + /* + * Get Carbon Copy Recipient list + */ + cc = cat(cc, nalloc(optarg, GCC)); + break; + case 'b': + /* + * Get Blind Carbon Copy Recipient list + */ + bcc = cat(bcc, nalloc(optarg, GBCC)); + break; + case '?': + fputs("\ +Usage: mail [-iInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ + [- sendmail-options ...]\n\ + mail [-iInNv] -f [name]\n\ + mail [-iInNv] [-u user]\n", + stderr); + exit(1); + } + } + for (i = optind; (argv[i]) && (*argv[i] != '-'); i++) + to = cat(to, nalloc(argv[i], GTO)); + for (; argv[i]; i++) + smopts = cat(smopts, nalloc(argv[i], 0)); + /* + * Check for inconsistent arguments. + */ + if (to == NIL && (subject != NOSTR || cc != NIL || bcc != NIL)) { + fputs("You must specify direct recipients with -s, -c, or -b.\n", stderr); + exit(1); + } + if (ef != NOSTR && to != NIL) { + fprintf(stderr, "Cannot give -f and people to send to.\n"); + exit(1); + } + tinit(); + setscreensize(); + input = stdin; + rcvmode = !to; + spreserve(); + if (!nosrc) + load(_PATH_MASTER_RC); + /* + * Expand returns a savestr, but load only uses the file name + * for fopen, so it's safe to do this. + */ + load(expand("~/.mailrc")); + if (!rcvmode) { + mail(to, cc, bcc, smopts, subject); + /* + * why wait? + */ + exit(senderr); + } + /* + * Ok, we are reading mail. + * Decide whether we are editing a mailbox or reading + * the system mailbox, and open up the right stuff. + */ + if (ef == NOSTR) + ef = "%"; + if (setfile(ef) < 0) + exit(1); /* error already reported */ + if (setjmp(hdrjmp) == 0) { + extern char *version; + + if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN) + signal(SIGINT, hdrstop); + if (value("quiet") == NOSTR) + printf("Mail version %s. Type ? for help.\n", + version); + announce(); + fflush(stdout); + signal(SIGINT, prevint); + } + commands(); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + quit(); + exit(0); +} + +/* + * Interrupt printing of the headers. + */ +void +hdrstop(signo) + int signo; +{ + + fflush(stdout); + fprintf(stderr, "\nInterrupt\n"); + longjmp(hdrjmp, 1); +} + +/* + * Compute what the screen size for printing headers should be. + * We use the following algorithm for the height: + * If baud rate < 1200, use 9 + * If baud rate = 1200, use 14 + * If baud rate > 1200, use 24 or ws_row + * Width is either 80 or ws_col; + */ +void +setscreensize() +{ + struct sgttyb tbuf; + struct winsize ws; + + if (ioctl(1, TIOCGWINSZ, (char *) &ws) < 0) + ws.ws_col = ws.ws_row = 0; + if (ioctl(1, TIOCGETP, &tbuf) < 0) + tbuf.sg_ospeed = B9600; + if (tbuf.sg_ospeed < B1200) + screenheight = 9; + else if (tbuf.sg_ospeed == B1200) + screenheight = 14; + else if (ws.ws_row != 0) + screenheight = ws.ws_row; + else + screenheight = 24; + if ((realscreenheight = ws.ws_row) == 0) + realscreenheight = 24; + if ((screenwidth = ws.ws_col) == 0) + screenwidth = 80; +} diff --git a/usr.bin/mail/misc/mail.help b/usr.bin/mail/misc/mail.help new file mode 100644 index 0000000..d5858c5 --- /dev/null +++ b/usr.bin/mail/misc/mail.help @@ -0,0 +1,23 @@ + Mail Commands +t <message list> type messages +n goto and type next message +e <message list> edit messages +f <message list> give head lines of messages +d <message list> delete messages +s <message list> file append messages to file +u <message list> undelete messages +R <message list> reply to message senders +r <message list> reply to message senders and all recipients +pre <message list> make messages go back to /usr/spool/mail +m <user list> mail to specific users +q quit, saving unresolved messages in mbox +x quit, do not remove system mailbox +h print out active message headers +! shell escape +cd [directory] chdir to directory or home if none given + +A <message list> consists of integers, ranges of same, or user names separated +by spaces. If omitted, Mail uses the last message typed. + +A <user list> consists of user names or aliases separated by spaces. +Aliases are defined in .mailrc in your home directory. diff --git a/usr.bin/mail/misc/mail.rc b/usr.bin/mail/misc/mail.rc new file mode 100644 index 0000000..90e937a --- /dev/null +++ b/usr.bin/mail/misc/mail.rc @@ -0,0 +1,2 @@ +set append dot save +ignore Received Message-Id Resent-Message-Id Status Mail-From Return-Path Via diff --git a/usr.bin/mail/misc/mail.tildehelp b/usr.bin/mail/misc/mail.tildehelp new file mode 100644 index 0000000..0b1ab13 --- /dev/null +++ b/usr.bin/mail/misc/mail.tildehelp @@ -0,0 +1,22 @@ +----------------------------------------------------------- +The following ~ escapes are defined: +~~ Quote a single tilde +~b users Add users to "blind" cc list +~c users Add users to cc list +~d Read in dead.letter +~e Edit the message buffer +~f messages Read in messages +~F messages Same as ~f, but keep all header lines +~h Prompt for to list, subject and cc list +~r file Read a file into the message buffer +~p Print the message buffer +~m messages Read in messages, right shifted by a tab +~M messages Same as ~m, but keep all header lines +~s subject Set subject +~t users Add users to to list +~v Invoke display editor on message +~w file Write message onto file. +~? Print this message +~!command Invoke the shell +~|command Pipe the message through the command +----------------------------------------------------------- diff --git a/usr.bin/mail/names.c b/usr.bin/mail/names.c new file mode 100644 index 0000000..b2f8cfe --- /dev/null +++ b/usr.bin/mail/names.c @@ -0,0 +1,694 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)names.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * Handle name lists. + */ + +#include "rcv.h" +#include <fcntl.h> +#include "extern.h" + +/* + * Allocate a single element of a name list, + * initialize its name field to the passed + * name and return it. + */ +struct name * +nalloc(str, ntype) + char str[]; + int ntype; +{ + register struct name *np; + + np = (struct name *) salloc(sizeof *np); + np->n_flink = NIL; + np->n_blink = NIL; + np->n_type = ntype; + np->n_name = savestr(str); + return(np); +} + +/* + * Find the tail of a list and return it. + */ +struct name * +tailof(name) + struct name *name; +{ + register struct name *np; + + np = name; + if (np == NIL) + return(NIL); + while (np->n_flink != NIL) + np = np->n_flink; + return(np); +} + +/* + * Extract a list of names from a line, + * and make a list of names from it. + * Return the list or NIL if none found. + */ +struct name * +extract(line, ntype) + char line[]; + int ntype; +{ + register char *cp; + register struct name *top, *np, *t; + char nbuf[BUFSIZ]; + + if (line == NOSTR || *line == '\0') + return NIL; + top = NIL; + np = NIL; + cp = line; + while ((cp = yankword(cp, nbuf)) != NOSTR) { + t = nalloc(nbuf, ntype); + if (top == NIL) + top = t; + else + np->n_flink = t; + t->n_blink = np; + np = t; + } + return top; +} + +/* + * Turn a list of names into a string of the same names. + */ +char * +detract(np, ntype) + register struct name *np; + int ntype; +{ + register int s; + register char *cp, *top; + register struct name *p; + register int comma; + + comma = ntype & GCOMMA; + if (np == NIL) + return(NOSTR); + ntype &= ~GCOMMA; + s = 0; + if (debug && comma) + fprintf(stderr, "detract asked to insert commas\n"); + for (p = np; p != NIL; p = p->n_flink) { + if (ntype && (p->n_type & GMASK) != ntype) + continue; + s += strlen(p->n_name) + 1; + if (comma) + s++; + } + if (s == 0) + return(NOSTR); + s += 2; + top = salloc(s); + cp = top; + for (p = np; p != NIL; p = p->n_flink) { + if (ntype && (p->n_type & GMASK) != ntype) + continue; + cp = copy(p->n_name, cp); + if (comma && p->n_flink != NIL) + *cp++ = ','; + *cp++ = ' '; + } + *--cp = 0; + if (comma && *--cp == ',') + *cp = 0; + return(top); +} + +/* + * Grab a single word (liberal word) + * Throw away things between ()'s, and take anything between <>. + */ +char * +yankword(ap, wbuf) + char *ap, wbuf[]; +{ + register char *cp, *cp2; + + cp = ap; + for (;;) { + if (*cp == '\0') + return NOSTR; + if (*cp == '(') { + register int nesting = 0; + + while (*cp != '\0') { + switch (*cp++) { + case '(': + nesting++; + break; + case ')': + --nesting; + break; + } + if (nesting <= 0) + break; + } + } else if (*cp == ' ' || *cp == '\t' || *cp == ',') + cp++; + else + break; + } + if (*cp == '<') + for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';) + ; + else + for (cp2 = wbuf; *cp && !index(" \t,(", *cp); *cp2++ = *cp++) + ; + *cp2 = '\0'; + return cp; +} + +/* + * For each recipient in the passed name list with a / + * in the name, append the message to the end of the named file + * and remove him from the recipient list. + * + * Recipients whose name begins with | are piped through the given + * program and removed. + */ +struct name * +outof(names, fo, hp) + struct name *names; + FILE *fo; + struct header *hp; +{ + register int c; + register struct name *np, *top; + time_t now, time(); + char *date, *fname, *ctime(); + FILE *fout, *fin; + int ispipe; + extern char tempEdit[]; + + top = names; + np = names; + (void) time(&now); + date = ctime(&now); + while (np != NIL) { + if (!isfileaddr(np->n_name) && np->n_name[0] != '|') { + np = np->n_flink; + continue; + } + ispipe = np->n_name[0] == '|'; + if (ispipe) + fname = np->n_name+1; + else + fname = expand(np->n_name); + + /* + * See if we have copied the complete message out yet. + * If not, do so. + */ + + if (image < 0) { + if ((fout = Fopen(tempEdit, "a")) == NULL) { + perror(tempEdit); + senderr++; + goto cant; + } + image = open(tempEdit, 2); + (void) unlink(tempEdit); + if (image < 0) { + perror(tempEdit); + senderr++; + (void) Fclose(fout); + goto cant; + } + (void) fcntl(image, F_SETFD, 1); + fprintf(fout, "From %s %s", myname, date); + puthead(hp, fout, GTO|GSUBJECT|GCC|GNL); + while ((c = getc(fo)) != EOF) + (void) putc(c, fout); + rewind(fo); + (void) putc('\n', fout); + (void) fflush(fout); + if (ferror(fout)) + perror(tempEdit); + (void) Fclose(fout); + } + + /* + * Now either copy "image" to the desired file + * or give it as the standard input to the desired + * program as appropriate. + */ + + if (ispipe) { + int pid; + char *shell; + + /* + * XXX + * We can't really reuse the same image file, + * because multiple piped recipients will + * share the same lseek location and trample + * on one another. + */ + if ((shell = value("SHELL")) == NOSTR) + shell = _PATH_CSHELL; + pid = start_command(shell, sigmask(SIGHUP)| + sigmask(SIGINT)|sigmask(SIGQUIT), + image, -1, "-c", fname, NOSTR); + if (pid < 0) { + senderr++; + goto cant; + } + free_child(pid); + } else { + int f; + if ((fout = Fopen(fname, "a")) == NULL) { + perror(fname); + senderr++; + goto cant; + } + if ((f = dup(image)) < 0) { + perror("dup"); + fin = NULL; + } else + fin = Fdopen(f, "r"); + if (fin == NULL) { + fprintf(stderr, "Can't reopen image\n"); + (void) Fclose(fout); + senderr++; + goto cant; + } + rewind(fin); + while ((c = getc(fin)) != EOF) + (void) putc(c, fout); + if (ferror(fout)) + senderr++, perror(fname); + (void) Fclose(fout); + (void) Fclose(fin); + } +cant: + /* + * In days of old we removed the entry from the + * the list; now for sake of header expansion + * we leave it in and mark it as deleted. + */ + np->n_type |= GDEL; + np = np->n_flink; + } + if (image >= 0) { + (void) close(image); + image = -1; + } + return(top); +} + +/* + * Determine if the passed address is a local "send to file" address. + * If any of the network metacharacters precedes any slashes, it can't + * be a filename. We cheat with .'s to allow path names like ./... + */ +int +isfileaddr(name) + char *name; +{ + register char *cp; + + if (*name == '+') + return 1; + for (cp = name; *cp; cp++) { + if (*cp == '!' || *cp == '%' || *cp == '@') + return 0; + if (*cp == '/') + return 1; + } + return 0; +} + +/* + * Map all of the aliased users in the invoker's mailrc + * file and insert them into the list. + * Changed after all these months of service to recursively + * expand names (2/14/80). + */ + +struct name * +usermap(names) + struct name *names; +{ + register struct name *new, *np, *cp; + struct grouphead *gh; + register int metoo; + + new = NIL; + np = names; + metoo = (value("metoo") != NOSTR); + while (np != NIL) { + if (np->n_name[0] == '\\') { + cp = np->n_flink; + new = put(new, np); + np = cp; + continue; + } + gh = findgroup(np->n_name); + cp = np->n_flink; + if (gh != NOGRP) + new = gexpand(new, gh, metoo, np->n_type); + else + new = put(new, np); + np = cp; + } + return(new); +} + +/* + * Recursively expand a group name. We limit the expansion to some + * fixed level to keep things from going haywire. + * Direct recursion is not expanded for convenience. + */ + +struct name * +gexpand(nlist, gh, metoo, ntype) + struct name *nlist; + struct grouphead *gh; + int metoo, ntype; +{ + struct group *gp; + struct grouphead *ngh; + struct name *np; + static int depth; + char *cp; + + if (depth > MAXEXP) { + printf("Expanding alias to depth larger than %d\n", MAXEXP); + return(nlist); + } + depth++; + for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) { + cp = gp->ge_name; + if (*cp == '\\') + goto quote; + if (strcmp(cp, gh->g_name) == 0) + goto quote; + if ((ngh = findgroup(cp)) != NOGRP) { + nlist = gexpand(nlist, ngh, metoo, ntype); + continue; + } +quote: + np = nalloc(cp, ntype); + /* + * At this point should allow to expand + * to self if only person in group + */ + if (gp == gh->g_list && gp->ge_link == NOGE) + goto skip; + if (!metoo && strcmp(cp, myname) == 0) + np->n_type |= GDEL; +skip: + nlist = put(nlist, np); + } + depth--; + return(nlist); +} + +/* + * Concatenate the two passed name lists, return the result. + */ +struct name * +cat(n1, n2) + struct name *n1, *n2; +{ + register struct name *tail; + + if (n1 == NIL) + return(n2); + if (n2 == NIL) + return(n1); + tail = tailof(n1); + tail->n_flink = n2; + n2->n_blink = tail; + return(n1); +} + +/* + * Unpack the name list onto a vector of strings. + * Return an error if the name list won't fit. + */ +char ** +unpack(np) + struct name *np; +{ + register char **ap, **top; + register struct name *n; + int t, extra, metoo, verbose; + + n = np; + if ((t = count(n)) == 0) + panic("No names to unpack"); + /* + * Compute the number of extra arguments we will need. + * We need at least two extra -- one for "mail" and one for + * the terminating 0 pointer. Additional spots may be needed + * to pass along -f to the host mailer. + */ + extra = 2; + extra++; + metoo = value("metoo") != NOSTR; + if (metoo) + extra++; + verbose = value("verbose") != NOSTR; + if (verbose) + extra++; + top = (char **) salloc((t + extra) * sizeof *top); + ap = top; + *ap++ = "send-mail"; + *ap++ = "-i"; + if (metoo) + *ap++ = "-m"; + if (verbose) + *ap++ = "-v"; + for (; n != NIL; n = n->n_flink) + if ((n->n_type & GDEL) == 0) + *ap++ = n->n_name; + *ap = NOSTR; + return(top); +} + +/* + * Remove all of the duplicates from the passed name list by + * insertion sorting them, then checking for dups. + * Return the head of the new list. + */ +struct name * +elide(names) + struct name *names; +{ + register struct name *np, *t, *new; + struct name *x; + + if (names == NIL) + return(NIL); + new = names; + np = names; + np = np->n_flink; + if (np != NIL) + np->n_blink = NIL; + new->n_flink = NIL; + while (np != NIL) { + t = new; + while (strcasecmp(t->n_name, np->n_name) < 0) { + if (t->n_flink == NIL) + break; + t = t->n_flink; + } + + /* + * If we ran out of t's, put the new entry after + * the current value of t. + */ + + if (strcasecmp(t->n_name, np->n_name) < 0) { + t->n_flink = np; + np->n_blink = t; + t = np; + np = np->n_flink; + t->n_flink = NIL; + continue; + } + + /* + * Otherwise, put the new entry in front of the + * current t. If at the front of the list, + * the new guy becomes the new head of the list. + */ + + if (t == new) { + t = np; + np = np->n_flink; + t->n_flink = new; + new->n_blink = t; + t->n_blink = NIL; + new = t; + continue; + } + + /* + * The normal case -- we are inserting into the + * middle of the list. + */ + + x = np; + np = np->n_flink; + x->n_flink = t; + x->n_blink = t->n_blink; + t->n_blink->n_flink = x; + t->n_blink = x; + } + + /* + * Now the list headed up by new is sorted. + * Go through it and remove duplicates. + */ + + np = new; + while (np != NIL) { + t = np; + while (t->n_flink != NIL && + strcasecmp(np->n_name, t->n_flink->n_name) == 0) + t = t->n_flink; + if (t == np || t == NIL) { + np = np->n_flink; + continue; + } + + /* + * Now t points to the last entry with the same name + * as np. Make np point beyond t. + */ + + np->n_flink = t->n_flink; + if (t->n_flink != NIL) + t->n_flink->n_blink = np; + np = np->n_flink; + } + return(new); +} + +/* + * Put another node onto a list of names and return + * the list. + */ +struct name * +put(list, node) + struct name *list, *node; +{ + node->n_flink = list; + node->n_blink = NIL; + if (list != NIL) + list->n_blink = node; + return(node); +} + +/* + * Determine the number of undeleted elements in + * a name list and return it. + */ +int +count(np) + register struct name *np; +{ + register int c; + + for (c = 0; np != NIL; np = np->n_flink) + if ((np->n_type & GDEL) == 0) + c++; + return c; +} + +/* + * Delete the given name from a namelist. + */ +struct name * +delname(np, name) + register struct name *np; + char name[]; +{ + register struct name *p; + + for (p = np; p != NIL; p = p->n_flink) + if (strcasecmp(p->n_name, name) == 0) { + if (p->n_blink == NIL) { + if (p->n_flink != NIL) + p->n_flink->n_blink = NIL; + np = p->n_flink; + continue; + } + if (p->n_flink == NIL) { + if (p->n_blink != NIL) + p->n_blink->n_flink = NIL; + continue; + } + p->n_blink->n_flink = p->n_flink; + p->n_flink->n_blink = p->n_blink; + } + return np; +} + +/* + * Pretty print a name list + * Uncomment it if you need it. + */ + +/* +void +prettyprint(name) + struct name *name; +{ + register struct name *np; + + np = name; + while (np != NIL) { + fprintf(stderr, "%s(%d) ", np->n_name, np->n_type); + np = np->n_flink; + } + fprintf(stderr, "\n"); +} +*/ diff --git a/usr.bin/mail/pathnames.h b/usr.bin/mail/pathnames.h new file mode 100644 index 0000000..13a7672 --- /dev/null +++ b/usr.bin/mail/pathnames.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 + */ + +#include <paths.h> + +#define _PATH_EX "/usr/bin/ex" +#define _PATH_HELP "/usr/share/misc/mail.help" +#define _PATH_TILDE "/usr/share/misc/mail.tildehelp" +#define _PATH_MASTER_RC "/etc/mail.rc" +#define _PATH_MORE "/usr/bin/more" diff --git a/usr.bin/mail/popen.c b/usr.bin/mail/popen.c new file mode 100644 index 0000000..467d24a --- /dev/null +++ b/usr.bin/mail/popen.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include <sys/wait.h> +#include <fcntl.h> +#include "extern.h" + +#define READ 0 +#define WRITE 1 + +struct fp { + FILE *fp; + int pipe; + int pid; + struct fp *link; +}; +static struct fp *fp_head; + +struct child { + int pid; + char done; + char free; + union wait status; + struct child *link; +}; +static struct child *child; +static struct child *findchild __P((int)); +static void delchild __P((struct child *)); + +FILE * +Fopen(file, mode) + char *file, *mode; +{ + FILE *fp; + + if ((fp = fopen(file, mode)) != NULL) { + register_file(fp, 0, 0); + (void) fcntl(fileno(fp), F_SETFD, 1); + } + return fp; +} + +FILE * +Fdopen(fd, mode) + int fd; + char *mode; +{ + FILE *fp; + + if ((fp = fdopen(fd, mode)) != NULL) { + register_file(fp, 0, 0); + (void) fcntl(fileno(fp), F_SETFD, 1); + } + return fp; +} + +int +Fclose(fp) + FILE *fp; +{ + unregister_file(fp); + return fclose(fp); +} + +FILE * +Popen(cmd, mode) + char *cmd; + char *mode; +{ + int p[2]; + int myside, hisside, fd0, fd1; + int pid; + FILE *fp; + + if (pipe(p) < 0) + return NULL; + (void) fcntl(p[READ], F_SETFD, 1); + (void) fcntl(p[WRITE], F_SETFD, 1); + if (*mode == 'r') { + myside = p[READ]; + fd0 = -1; + hisside = fd1 = p[WRITE]; + } else { + myside = p[WRITE]; + hisside = fd0 = p[READ]; + fd1 = -1; + } + if ((pid = start_command(cmd, 0, fd0, fd1, NOSTR, NOSTR, NOSTR)) < 0) { + close(p[READ]); + close(p[WRITE]); + return NULL; + } + (void) close(hisside); + if ((fp = fdopen(myside, mode)) != NULL) + register_file(fp, 1, pid); + return fp; +} + +int +Pclose(ptr) + FILE *ptr; +{ + int i; + int omask; + + i = file_pid(ptr); + unregister_file(ptr); + (void) fclose(ptr); + omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP)); + i = wait_child(i); + sigsetmask(omask); + return i; +} + +void +close_all_files() +{ + + while (fp_head) + if (fp_head->pipe) + (void) Pclose(fp_head->fp); + else + (void) Fclose(fp_head->fp); +} + +void +register_file(fp, pipe, pid) + FILE *fp; + int pipe, pid; +{ + struct fp *fpp; + + if ((fpp = (struct fp *) malloc(sizeof *fpp)) == NULL) + panic("Out of memory"); + fpp->fp = fp; + fpp->pipe = pipe; + fpp->pid = pid; + fpp->link = fp_head; + fp_head = fpp; +} + +void +unregister_file(fp) + FILE *fp; +{ + struct fp **pp, *p; + + for (pp = &fp_head; p = *pp; pp = &p->link) + if (p->fp == fp) { + *pp = p->link; + free((char *) p); + return; + } + panic("Invalid file pointer"); +} + +file_pid(fp) + FILE *fp; +{ + struct fp *p; + + for (p = fp_head; p; p = p->link) + if (p->fp == fp) + return (p->pid); + panic("Invalid file pointer"); + /*NOTREACHED*/ +} + +/* + * Run a command without a shell, with optional arguments and splicing + * of stdin and stdout. The command name can be a sequence of words. + * Signals must be handled by the caller. + * "Mask" contains the signals to ignore in the new process. + * SIGINT is enabled unless it's in the mask. + */ +/*VARARGS4*/ +int +run_command(cmd, mask, infd, outfd, a0, a1, a2) + char *cmd; + int mask, infd, outfd; + char *a0, *a1, *a2; +{ + int pid; + + if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0) + return -1; + return wait_command(pid); +} + +/*VARARGS4*/ +int +start_command(cmd, mask, infd, outfd, a0, a1, a2) + char *cmd; + int mask, infd, outfd; + char *a0, *a1, *a2; +{ + int pid; + + if ((pid = vfork()) < 0) { + perror("fork"); + return -1; + } + if (pid == 0) { + char *argv[100]; + int i = getrawlist(cmd, argv, sizeof argv / sizeof *argv); + + if ((argv[i++] = a0) != NOSTR && + (argv[i++] = a1) != NOSTR && + (argv[i++] = a2) != NOSTR) + argv[i] = NOSTR; + prepare_child(mask, infd, outfd); + execvp(argv[0], argv); + perror(argv[0]); + _exit(1); + } + return pid; +} + +void +prepare_child(mask, infd, outfd) + int mask, infd, outfd; +{ + int i; + + /* + * All file descriptors other than 0, 1, and 2 are supposed to be + * close-on-exec. + */ + if (infd >= 0) + dup2(infd, 0); + if (outfd >= 0) + dup2(outfd, 1); + for (i = 1; i <= NSIG; i++) + if (mask & sigmask(i)) + (void) signal(i, SIG_IGN); + if ((mask & sigmask(SIGINT)) == 0) + (void) signal(SIGINT, SIG_DFL); + (void) sigsetmask(0); +} + +int +wait_command(pid) + int pid; +{ + + if (wait_child(pid) < 0) { + printf("Fatal error in process.\n"); + return -1; + } + return 0; +} + +static struct child * +findchild(pid) + int pid; +{ + register struct child **cpp; + + for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid; + cpp = &(*cpp)->link) + ; + if (*cpp == NULL) { + *cpp = (struct child *) malloc(sizeof (struct child)); + (*cpp)->pid = pid; + (*cpp)->done = (*cpp)->free = 0; + (*cpp)->link = NULL; + } + return *cpp; +} + +static void +delchild(cp) + register struct child *cp; +{ + register struct child **cpp; + + for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link) + ; + *cpp = cp->link; + free((char *) cp); +} + +void +sigchild(signo) + int signo; +{ + int pid; + union wait status; + register struct child *cp; + + while ((pid = + wait3((int *)&status, WNOHANG, (struct rusage *)0)) > 0) { + cp = findchild(pid); + if (cp->free) + delchild(cp); + else { + cp->done = 1; + cp->status = status; + } + } +} + +union wait wait_status; + +/* + * Wait for a specific child to die. + */ +int +wait_child(pid) + int pid; +{ + int mask = sigblock(sigmask(SIGCHLD)); + register struct child *cp = findchild(pid); + + while (!cp->done) + sigpause(mask); + wait_status = cp->status; + delchild(cp); + sigsetmask(mask); + return wait_status.w_status ? -1 : 0; +} + +/* + * Mark a child as don't care. + */ +void +free_child(pid) + int pid; +{ + int mask = sigblock(sigmask(SIGCHLD)); + register struct child *cp = findchild(pid); + + if (cp->done) + delchild(cp); + else + cp->free = 1; + sigsetmask(mask); +} diff --git a/usr.bin/mail/quit.c b/usr.bin/mail/quit.c new file mode 100644 index 0000000..05e708f --- /dev/null +++ b/usr.bin/mail/quit.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)quit.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include <fcntl.h> +#include "extern.h" + +/* + * Rcv -- receive mail rationally. + * + * Termination processing. + */ + +/* + * The "quit" command. + */ +int +quitcmd() +{ + /* + * If we are sourcing, then return 1 so execute() can handle it. + * Otherwise, return -1 to abort command loop. + */ + if (sourcing) + return 1; + return -1; +} + +/* + * Save all of the undetermined messages at the top of "mbox" + * Save all untouched messages back in the system mailbox. + * Remove the system mailbox, if none saved there. + */ +void +quit() +{ + int mcount, p, modify, autohold, anystat, holdbit, nohold; + FILE *ibuf, *obuf, *fbuf, *rbuf, *readstat, *abuf; + register struct message *mp; + register int c; + extern char tempQuit[], tempResid[]; + struct stat minfo; + char *mbox; + + /* + * If we are read only, we can't do anything, + * so just return quickly. + */ + if (readonly) + return; + /* + * If editing (not reading system mail box), then do the work + * in edstop() + */ + if (edit) { + edstop(); + return; + } + + /* + * See if there any messages to save in mbox. If no, we + * can save copying mbox to /tmp and back. + * + * Check also to see if any files need to be preserved. + * Delete all untouched messages to keep them out of mbox. + * If all the messages are to be preserved, just exit with + * a message. + */ + + fbuf = Fopen(mailname, "r"); + if (fbuf == NULL) + goto newmail; + flock(fileno(fbuf), LOCK_EX); + rbuf = NULL; + if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) { + printf("New mail has arrived.\n"); + rbuf = Fopen(tempResid, "w"); + if (rbuf == NULL || fbuf == NULL) + goto newmail; +#ifdef APPEND + fseek(fbuf, (long)mailsize, 0); + while ((c = getc(fbuf)) != EOF) + (void) putc(c, rbuf); +#else + p = minfo.st_size - mailsize; + while (p-- > 0) { + c = getc(fbuf); + if (c == EOF) + goto newmail; + (void) putc(c, rbuf); + } +#endif + Fclose(rbuf); + if ((rbuf = Fopen(tempResid, "r")) == NULL) + goto newmail; + rm(tempResid); + } + + /* + * Adjust the message flags in each message. + */ + + anystat = 0; + autohold = value("hold") != NOSTR; + holdbit = autohold ? MPRESERVE : MBOX; + nohold = MBOX|MSAVED|MDELETED|MPRESERVE; + if (value("keepsave") != NOSTR) + nohold &= ~MSAVED; + for (mp = &message[0]; mp < &message[msgCount]; mp++) { + if (mp->m_flag & MNEW) { + mp->m_flag &= ~MNEW; + mp->m_flag |= MSTATUS; + } + if (mp->m_flag & MSTATUS) + anystat++; + if ((mp->m_flag & MTOUCH) == 0) + mp->m_flag |= MPRESERVE; + if ((mp->m_flag & nohold) == 0) + mp->m_flag |= holdbit; + } + modify = 0; + if (Tflag != NOSTR) { + if ((readstat = Fopen(Tflag, "w")) == NULL) + Tflag = NOSTR; + } + for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) { + if (mp->m_flag & MBOX) + c++; + if (mp->m_flag & MPRESERVE) + p++; + if (mp->m_flag & MODIFY) + modify++; + if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) { + char *id; + + if ((id = hfield("article-id", mp)) != NOSTR) + fprintf(readstat, "%s\n", id); + } + } + if (Tflag != NOSTR) + Fclose(readstat); + if (p == msgCount && !modify && !anystat) { + printf("Held %d message%s in %s\n", + p, p == 1 ? "" : "s", mailname); + Fclose(fbuf); + return; + } + if (c == 0) { + if (p != 0) { + writeback(rbuf); + Fclose(fbuf); + return; + } + goto cream; + } + + /* + * Create another temporary file and copy user's mbox file + * darin. If there is no mbox, copy nothing. + * If he has specified "append" don't copy his mailbox, + * just copy saveable entries at the end. + */ + + mbox = expand("&"); + mcount = c; + if (value("append") == NOSTR) { + if ((obuf = Fopen(tempQuit, "w")) == NULL) { + perror(tempQuit); + Fclose(fbuf); + return; + } + if ((ibuf = Fopen(tempQuit, "r")) == NULL) { + perror(tempQuit); + rm(tempQuit); + Fclose(obuf); + Fclose(fbuf); + return; + } + rm(tempQuit); + if ((abuf = Fopen(mbox, "r")) != NULL) { + while ((c = getc(abuf)) != EOF) + (void) putc(c, obuf); + Fclose(abuf); + } + if (ferror(obuf)) { + perror(tempQuit); + Fclose(ibuf); + Fclose(obuf); + Fclose(fbuf); + return; + } + Fclose(obuf); + close(creat(mbox, 0600)); + if ((obuf = Fopen(mbox, "r+")) == NULL) { + perror(mbox); + Fclose(ibuf); + Fclose(fbuf); + return; + } + } + if (value("append") != NOSTR) { + if ((obuf = Fopen(mbox, "a")) == NULL) { + perror(mbox); + Fclose(fbuf); + return; + } + fchmod(fileno(obuf), 0600); + } + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if (mp->m_flag & MBOX) + if (send(mp, obuf, saveignore, NOSTR) < 0) { + perror(mbox); + Fclose(ibuf); + Fclose(obuf); + Fclose(fbuf); + return; + } + + /* + * Copy the user's old mbox contents back + * to the end of the stuff we just saved. + * If we are appending, this is unnecessary. + */ + + if (value("append") == NOSTR) { + rewind(ibuf); + c = getc(ibuf); + while (c != EOF) { + (void) putc(c, obuf); + if (ferror(obuf)) + break; + c = getc(ibuf); + } + Fclose(ibuf); + fflush(obuf); + } + trunc(obuf); + if (ferror(obuf)) { + perror(mbox); + Fclose(obuf); + Fclose(fbuf); + return; + } + Fclose(obuf); + if (mcount == 1) + printf("Saved 1 message in mbox\n"); + else + printf("Saved %d messages in mbox\n", mcount); + + /* + * Now we are ready to copy back preserved files to + * the system mailbox, if any were requested. + */ + + if (p != 0) { + writeback(rbuf); + Fclose(fbuf); + return; + } + + /* + * Finally, remove his /usr/mail file. + * If new mail has arrived, copy it back. + */ + +cream: + if (rbuf != NULL) { + abuf = Fopen(mailname, "r+"); + if (abuf == NULL) + goto newmail; + while ((c = getc(rbuf)) != EOF) + (void) putc(c, abuf); + Fclose(rbuf); + trunc(abuf); + Fclose(abuf); + alter(mailname); + Fclose(fbuf); + return; + } + demail(); + Fclose(fbuf); + return; + +newmail: + printf("Thou hast new mail.\n"); + if (fbuf != NULL) + Fclose(fbuf); +} + +/* + * Preserve all the appropriate messages back in the system + * mailbox, and print a nice message indicated how many were + * saved. On any error, just return -1. Else return 0. + * Incorporate the any new mail that we found. + */ +int +writeback(res) + register FILE *res; +{ + register struct message *mp; + register int p, c; + FILE *obuf; + + p = 0; + if ((obuf = Fopen(mailname, "r+")) == NULL) { + perror(mailname); + return(-1); + } +#ifndef APPEND + if (res != NULL) + while ((c = getc(res)) != EOF) + (void) putc(c, obuf); +#endif + for (mp = &message[0]; mp < &message[msgCount]; mp++) + if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) { + p++; + if (send(mp, obuf, (struct ignoretab *)0, NOSTR) < 0) { + perror(mailname); + Fclose(obuf); + return(-1); + } + } +#ifdef APPEND + if (res != NULL) + while ((c = getc(res)) != EOF) + (void) putc(c, obuf); +#endif + fflush(obuf); + trunc(obuf); + if (ferror(obuf)) { + perror(mailname); + Fclose(obuf); + return(-1); + } + if (res != NULL) + Fclose(res); + Fclose(obuf); + alter(mailname); + if (p == 1) + printf("Held 1 message in %s\n", mailname); + else + printf("Held %d messages in %s\n", p, mailname); + return(0); +} + +/* + * Terminate an editing session by attempting to write out the user's + * file from the temporary. Save any new stuff appended to the file. + */ +void +edstop() +{ + extern char *tmpdir; + register int gotcha, c; + register struct message *mp; + FILE *obuf, *ibuf, *readstat; + struct stat statb; + char tempname[30]; + char *mktemp(); + + if (readonly) + return; + holdsigs(); + if (Tflag != NOSTR) { + if ((readstat = Fopen(Tflag, "w")) == NULL) + Tflag = NOSTR; + } + for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) { + if (mp->m_flag & MNEW) { + mp->m_flag &= ~MNEW; + mp->m_flag |= MSTATUS; + } + if (mp->m_flag & (MODIFY|MDELETED|MSTATUS)) + gotcha++; + if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) { + char *id; + + if ((id = hfield("article-id", mp)) != NOSTR) + fprintf(readstat, "%s\n", id); + } + } + if (Tflag != NOSTR) + Fclose(readstat); + if (!gotcha || Tflag != NOSTR) + goto done; + ibuf = NULL; + if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) { + strcpy(tempname, tmpdir); + strcat(tempname, "mboxXXXXXX"); + mktemp(tempname); + if ((obuf = Fopen(tempname, "w")) == NULL) { + perror(tempname); + relsesigs(); + reset(0); + } + if ((ibuf = Fopen(mailname, "r")) == NULL) { + perror(mailname); + Fclose(obuf); + rm(tempname); + relsesigs(); + reset(0); + } + fseek(ibuf, (long)mailsize, 0); + while ((c = getc(ibuf)) != EOF) + (void) putc(c, obuf); + Fclose(ibuf); + Fclose(obuf); + if ((ibuf = Fopen(tempname, "r")) == NULL) { + perror(tempname); + rm(tempname); + relsesigs(); + reset(0); + } + rm(tempname); + } + printf("\"%s\" ", mailname); + fflush(stdout); + if ((obuf = Fopen(mailname, "r+")) == NULL) { + perror(mailname); + relsesigs(); + reset(0); + } + trunc(obuf); + c = 0; + for (mp = &message[0]; mp < &message[msgCount]; mp++) { + if ((mp->m_flag & MDELETED) != 0) + continue; + c++; + if (send(mp, obuf, (struct ignoretab *) NULL, NOSTR) < 0) { + perror(mailname); + relsesigs(); + reset(0); + } + } + gotcha = (c == 0 && ibuf == NULL); + if (ibuf != NULL) { + while ((c = getc(ibuf)) != EOF) + (void) putc(c, obuf); + Fclose(ibuf); + } + fflush(obuf); + if (ferror(obuf)) { + perror(mailname); + relsesigs(); + reset(0); + } + Fclose(obuf); + if (gotcha) { + rm(mailname); + printf("removed\n"); + } else + printf("complete\n"); + fflush(stdout); + +done: + relsesigs(); +} diff --git a/usr.bin/mail/rcv.h b/usr.bin/mail/rcv.h new file mode 100644 index 0000000..6d78f36 --- /dev/null +++ b/usr.bin/mail/rcv.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)rcv.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * Mail -- a mail program + * + * This file is included by normal files which want both + * globals and declarations. + */ + +#include "def.h" +#include "glob.h" diff --git a/usr.bin/mail/send.c b/usr.bin/mail/send.c new file mode 100644 index 0000000..c8b8fea --- /dev/null +++ b/usr.bin/mail/send.c @@ -0,0 +1,556 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Mail to others. + */ + +/* + * Send message described by the passed pointer to the + * passed output buffer. Return -1 on error. + * Adjust the status: field if need be. + * If doign is given, suppress ignored header fields. + * prefix is a string to prepend to each output line. + */ +int +send(mp, obuf, doign, prefix) + register struct message *mp; + FILE *obuf; + struct ignoretab *doign; + char *prefix; +{ + long count; + register FILE *ibuf; + char line[LINESIZE]; + int ishead, infld, ignoring, dostat, firstline; + register char *cp, *cp2; + register int c; + int length; + int prefixlen; + + /* + * Compute the prefix string, without trailing whitespace + */ + if (prefix != NOSTR) { + cp2 = 0; + for (cp = prefix; *cp; cp++) + if (*cp != ' ' && *cp != '\t') + cp2 = cp; + prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1; + } + ibuf = setinput(mp); + count = mp->m_size; + ishead = 1; + dostat = doign == 0 || !isign("status", doign); + infld = 0; + firstline = 1; + /* + * Process headers first + */ + while (count > 0 && ishead) { + if (fgets(line, LINESIZE, ibuf) == NULL) + break; + count -= length = strlen(line); + if (firstline) { + /* + * First line is the From line, so no headers + * there to worry about + */ + firstline = 0; + ignoring = doign == ignoreall; + } else if (line[0] == '\n') { + /* + * If line is blank, we've reached end of + * headers, so force out status: field + * and note that we are no longer in header + * fields + */ + if (dostat) { + statusput(mp, obuf, prefix); + dostat = 0; + } + ishead = 0; + ignoring = doign == ignoreall; + } else if (infld && (line[0] == ' ' || line[0] == '\t')) { + /* + * If this line is a continuation (via space or tab) + * of a previous header field, just echo it + * (unless the field should be ignored). + * In other words, nothing to do. + */ + } else { + /* + * Pick up the header field if we have one. + */ + for (cp = line; (c = *cp++) && c != ':' && !isspace(c);) + ; + cp2 = --cp; + while (isspace(*cp++)) + ; + if (cp[-1] != ':') { + /* + * Not a header line, force out status: + * This happens in uucp style mail where + * there are no headers at all. + */ + if (dostat) { + statusput(mp, obuf, prefix); + dostat = 0; + } + if (doign != ignoreall) + /* add blank line */ + (void) putc('\n', obuf); + ishead = 0; + ignoring = 0; + } else { + /* + * If it is an ignored field and + * we care about such things, skip it. + */ + *cp2 = 0; /* temporarily null terminate */ + if (doign && isign(line, doign)) + ignoring = 1; + else if ((line[0] == 's' || line[0] == 'S') && + strcasecmp(line, "status") == 0) { + /* + * If the field is "status," go compute + * and print the real Status: field + */ + if (dostat) { + statusput(mp, obuf, prefix); + dostat = 0; + } + ignoring = 1; + } else { + ignoring = 0; + *cp2 = c; /* restore */ + } + infld = 1; + } + } + if (!ignoring) { + /* + * Strip trailing whitespace from prefix + * if line is blank. + */ + if (prefix != NOSTR) + if (length > 1) + fputs(prefix, obuf); + else + (void) fwrite(prefix, sizeof *prefix, + prefixlen, obuf); + (void) fwrite(line, sizeof *line, length, obuf); + if (ferror(obuf)) + return -1; + } + } + /* + * Copy out message body + */ + if (doign == ignoreall) + count--; /* skip final blank line */ + if (prefix != NOSTR) + while (count > 0) { + if (fgets(line, LINESIZE, ibuf) == NULL) { + c = 0; + break; + } + count -= c = strlen(line); + /* + * Strip trailing whitespace from prefix + * if line is blank. + */ + if (c > 1) + fputs(prefix, obuf); + else + (void) fwrite(prefix, sizeof *prefix, + prefixlen, obuf); + (void) fwrite(line, sizeof *line, c, obuf); + if (ferror(obuf)) + return -1; + } + else + while (count > 0) { + c = count < LINESIZE ? count : LINESIZE; + if ((c = fread(line, sizeof *line, c, ibuf)) <= 0) + break; + count -= c; + if (fwrite(line, sizeof *line, c, obuf) != c) + return -1; + } + if (doign == ignoreall && c > 0 && line[c - 1] != '\n') + /* no final blank line */ + if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF) + return -1; + return 0; +} + +/* + * Output a reasonable looking status field. + */ +void +statusput(mp, obuf, prefix) + register struct message *mp; + FILE *obuf; + char *prefix; +{ + char statout[3]; + register char *cp = statout; + + if (mp->m_flag & MREAD) + *cp++ = 'R'; + if ((mp->m_flag & MNEW) == 0) + *cp++ = 'O'; + *cp = 0; + if (statout[0]) + fprintf(obuf, "%sStatus: %s\n", + prefix == NOSTR ? "" : prefix, statout); +} + +/* + * Interface between the argument list and the mail1 routine + * which does all the dirty work. + */ +int +mail(to, cc, bcc, smopts, subject) + struct name *to, *cc, *bcc, *smopts; + char *subject; +{ + struct header head; + + head.h_to = to; + head.h_subject = subject; + head.h_cc = cc; + head.h_bcc = bcc; + head.h_smopts = smopts; + mail1(&head, 0); + return(0); +} + + +/* + * Send mail to a bunch of user names. The interface is through + * the mail routine below. + */ +int +sendmail(str) + char *str; +{ + struct header head; + + head.h_to = extract(str, GTO); + head.h_subject = NOSTR; + head.h_cc = NIL; + head.h_bcc = NIL; + head.h_smopts = NIL; + mail1(&head, 0); + return(0); +} + +/* + * Mail a message on standard input to the people indicated + * in the passed header. (Internal interface). + */ +void +mail1(hp, printheaders) + struct header *hp; + int printheaders; +{ + char *cp; + int pid; + char **namelist; + struct name *to; + FILE *mtf; + + /* + * Collect user's mail from standard input. + * Get the result as mtf. + */ + if ((mtf = collect(hp, printheaders)) == NULL) + return; + if (value("interactive") != NOSTR) + if (value("askcc") != NOSTR) + grabh(hp, GCC); + else { + printf("EOT\n"); + (void) fflush(stdout); + } + if (fsize(mtf) == 0) + if (hp->h_subject == NOSTR) + printf("No message, no subject; hope that's ok\n"); + else + printf("Null message body; hope that's ok\n"); + /* + * Now, take the user names from the combined + * to and cc lists and do all the alias + * processing. + */ + senderr = 0; + to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc))); + if (to == NIL) { + printf("No recipients specified\n"); + senderr++; + } + /* + * Look through the recipient list for names with /'s + * in them which we write to as files directly. + */ + to = outof(to, mtf, hp); + if (senderr) + savedeadletter(mtf); + to = elide(to); + if (count(to) == 0) + goto out; + fixhead(hp, to); + if ((mtf = infix(hp, mtf)) == NULL) { + fprintf(stderr, ". . . message lost, sorry.\n"); + return; + } + namelist = unpack(cat(hp->h_smopts, to)); + if (debug) { + char **t; + + printf("Sendmail arguments:"); + for (t = namelist; *t != NOSTR; t++) + printf(" \"%s\"", *t); + printf("\n"); + goto out; + } + if ((cp = value("record")) != NOSTR) + (void) savemail(expand(cp), mtf); + /* + * Fork, set up the temporary mail file as standard + * input for "mail", and exec with the user list we generated + * far above. + */ + pid = fork(); + if (pid == -1) { + perror("fork"); + savedeadletter(mtf); + goto out; + } + if (pid == 0) { + prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)| + sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU), + fileno(mtf), -1); + if ((cp = value("sendmail")) != NOSTR) + cp = expand(cp); + else + cp = _PATH_SENDMAIL; + execv(cp, namelist); + perror(cp); + _exit(1); + } + if (value("verbose") != NOSTR) + (void) wait_child(pid); + else + free_child(pid); +out: + (void) Fclose(mtf); +} + +/* + * Fix the header by glopping all of the expanded names from + * the distribution list into the appropriate fields. + */ +void +fixhead(hp, tolist) + struct header *hp; + struct name *tolist; +{ + register struct name *np; + + hp->h_to = NIL; + hp->h_cc = NIL; + hp->h_bcc = NIL; + for (np = tolist; np != NIL; np = np->n_flink) + if ((np->n_type & GMASK) == GTO) + hp->h_to = + cat(hp->h_to, nalloc(np->n_name, np->n_type)); + else if ((np->n_type & GMASK) == GCC) + hp->h_cc = + cat(hp->h_cc, nalloc(np->n_name, np->n_type)); + else if ((np->n_type & GMASK) == GBCC) + hp->h_bcc = + cat(hp->h_bcc, nalloc(np->n_name, np->n_type)); +} + +/* + * Prepend a header in front of the collected stuff + * and return the new file. + */ +FILE * +infix(hp, fi) + struct header *hp; + FILE *fi; +{ + extern char tempMail[]; + register FILE *nfo, *nfi; + register int c; + + if ((nfo = Fopen(tempMail, "w")) == NULL) { + perror(tempMail); + return(fi); + } + if ((nfi = Fopen(tempMail, "r")) == NULL) { + perror(tempMail); + (void) Fclose(nfo); + return(fi); + } + (void) rm(tempMail); + (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA); + c = getc(fi); + while (c != EOF) { + (void) putc(c, nfo); + c = getc(fi); + } + if (ferror(fi)) { + perror("read"); + rewind(fi); + return(fi); + } + (void) fflush(nfo); + if (ferror(nfo)) { + perror(tempMail); + (void) Fclose(nfo); + (void) Fclose(nfi); + rewind(fi); + return(fi); + } + (void) Fclose(nfo); + (void) Fclose(fi); + rewind(nfi); + return(nfi); +} + +/* + * Dump the to, subject, cc header on the + * passed file buffer. + */ +int +puthead(hp, fo, w) + struct header *hp; + FILE *fo; + int w; +{ + register int gotcha; + + gotcha = 0; + if (hp->h_to != NIL && w & GTO) + fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++; + if (hp->h_subject != NOSTR && w & GSUBJECT) + fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++; + if (hp->h_cc != NIL && w & GCC) + fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++; + if (hp->h_bcc != NIL && w & GBCC) + fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++; + if (gotcha && w & GNL) + (void) putc('\n', fo); + return(0); +} + +/* + * Format the given header line to not exceed 72 characters. + */ +void +fmt(str, np, fo, comma) + char *str; + register struct name *np; + FILE *fo; + int comma; +{ + register col, len; + + comma = comma ? 1 : 0; + col = strlen(str); + if (col) + fputs(str, fo); + for (; np != NIL; np = np->n_flink) { + if (np->n_flink == NIL) + comma = 0; + len = strlen(np->n_name); + col++; /* for the space */ + if (col + len + comma > 72 && col > 4) { + fputs("\n ", fo); + col = 4; + } else + putc(' ', fo); + fputs(np->n_name, fo); + if (comma) + putc(',', fo); + col += len + comma; + } + putc('\n', fo); +} + +/* + * Save the outgoing mail on the passed file. + */ + +/*ARGSUSED*/ +int +savemail(name, fi) + char name[]; + register FILE *fi; +{ + register FILE *fo; + char buf[BUFSIZ]; + register i; + time_t now, time(); + char *ctime(); + + if ((fo = Fopen(name, "a")) == NULL) { + perror(name); + return (-1); + } + (void) time(&now); + fprintf(fo, "From %s %s", myname, ctime(&now)); + while ((i = fread(buf, 1, sizeof buf, fi)) > 0) + (void) fwrite(buf, 1, i, fo); + (void) putc('\n', fo); + (void) fflush(fo); + if (ferror(fo)) + perror(name); + (void) Fclose(fo); + rewind(fi); + return (0); +} diff --git a/usr.bin/mail/strings.c b/usr.bin/mail/strings.c new file mode 100644 index 0000000..f27b959 --- /dev/null +++ b/usr.bin/mail/strings.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)strings.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * String allocation routines. + * Strings handed out here are reclaimed at the top of the command + * loop each time, so they need not be freed. + */ + +#include "rcv.h" +#include "extern.h" + +/* + * Allocate size more bytes of space and return the address of the + * first byte to the caller. An even number of bytes are always + * allocated so that the space will always be on a word boundary. + * The string spaces are of exponentially increasing size, to satisfy + * the occasional user with enormous string size requests. + */ + +char * +salloc(size) + int size; +{ + register char *t; + register int s; + register struct strings *sp; + int index; + + s = size; + s += 3; + s &= ~03; + index = 0; + for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) { + if (sp->s_topFree == NOSTR && (STRINGSIZE << index) >= s) + break; + if (sp->s_nleft >= s) + break; + index++; + } + if (sp >= &stringdope[NSPACE]) + panic("String too large"); + if (sp->s_topFree == NOSTR) { + index = sp - &stringdope[0]; + sp->s_topFree = malloc(STRINGSIZE << index); + if (sp->s_topFree == NOSTR) { + fprintf(stderr, "No room for space %d\n", index); + panic("Internal error"); + } + sp->s_nextFree = sp->s_topFree; + sp->s_nleft = STRINGSIZE << index; + } + sp->s_nleft -= s; + t = sp->s_nextFree; + sp->s_nextFree += s; + return(t); +} + +/* + * Reset the string area to be empty. + * Called to free all strings allocated + * since last reset. + */ +void +sreset() +{ + register struct strings *sp; + register int index; + + if (noreset) + return; + index = 0; + for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) { + if (sp->s_topFree == NOSTR) + continue; + sp->s_nextFree = sp->s_topFree; + sp->s_nleft = STRINGSIZE << index; + index++; + } +} + +/* + * Make the string area permanent. + * Meant to be called in main, after initialization. + */ +void +spreserve() +{ + register struct strings *sp; + + for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) + sp->s_topFree = NOSTR; +} diff --git a/usr.bin/mail/temp.c b/usr.bin/mail/temp.c new file mode 100644 index 0000000..9162c9f --- /dev/null +++ b/usr.bin/mail/temp.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)temp.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include <errno.h> +#include "extern.h" + +/* + * Mail -- a mail program + * + * Give names to all the temporary files that we will need. + */ + +char tempMail[24]; +char tempQuit[24]; +char tempEdit[24]; +char tempResid[24]; +char tempMesg[24]; +char *tmpdir; + +void +tinit() +{ + register char *cp; + int len; + + if ((tmpdir = getenv("TMPDIR")) == NULL) + tmpdir = _PATH_TMP; + else { + len = strlen(tmpdir); + if ((cp = malloc(len + 2)) == NULL) { + (void)fprintf(stderr, "mail: %s\n", strerror(errno)); + exit (1); + } + (void)strcpy(cp, tmpdir); + cp[len] = '/'; + cp[len + 1] = '\0'; + tmpdir = cp; + } + + strcpy(tempMail, tmpdir); + mktemp(strcat(tempMail, "RsXXXXXX")); + strcpy(tempResid, tmpdir); + mktemp(strcat(tempResid, "RqXXXXXX")); + strcpy(tempQuit, tmpdir); + mktemp(strcat(tempQuit, "RmXXXXXX")); + strcpy(tempEdit, tmpdir); + mktemp(strcat(tempEdit, "ReXXXXXX")); + strcpy(tempMesg, tmpdir); + mktemp(strcat(tempMesg, "RxXXXXXX")); + + /* + * It's okay to call savestr in here because main will + * do a spreserve() after us. + */ + if (myname != NOSTR) { + if (getuserid(myname) < 0) { + printf("\"%s\" is not a user of this system\n", + myname); + exit(1); + } + } else { + if ((cp = username()) == NOSTR) { + myname = "ubluit"; + if (rcvmode) { + printf("Who are you!?\n"); + exit(1); + } + } else + myname = savestr(cp); + } + if ((cp = getenv("HOME")) == NOSTR) + cp = "."; + homedir = savestr(cp); + if (debug) + printf("user = %s, homedir = %s\n", myname, homedir); +} diff --git a/usr.bin/mail/tty.c b/usr.bin/mail/tty.c new file mode 100644 index 0000000..b39eba5 --- /dev/null +++ b/usr.bin/mail/tty.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * Generally useful tty stuff. + */ + +#include "rcv.h" +#include "extern.h" + +static int c_erase; /* Current erase char */ +static int c_kill; /* Current kill char */ +static jmp_buf rewrite; /* Place to go when continued */ +static jmp_buf intjmp; /* Place to go when interrupted */ +#ifndef TIOCSTI +static int ttyset; /* We must now do erase/kill */ +#endif + +/* + * Read all relevant header fields. + */ + +int +grabh(hp, gflags) + struct header *hp; + int gflags; +{ + struct sgttyb ttybuf; + sig_t saveint; +#ifndef TIOCSTI + sig_t savequit; +#endif + sig_t savetstp; + sig_t savettou; + sig_t savettin; + int errs; + void ttyint(); + + savetstp = signal(SIGTSTP, SIG_DFL); + savettou = signal(SIGTTOU, SIG_DFL); + savettin = signal(SIGTTIN, SIG_DFL); + errs = 0; +#ifndef TIOCSTI + ttyset = 0; +#endif + if (ioctl(fileno(stdin), TIOCGETP, &ttybuf) < 0) { + perror("gtty"); + return(-1); + } + c_erase = ttybuf.sg_erase; + c_kill = ttybuf.sg_kill; +#ifndef TIOCSTI + ttybuf.sg_erase = 0; + ttybuf.sg_kill = 0; + if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL) + signal(SIGINT, SIG_DFL); + if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL) + signal(SIGQUIT, SIG_DFL); +#else + if (setjmp(intjmp)) + goto out; + saveint = signal(SIGINT, ttyint); +#endif + if (gflags & GTO) { +#ifndef TIOCSTI + if (!ttyset && hp->h_to != NIL) + ttyset++, stty(fileno(stdin), &ttybuf); +#endif + hp->h_to = + extract(readtty("To: ", detract(hp->h_to, 0)), GTO); + } + if (gflags & GSUBJECT) { +#ifndef TIOCSTI + if (!ttyset && hp->h_subject != NOSTR) + ttyset++, stty(fileno(stdin), &ttybuf); +#endif + hp->h_subject = readtty("Subject: ", hp->h_subject); + } + if (gflags & GCC) { +#ifndef TIOCSTI + if (!ttyset && hp->h_cc != NIL) + ttyset++, stty(fileno(stdin), &ttybuf); +#endif + hp->h_cc = + extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC); + } + if (gflags & GBCC) { +#ifndef TIOCSTI + if (!ttyset && hp->h_bcc != NIL) + ttyset++, stty(fileno(stdin), &ttybuf); +#endif + hp->h_bcc = + extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC); + } +out: + signal(SIGTSTP, savetstp); + signal(SIGTTOU, savettou); + signal(SIGTTIN, savettin); +#ifndef TIOCSTI + ttybuf.sg_erase = c_erase; + ttybuf.sg_kill = c_kill; + if (ttyset) + stty(fileno(stdin), &ttybuf); + signal(SIGQUIT, savequit); +#endif + signal(SIGINT, saveint); + return(errs); +} + +/* + * Read up a header from standard input. + * The source string has the preliminary contents to + * be read. + * + */ + +char * +readtty(pr, src) + char pr[], src[]; +{ + char ch, canonb[BUFSIZ]; + int c; + register char *cp, *cp2; + void ttystop(); + + fputs(pr, stdout); + fflush(stdout); + if (src != NOSTR && strlen(src) > BUFSIZ - 2) { + printf("too long to edit\n"); + return(src); + } +#ifndef TIOCSTI + if (src != NOSTR) + cp = copy(src, canonb); + else + cp = copy("", canonb); + fputs(canonb, stdout); + fflush(stdout); +#else + cp = src == NOSTR ? "" : src; + while (c = *cp++) { + if (c == c_erase || c == c_kill) { + ch = '\\'; + ioctl(0, TIOCSTI, &ch); + } + ch = c; + ioctl(0, TIOCSTI, &ch); + } + cp = canonb; + *cp = 0; +#endif + cp2 = cp; + while (cp2 < canonb + BUFSIZ) + *cp2++ = 0; + cp2 = cp; + if (setjmp(rewrite)) + goto redo; + signal(SIGTSTP, ttystop); + signal(SIGTTOU, ttystop); + signal(SIGTTIN, ttystop); + clearerr(stdin); + while (cp2 < canonb + BUFSIZ) { + c = getc(stdin); + if (c == EOF || c == '\n') + break; + *cp2++ = c; + } + *cp2 = 0; + signal(SIGTSTP, SIG_DFL); + signal(SIGTTOU, SIG_DFL); + signal(SIGTTIN, SIG_DFL); + if (c == EOF && ferror(stdin)) { +redo: + cp = strlen(canonb) > 0 ? canonb : NOSTR; + clearerr(stdin); + return(readtty(pr, cp)); + } +#ifndef TIOCSTI + if (cp == NOSTR || *cp == '\0') + return(src); + cp2 = cp; + if (!ttyset) + return(strlen(canonb) > 0 ? savestr(canonb) : NOSTR); + while (*cp != '\0') { + c = *cp++; + if (c == c_erase) { + if (cp2 == canonb) + continue; + if (cp2[-1] == '\\') { + cp2[-1] = c; + continue; + } + cp2--; + continue; + } + if (c == c_kill) { + if (cp2 == canonb) + continue; + if (cp2[-1] == '\\') { + cp2[-1] = c; + continue; + } + cp2 = canonb; + continue; + } + *cp2++ = c; + } + *cp2 = '\0'; +#endif + if (equal("", canonb)) + return(NOSTR); + return(savestr(canonb)); +} + +/* + * Receipt continuation. + */ +void +ttystop(s) + int s; +{ + sig_t old_action = signal(s, SIG_DFL); + + sigsetmask(sigblock(0) & ~sigmask(s)); + kill(0, s); + sigblock(sigmask(s)); + signal(s, old_action); + longjmp(rewrite, 1); +} + +/*ARGSUSED*/ +void +ttyint(s) + int s; +{ + longjmp(intjmp, 1); +} diff --git a/usr.bin/mail/v7.local.c b/usr.bin/mail/v7.local.c new file mode 100644 index 0000000..5144c01 --- /dev/null +++ b/usr.bin/mail/v7.local.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)v7.local.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Mail -- a mail program + * + * Version 7 + * + * Local routines that are installation dependent. + */ + +#include "rcv.h" +#include <fcntl.h> +#include "extern.h" + +/* + * Locate the user's mailbox file (ie, the place where new, unread + * mail is queued). + */ +void +findmail(user, buf) + char *user, *buf; +{ + (void)sprintf(buf, "%s/%s", _PATH_MAILDIR, user); +} + +/* + * Get rid of the queued mail. + */ +void +demail() +{ + + if (value("keep") != NOSTR || rm(mailname) < 0) + close(creat(mailname, 0600)); +} + +/* + * Discover user login name. + */ +char * +username() +{ + char *np; + + if ((np = getenv("USER")) != NOSTR) + return np; + return getname(getuid()); +} diff --git a/usr.bin/mail/vars.c b/usr.bin/mail/vars.c new file mode 100644 index 0000000..2a90442 --- /dev/null +++ b/usr.bin/mail/vars.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)vars.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Variable handling stuff. + */ + +/* + * Assign a value to a variable. + */ +void +assign(name, value) + char name[], value[]; +{ + register struct var *vp; + register int h; + + h = hash(name); + vp = lookup(name); + if (vp == NOVAR) { + vp = (struct var *) calloc(sizeof *vp, 1); + vp->v_name = vcopy(name); + vp->v_link = variables[h]; + variables[h] = vp; + } + else + vfree(vp->v_value); + vp->v_value = vcopy(value); +} + +/* + * Free up a variable string. We do not bother to allocate + * strings whose value is "" since they are expected to be frequent. + * Thus, we cannot free same! + */ +void +vfree(cp) + char *cp; +{ + if (*cp) + free(cp); +} + +/* + * Copy a variable value into permanent (ie, not collected after each + * command) space. Do not bother to alloc space for "" + */ + +char * +vcopy(str) + char str[]; +{ + char *new; + unsigned len; + + if (*str == '\0') + return ""; + len = strlen(str) + 1; + if ((new = malloc(len)) == NULL) + panic("Out of memory"); + bcopy(str, new, (int) len); + return new; +} + +/* + * Get the value of a variable and return it. + * Look in the environment if its not available locally. + */ + +char * +value(name) + char name[]; +{ + register struct var *vp; + + if ((vp = lookup(name)) == NOVAR) + return(getenv(name)); + return(vp->v_value); +} + +/* + * Locate a variable and return its variable + * node. + */ + +struct var * +lookup(name) + register char name[]; +{ + register struct var *vp; + + for (vp = variables[hash(name)]; vp != NOVAR; vp = vp->v_link) + if (*vp->v_name == *name && equal(vp->v_name, name)) + return(vp); + return(NOVAR); +} + +/* + * Locate a group name and return it. + */ + +struct grouphead * +findgroup(name) + register char name[]; +{ + register struct grouphead *gh; + + for (gh = groups[hash(name)]; gh != NOGRP; gh = gh->g_link) + if (*gh->g_name == *name && equal(gh->g_name, name)) + return(gh); + return(NOGRP); +} + +/* + * Print a group out on stdout + */ +void +printgroup(name) + char name[]; +{ + register struct grouphead *gh; + register struct group *gp; + + if ((gh = findgroup(name)) == NOGRP) { + printf("\"%s\": not a group\n", name); + return; + } + printf("%s\t", gh->g_name); + for (gp = gh->g_list; gp != NOGE; gp = gp->ge_link) + printf(" %s", gp->ge_name); + putchar('\n'); +} + +/* + * Hash the passed string and return an index into + * the variable or group hash table. + */ +int +hash(name) + register char *name; +{ + register h = 0; + + while (*name) { + h <<= 2; + h += *name++; + } + if (h < 0 && (h = -h) < 0) + h = 0; + return (h % HSHSIZE); +} diff --git a/usr.bin/mail/version.c b/usr.bin/mail/version.c new file mode 100644 index 0000000..c7d39c3 --- /dev/null +++ b/usr.bin/mail/version.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char sccsid[] = "@(#)version.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * Just keep track of the date/sid of this version of Mail. + * Load this file first to get a "total" Mail version. + */ +char *version = "8.1 6/6/93"; |