pdp11v/usr/src/cmd/mail.c
/* @(#)mail.c 1.6 */
/*
* Mail to a remote machine will normally use the uux command.
* If available, it may be better to send mail via nusend
* or usend, although delivery is not as reliable as uux.
* Mail may be compiled to take advantage
* of these other networks by adding:
* #define USE_NUSEND for nusend
* and
* #define USE_USEND for usend.
*
* NOTE: If either or both defines are specified, that network
* will be tried before uux.
*/
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <pwd.h>
#include <time.h>
#include <utmp.h>
#include <sys/stat.h>
#include <setjmp.h>
#include <sys/utsname.h>
#define LOCKON 1 /* lock set */
#define LOCKOFF 0 /* lock released */
#define C_NOACCESS 0 /* no access to file */
#define CHILD 0
#define SAME 0
#define CERROR -1
#define CSUCCESS 0
#define TRUE 1
#define FALSE 0
#define E_FLGE 1 /* exit flge error */
#define E_FILE 2 /* exit file error */
#define E_SPACE 3 /* exit no space */
/*
* copylet flags
*/
#define REMOTE 1 /* remote mail, add rmtmsg */
#define ORDINARY 2
#define ZAP 3 /* zap header and trailing empty line */
#define FORWARD 4
#define LSIZE 256 /* maximum size of a line */
#define MAXLET 300 /* maximum number of letters */
#define FROMLEVELS 20 /* maxium number of forwards */
#define MAXFILENAME 128
#ifndef MFMODE
#define MFMODE 0660 /* create mode for `/usr/mail' files */
#endif
#define A_OK 0 /* return value for access */
#define A_EXIST 0 /* access check for existence */
#define A_WRITE 2 /* access check for write permission */
#define A_READ 4 /* access check for read permission */
struct let {
long adr;
char change;
} let[MAXLET];
struct passwd *getpwuid(), getpwent();
struct utsname utsn;
FILE *tmpf, *malf;
char lettmp[] = "/tmp/maXXXXX";
char from[] = "From ";
char TO[] = "To: ";
char maildir[] = "/usr/mail/";
char sendto[256];
/*
* fowrding address
*/
char *mailfile;
char maillock[] = ".lock";
char dead[] = "/dead.letter";
char rmtbuf[] = "/tmp/marXXXXXX";
#define RMTMSG " remote from %s\n"
#define FORWMSG " forwarded by %s\n"
char frwrd[] = "Forward to ";
char nospace[] = "mail: no space for temp file\n";
char *thissys;
char mbox[] = "/mbox";
char curlock[50];
char line[LSIZE];
char resp[LSIZE];
char *hmbox;
char *hmdead;
char *home;
char *my_name;
char *getlogin();
char *malloc();
char lfil[50];
char *ctime();
char *getenv();
char *strrchr();
char *mktemp();
int error;
int fromlevel = 0;
int nlet = 0;
int locked;
int changed;
int forward;
int delete();
int flgf = 0;
int flgp = 0;
int flge = 0;
int delflg = 1;
int toflg = 0;
int savdead();
int (*saveint)();
int (*setsig())();
long ftell();
long iop;
jmp_buf sjbuf;
#ifdef USE_NUSEND
jmp_buf nusendfail;
int nusendjmp = FALSE;
#endif
#ifdef USE_USEND
jmp_buf usendfail;
int usendjmp = FALSE;
#endif
unsigned umsave;
char *help[] = {
"q\t\tquit\n",
"x\t\texit without changing mail\n",
"p\t\tprint\n",
"s [file]\tsave (default mbox)\n",
"w [file]\tsame without header\n",
"-\t\tprint previous\n",
"d\t\tdelete\n",
"+\t\tnext (no delete)\n",
"m [user]\tmail to user\n",
"! cmd\t\texecute cmd\n",
0
};
/*
* mail [ + ] [ -irpqet ] [ -f file ]
* mail [ -t ] persons
* rmail [ -t ] persons
*/
main(argc, argv)
char **argv;
{
register i;
umsave = umask(7);
setbuf(stdout, malloc(BUFSIZ));
uname(&utsn);
thissys = utsn.nodename;
/*
* Use environment variables
* logname is used for from
*/
if(((home = getenv("HOME")) == NULL) || (strlen(home) == 0))
home = ".";
if (((my_name = getenv("LOGNAME")) == NULL) || (strlen(my_name) == 0))
my_name = getlogin();
if ((my_name == NULL) || (strlen(my_name) == 0))
my_name = getpwuid(geteuid())->pw_name;
/*
* Catch signals for cleanup
*/
if(setjmp(sjbuf))
done();
for (i=SIGINT; i<SIGCLD; i++)
setsig(i, delete);
setsig(SIGHUP, done);
/*
* Make temporary file for letter
*/
mktemp(lettmp);
unlink(lettmp);
if((tmpf = fopen(lettmp, "w")) == NULL){
fprintf(stderr, "mail: can't open %s for writing\n", lettmp);
error = E_FILE;
done();
}
/*
* Rmail always invoked to send mail
*/
if (argv[0][0] != 'r' &&
(argc == 1 || argv[1][0] == '-' || argv[1][0] == '+'))
printmail(argc, argv);
else
sendmail(argc, argv);
done();
}
/*
* Signal reset
* signals that are not being ignored will be
* caught by function f
* i -> signal number
* f -> signal routine
* return
* rc -> former signal
*/
int (*setsig(i, f))()
int i;
int (*f)();
{
register int (*rc)();
if((rc = signal(i, SIG_IGN))!=SIG_IGN)
signal(i, f);
return(rc);
}
/*
* Print mail entries
* argc -> argument count
* argv -> arguments
*/
printmail(argc, argv)
char **argv;
{
register int c;
int flg, i, j, print, aret, stret, goerr = 0;
char *p, *getarg();
char frwrdbuf[256];
struct stat stbuf;
extern char *optarg;
/*
* Print in reverse order
*/
if (argv[1][0] == '+') {
forward = 1;
argc--;
argv++;
}
while((c = getopt(argc, argv, "f:rpqiet")) != EOF)
switch(c) {
/*
* use file input for mail
*/
case 'f':
flgf = 1;
mailfile = optarg;
break;
/*
* print without prompting
*/
case 'p':
flgp++;
/*
* terminate on deletes
*/
case 'q':
delflg = 0;
case 'i':
break;
/*
* print by first in, first out order
*/
case 'r':
forward = 1;
break;
/*
* do not print mail
*/
case 'e':
flge = 1;
break;
case 't':
toflg = 1;
break;
/*
* bad option
*/
case '?':
goerr++;
}
if(goerr) {
fprintf(stderr, "usage: mail [-erpqt] [-f file] [persons]\n");
error = E_FILE;
done();
}
if (toflg == 1 && argc > 2) {
argv++;
sendmail(--argc, argv);
done();
}
/*
* create working directory mbox name
*/
if((hmbox = malloc(strlen(home) + strlen(mbox) + 1)) == NULL){
fprintf(stderr, "mail: can't allocate hmbox");
error = E_FILE;
return;
}
cat(hmbox, home, mbox);
if(!flgf) {
if(((mailfile = getenv("MAIL")) == NULL) || (strlen(mailfile) == 0)) {
if((mailfile = malloc(strlen(maildir) + strlen(my_name) + 1)) == NULL){
fprintf(stderr, "mail: can't allocate mailfile");
error = E_FILE;
return;
}
cat(mailfile, maildir, my_name);
}
}
/*
* Check accessibility of mail file
*/
stret = stat(mailfile, &stbuf);
if((aret=access(mailfile, A_READ)) == A_OK)
malf = fopen(mailfile, "r");
if (stret == CSUCCESS && aret == CERROR) {
fprintf(stderr, "mail: permission denied!\n");
error = E_FILE;
return;
}else
if (flgf && (aret == CERROR || (malf == NULL))) {
fprintf(stderr, "mail: cannot open %s\n", mailfile);
error = E_FILE;
return;
}else
if(aret == CERROR || (malf == NULL) || (stbuf.st_size == 0)) {
if(!flge) printf("No mail.\n");
error = E_FLGE;
return;
}
lock(mailfile);
/*
* See if mail is to be forwarded to
* another system
*/
if(areforwarding(mailfile)) {
if(flge) {
unlock();
error = E_FLGE;
return;
}
printf("Your mail is being forwarded to ");
fseek(malf, (long)(sizeof(frwrd) - 1), 0);
fgets(frwrdbuf, sizeof(frwrdbuf), malf);
printf("%s", frwrdbuf);
if(getc(malf) != EOF)
printf("and your mailbox contains extra stuff\n");
unlock();
return;
}
if(flge) {
unlock();
return;
}
/*
* copy mail to temp file and mark each
* letter in the let array
*/
copymt(malf, tmpf);
fclose(malf);
fclose(tmpf);
unlock();
if((tmpf = fopen(lettmp, "r")) == NULL) {
fprintf(stderr, "mail: can't open %s\n", lettmp);
error = E_FILE;
return;
}
changed = 0;
print = 1;
for (i = 0; i < nlet; ) {
/*
* reverse order ?
*/
j = forward ? i : nlet - i - 1;
if( setjmp(sjbuf) == 0 && print != 0 )
copylet(j, stdout, ORDINARY);
/*
* print only
*/
if(flgp) {
i++;
continue;
}
/*
* Interactive
*/
setjmp(sjbuf);
printf("? ");
fflush(stdout);
if (fgets(resp, sizeof(resp), stdin) == NULL)
break;
print = 1;
switch (resp[0]) {
default:
printf("usage\n");
/*
* help
*/
case '?':
print = 0;
{
register i;
for(i=0;help[i];i++)
printf("%s", help[i]);
}
break;
/*
* skip entry
*/
case '+':
case 'n':
case '\n':
i++;
case 'p':
break;
case 'x':
changed = 0;
case 'q':
goto donep;
/*
* Previous entry
*/
case '^':
case '-':
if (--i < 0)
i = 0;
break;
/*
* Save in file without header
*/
case 'y':
case 'w':
/*
* Save mail with header
*/
case 's':
if (resp[1] == '\n' || resp[1] == '\0')
cat(resp+1, hmbox, "");
else if(resp[1] != ' ') {
printf("invalid command\n");
print = 0;
continue;
}
umask(umsave);
flg = 0;
for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) {
if((aret=legal(lfil)))
malf = fopen(lfil, "a");
if ((malf == NULL) || (aret == 0)) {
fprintf(stderr, "mail: cannot append to %s\n", lfil);
flg++;
continue;
}
if(aret==2)
chown(lfil, geteuid(), getgid());
if (copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY) == FALSE) {
fprintf(stderr, "mail: cannot save mail\n");
}
fclose(malf);
}
umask(7);
if (flg)
print = 0;
else {
let[j].change = 'd';
changed++;
i++;
}
break;
/*
* Mail letter to someone else
*/
case 'm':
if (resp[1] == '\n' || resp[1] == '\0') {
i++;
continue;
}
if (resp[1] != ' ') {
printf("invalid command\n");
print = 0;
continue;
}
flg = 0;
for (p = resp+1; (p = getarg(lfil, p)) != NULL; )
if (sendrmt(j, lfil) == FALSE)
flg++;
if (flg)
print = 0;
else {
let[j].change = 'd';
changed++;
i++;
}
break;
/*
* Escape to shell
*/
case '!':
system(resp+1);
printf("!\n");
print = 0;
break;
/*
* Delete an entry
*/
case 'd':
let[j].change = 'd';
changed++;
i++;
if (resp[1] == 'q')
goto donep;
break;
}
}
/*
* Copy updated mail file back
*/
donep:
if (changed)
copyback();
}
/*
* copy temp or whatever back to /usr/mail
*/
copyback()
{
register i, n, c;
int new = 0, aret;
struct stat stbuf;
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
lock(mailfile);
stat(mailfile, &stbuf);
/*
* Has new mail arrived?
*/
if (stbuf.st_size != let[nlet].adr) {
if((malf = fopen(mailfile, "r")) == NULL) {
fprintf(stderr, "mail: can't re-read %s\n", mailfile);
error = E_FILE;
done();
}
fseek(malf, let[nlet].adr, 0);
fclose(tmpf);
if((tmpf = fopen(lettmp, "a")) == NULL) {
fprintf(stderr, "mail: can't re-write %s\n", mailfile);
error = E_FILE;
done();
}
/*
* append new mail
* assume only one
* new letter
*/
while ((c = fgetc(malf)) != EOF)
if (fputc(c, tmpf) == EOF) {
fclose(malf);
fclose(tmpf);
fprintf(stderr, nospace);
error = E_SPACE;
done();
}
fclose(malf);
fclose(tmpf);
if((tmpf = fopen(lettmp, "r")) == NULL) {
fprintf(stderr, "mail: can't re-read %s\n", lettmp);
error = E_FILE;
done();
}
if(nlet == (MAXLET-2)){
fprintf(stderr, "copyback:Too many letters\n");
error = E_SPACE;
done();
}
let[++nlet].adr = stbuf.st_size;
new = 1;
}
/*
* Copy mail back to mail file
*/
if((aret=access(mailfile, A_WRITE)) == A_OK)
malf = fopen(mailfile, "w");
if ((malf == NULL) || (aret == CERROR)) {
fprintf(stderr, "mail: can't rewrite %s\n", mailfile);
error = E_FILE;
done();
}
n = 0;
for (i = 0; i < nlet; i++)
if (let[i].change != 'd') {
if (copylet(i, malf, ORDINARY) == FALSE) {
fprintf(stderr, "mail: cannot copy mail back\n");
}
n++;
}
fclose(malf);
/*
* Empty mailbox?
*/
if ((n == 0) && ((stbuf.st_mode & 0777)== MFMODE))
unlink(mailfile);
if (new && !flgf)
printf("new mail arrived\n");
unlock();
}
/*
* copy mail (f1) to temp (f2)
*/
copymt(f1, f2)
register FILE *f1, *f2;
{
long nextadr;
nlet = nextadr = 0;
let[0].adr = 0;
while (fgets(line, sizeof(line), f1) != NULL) {
/*
* bug nlet should be checked
*/
if(line[0] == from[0])
if (isfrom(line)){
if(nlet >= (MAXLET-2)){
fclose(f1);
fclose(f2);
fprintf(stderr,"copymt:Too many letters\n");
error = E_SPACE;
done();
}
let[nlet++].adr = nextadr;
}
nextadr += strlen(line);
if (fputs(line, f2) == EOF) {
fclose(f1);
fclose(f2);
fprintf(stderr, nospace);
error = E_SPACE;
done();
}
}
/*
* last plus 1
*/
let[nlet].adr = nextadr;
}
/*
* check to see if mail is being forwarded
* s -> mail file
* returns
* TRUE -> forwarding
* FALSE -> local
*/
areforwarding(s)
char *s;
{
register char *p;
register int c;
FILE *fd;
char fbuf[256];
if((fd = fopen(s, "r")) == NULL)
return(FALSE);
fbuf[0] = '\0';
fread(fbuf, sizeof(frwrd) - 1, 1, fd);
if(strncmp(fbuf, frwrd, sizeof(frwrd) - 1) == SAME) {
for(p = sendto; (c = getc(fd)) != EOF && c != '\n';)
if(c != ' ')
*p++ = c;
*p = '\0';
fclose(fd);
return(TRUE);
}
fclose(fd);
return(FALSE);
}
/*
* copy letter
* ln -> index into: letter table
* f -> file descrptor to copy file to
* type -> copy type
*/
copylet(ln, f, type)
register FILE *f;
{
register int i;
register char *s;
char buf[512], lastc, ch;
int k, n, j;
int num;
fseek(tmpf, let[ln].adr, 0);
k = let[ln+1].adr - let[ln].adr;
if(k)
k--;
for(i=0;i<k;){
s = buf;
num = ((k-i) > sizeof(buf))?sizeof(buf):(k-i);
if((n = read(tmpf->_file, buf, num)) < 0){
}
lastc = buf[n-1];
if(i == 0){
for(j=0;j<n;j++,s++){
if(*s == '\n')
break;
}
if(type != ZAP)
if(write(f->_file,buf,j) == CERROR){
return(FALSE);
}
i += j+1;
n -= j+1;
ch = *s++;
switch(type){
case REMOTE:
fprintf(f, RMTMSG, thissys);
break;
case ORDINARY:
fprintf(f, "%c", ch);
break;
case FORWARD:
fprintf(f, FORWMSG, my_name);
break;
}
fflush(f);
}
if(write(f->_file, s, n) != n){
return(FALSE);
}
i += n;
}
if(type != ZAP || lastc != '\n'){
read(tmpf->_file, buf, 1);
write(f->_file, buf, 1);
}
return(TRUE);
}
/*
* check for "from" string
* lp -> string to be checked
* returns
* TRUE -> match
* FALSE -> no match
*/
isfrom(lp)
register char *lp;
{
register char *p;
for (p = from; *p; )
if (*lp++ != *p++)
return(FALSE);
return(TRUE);
}
/*
* Send mail
* argc -> argument count
* argv -> argument list
*/
sendmail(argc, argv)
char **argv;
{
int aret;
char **args;
int fromflg = 0;
char *asctime();
struct tm *bp, *localtime();
char *tp, *zp;
/*
* Format time
*/
time(&iop);
bp = localtime(&iop);
tp = asctime(bp);
zp = tzname[bp->tm_isdst];
fprintf(tmpf, "%s%s %.16s %.3s %.5s", from, my_name, tp, zp, tp+20);
/*
* Copy to list in mail entry?
*/
if (toflg == 1 && argc > 1) {
aret = argc;
args = argv;
fprintf(tmpf,"%s ",TO);
while(--aret > 0)
fprintf(tmpf,"%s ",*++args);
fputs("\n",tmpf);
}
iop = ftell(tmpf);
flgf = 1;
/*
* Read mail message
*/
saveint = setsig(SIGINT, savdead);
fromlevel = 0;
while (fgets(line, sizeof(line), stdin) != NULL) {
if (line[0] == '.' && line[1] == '\n')
break;
/*
* If "from" string is present prepend with
* a ">" so it is no longer interpreted as
* the last system fowarding the mail.
*/
if(line[0] == from[0])
if (isfrom(line))
fputs(">", tmpf);
/*
* Find out how many "from" lines
*/
if (fromflg == 0 && (strncmp(line, "From", 4) == SAME || strncmp(line, ">From", 5) == SAME))
fromlevel++;
else
fromflg = 1;
if (fputs(line, tmpf) == EOF) {
fclose(tmpf);
fprintf(stderr, nospace);
error = E_SPACE;
return;
}
flgf = 0;
}
setsig(SIGINT, saveint);
fputs("\n", tmpf);
/*
* In order to use some of the subroutines that
* are used to read mail, the let array must be set up
*/
nlet = 1;
let[0].adr = 0;
let[1].adr = ftell(tmpf);
fclose(tmpf);
if (flgf)
return;
if((tmpf = fopen(lettmp, "r")) == NULL) {
fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp);
error = E_FILE;
return;
}
/*
* Send a copy of the letter to the specified users
*/
if (error == 0)
while (--argc > 0)
if (send(0, *++argv, 0) == FALSE)
error++;
/*
* Save a copy of the letter in dead.letter if
* any letters can't be sent
*/
if (error) {
/*
* Try to create dead letter in current directory
* or in home directory
*/
umask(umsave);
if((aret=legal(&dead[1])))
malf = fopen(&dead[1], "w");
if ((malf == NULL) || (aret == 0)) {
/*
* try to create in $HOME
*/
if((hmdead = malloc(strlen(home) + strlen(dead) + 1)) == NULL) {
fprintf(stderr, "mail: can't malloc\n");
goto out;
}
cat(hmdead, home, dead);
if((aret=legal(hmdead)))
malf = fopen(hmdead, "w");
if ((malf == NULL) || (aret == 0)) {
fprintf(stderr, "mail: cannot create %s\n", &dead[1]);
out:
fclose(tmpf);
error = E_FILE;
umask(7);
return;
} else {
chmod(hmdead, 0600);
printf("Mail saved in %s\n", hmdead);
}
} else {
chmod(&dead[1], 0600);
printf("Mail saved in %s\n", &dead[1]);
}
/*
* Copy letter into dead letter box
*/
umask(7);
if (copylet(0, malf, ZAP) == FALSE) {
fprintf(stderr, "mail: cannot save in dead letter\n");
}
fclose(malf);
}
fclose(tmpf);
}
savdead()
{
setsig(SIGINT, saveint);
error++;
}
/*
* send mail to remote system taking fowarding into account
* n -> index into mail table
* name -> mail destination
* returns
* TRUE -> sent mail
* FALSE -> can't send mail
*/
sendrmt(n, name)
register char *name;
{
# define NSCCONS "/usr/nsc/cons/"
register char *p;
register local;
FILE *rmf, *popen();
char rsys[64], cmd[200];
char remote[30];
/*
* assume mail is for remote
* look for bang to confirm that
* assumption
*/
local = 0;
while (*name=='!')
name++;
for(p=rsys; *name!='!'; *p++ = *name++)
if (*name=='\0') {
local++;
break;
}
*p = '\0';
if ((!local && *name=='\0') || (local && *rsys=='\0')) {
fprintf(stderr, "null name\n");
return(FALSE);
}
if (local)
sprintf(cmd, "mail %s", rsys);
if (strcmp(thissys, rsys) == SAME) {
local++;
sprintf(cmd, "mail %s", name+1);
}
/*
* send local mail or remote via uux
*/
if (!local) {
if (fromlevel > FROMLEVELS)
return(FALSE);
#ifdef USE_NUSEND
/*
* If mail can't be sent over NSC network
* use uucp.
*/
if (setjmp(nusendfail) == 0) {
nusendjmp = TRUE;
sprintf(remote, "%s%s", NSCCONS, rsys);
if (access(remote, A_EXIST) != CERROR) {
/*
* Send mail over NSC network
*/
sprintf(cmd, "nusend -d %s -s -e -!'rmail %s' - 2>/dev/null",
rsys, name);
#ifdef DEBUG
printf("%s\n", cmd);
#endif
if ((rmf=popen(cmd, "w")) != NULL) {
copylet(n, rmf, local? FORWARD: REMOTE);
if (pclose(rmf) == 0) {
nusendjmp = FALSE;
return(TRUE);
}
}
}
}
nusendjmp = FALSE;
#endif
#ifdef USE_USEND
if (setjmp(usendfail) == 0) {
usendjmp = TRUE;
sprintf(cmd, "usend -s -d%s -uNoLogin -!'rmail %s' - 2>/dev/null",
rsys, name);
#ifdef DEBUG
printf("%s\n", cmd);
#endif
if ((rmf=popen(cmd, "w")) != NULL) {
copylet(n, rmf, local? FORWARD: REMOTE);
if (pclose(rmf) == 0) {
usendjmp = FALSE;
return(TRUE);
}
}
}
usendjmp = FALSE;
#endif
/*
* Use uux to send mail
*/
if (strchr(name+1, '!'))
sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
else
sprintf(cmd, "uux - %s!rmail %s", rsys, name+1);
}
#ifdef DEBUG
printf("%s\n", cmd);
#endif
/*
* copy letter to pipe
*/
if ((rmf=popen(cmd, "w")) == NULL)
return(FALSE);
if (copylet(n, rmf, local? FORWARD: REMOTE) == FALSE) {
fprintf(stderr, "mail: cannot pipe to mail command\n");
pclose(rmf);
return(FALSE);
}
/*
* check status
*/
return(pclose(rmf)==0 ? TRUE : FALSE);
}
/*
* send letter n to name
* n -> letter number
* name -> mail destination
* level -> depth of recursion for forwarding
* returns
* TRUE -> mail sent
* FALSE -> can't send mail
*/
send(n, name, level)
int n;
char *name;
{
register char *p;
char file[MAXFILENAME];
struct passwd *pwd, *getpwname();
if(level > 20) {
fprintf(stderr, "unbounded forwarding\n");
return(FALSE);
}
if (strcmp(name, "-") == SAME)
return(TRUE);
/*
* See if mail is to be fowarded
*/
for(p=name; *p!='!' &&*p!='\0'; p++)
;
if (*p == '!')
return(sendrmt(n, name));
/*
* See if user has specified that mail is to be fowarded
*/
cat(file, maildir, name);
if(areforwarding(file))
return(send(n, sendto, level+1));
/*
* see if user exists on this system
*/
setpwent();
if((pwd = getpwnam(name)) == NULL){
fprintf(stderr, "mail: can't send to %s\n", name);
return(FALSE);
}
cat(file, maildir, name);
lock(file);
/*
* If mail file does not exist create it
* with the correct uid and gid
*/
if(access(file, A_EXIST) == CERROR) {
umask(0);
close(creat(file, MFMODE));
umask(7);
chown(file, pwd->pw_uid, getegid());
}
/*
* Append letter to mail box
*/
if((malf = fopen(file, "a")) == NULL){
fprintf(stderr, "mail: cannot append to %s\n", file);
unlock();
return(FALSE);
}
if (copylet(n, malf, ORDINARY) == FALSE) {
fprintf(stderr, "mail: cannot append to %s\n", file);
unlock();
return(FALSE);
}
fclose(malf);
unlock();
return(TRUE);
}
/*
* signal catching routine
* reset signals on quits and interupts
* exit on other signals
* i -> signal #
*/
delete(i)
register int i;
{
setsig(i, delete);
#ifdef USE_NUSEND
if (i == SIGPIPE && nusendjmp == TRUE)
longjmp(nusendfail, 1);
#endif
#ifdef USE_USEND
if (i == SIGPIPE && usendjmp == TRUE)
longjmp(usendfail, 1);
#endif
if(i>SIGQUIT){
fprintf(stderr, "mail: error signal %d\n", i);
}else
fprintf(stderr, "\n");
if(delflg && (i==SIGINT || i==SIGQUIT))
longjmp(sjbuf, 1);
done();
}
/*
* clean up lock files and exit
*/
done()
{
unlock();
unlink(lettmp);
unlink(rmtbuf);
exit(error);
}
/*
* create mail lock file
* file -> lock file name
* returns:
* none
*/
lock(file)
char *file;
{
register int f, i;
if (locked == LOCKON)
return;
cat(curlock, file, maillock);
for (i=0; i<10; i++) {
if((f = creat(curlock, C_NOACCESS)) != CERROR){
close(f);
locked = LOCKON;
return;
}
sleep(2);
}
fprintf(stderr, "mail: %s not creatable after %d tries\n", curlock, i);
error = E_FILE;
done();
}
unlock()
{
unlink(curlock);
locked = LOCKOFF;
}
/*
* concatenate from1 and from2 to to
* to -> destination string
* from1 -> source string
* from2 -> source string
* return:
* none
*/
cat(to, from1, from2)
register char *to, *from1, *from2;
{
for (; *from1; )
*to++ = *from1++;
for (; *from2; )
*to++ = *from2++;
*to = '\0';
}
/*
* get next token
* p -> string to be searched
* s -> area to return token
* returns:
* p -> updated string pointer
* s -> token
* NULL -> no token
*/
char *getarg(s, p)
register char *s, *p;
{
while (*p == ' ' || *p == '\t')
p++;
if (*p == '\n' || *p == '\0')
return(NULL);
while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
*s++ = *p++;
*s = '\0';
return(p);
}
/*
* check existence of file
* file -> file to check
* returns:
* 0 -> exists unwriteable
* 1 -> exists writeable
* 2 -> does not exist
*/
legal(file)
register char *file;
{
register char *sp;
char dfile[MAXFILENAME];
/*
* If file does not exist then
* try "." if file name has no "/"
* For file names that have a "/", try check
* for existence of previous directory
*/
if(access(file, A_EXIST) == A_OK)
if(access(file, A_WRITE) == A_OK)
return(1);
else return(0);
else {
if((sp=strrchr(file, '/')) == NULL)
cat(dfile, ".", "");
else {
strncpy(dfile, file, sp - file);
dfile[sp - file] = '\0';
}
if(access(dfile, A_WRITE) == CERROR)
return(0);
return(2);
}
}
/*
* invok shell to execute command waiting for
* command to terminate
* s -> command string
* return:
* status -> command exit status
*/
system(s)
char *s;
{
register int pid, w;
int status;
int (*istat)(), (*qstat)();
/*
* Spawn the shell to execute command, however,
* since the mail command runs setgid mode
* reset the effective group id to the real
* group id so that the command does not
* acquire any special privileges
*/
if ((pid = fork()) == CHILD) {
setuid(getuid());
setgid(getgid());
execl("/bin/sh", "sh", "-c", s, NULL);
_exit(127);
}
/*
* Parent temporarily ignores signals so it
* will remain around for command to finish
*/
istat = signal(SIGINT, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
while ((w = wait(&status)) != pid && w != CERROR)
;
if (w == CERROR)
status = CERROR;
signal(SIGINT, istat);
signal(SIGQUIT, qstat);
return(status);
}