/* mail command usage
	mail
		prints your mail
	mail people
		sends standard input to people
 */
/*
 * patched 3/2/82 routine setpw() will now recognize the fact
 *	that it could not open /etc/passwd (if that should ever
 *	come to pass).
 */

/* patched 9/6/79 for group-id in passwd file by HY. */

/* modified  4/22/80 by HY
  1) uses /etc/forwardings file:
     source:comment:target,target,!no-recurse-target,...
  2) expects to run priviledged but does not create mailboxes
  3) if sender has no mailbox, one is optionally created for him.
  4) deadsv() not run until end
  5) recipient must own his mailbox.
*/

/* patched by HY --
  1) -Z flag makes mail run unpriviledged and not use /etc/forwardings
  2) mail will not send if sender is tty? (no controlling tty) AND
     /etc/forwardings entry contains more than one reference
  3) mail will by default never send (indirectly) to sender, unless -s option
Note: -Z flag MUST precede -s flag if both are specified
*/

/* patched by HY --
1) mailbox automatically created for recipient mode 600 if necessary
2) mailbox recipient must have execute bit (0100) OFF to receive mail
3) -c option adds cc-list to end of mail. name passed before -c
   option (from command string) will not be on (or have) this cc-list
*/

#include	"stdio.h"
#include	<sys/types.h>
#include <sys/stat.h>
#include	"pwd.h"
#include	"hsubs.h"
#define RECUR 10
#define SIGINT  2

char **xargv;
char	myname[14];
int xargc;
int	superu = 0;
char    lettmp[] "/tmp/maXXXXX";
FILE    *pwfil;
FILE    *mfil;
FILE *frdfil;
FILE *ufrdfil;
long    msiz;
int priv = 1;
long    ftell(), prlet();
char    *cat(), *whoami();
extern  delexit();

int saved = 0;
int dead = 0;
int nomeflg = 1;

int recsave[3];
char hdline[64];
char toline[512];
char ufdfile[64];
char line[512];
char *whereto;
int hy3;
char rmtmsg[64];

main(argc, argv)
char **argv;
{
	char y;
	char plugh[64];

	superu = getgid();
	superu = (superu == 0)|(superu == 2)|(superu == 3);
	mktemp(lettmp);
	if(argv[0][0] != 'r' && (argc == 1 || (argv[1][0] == '-' &&
		(argc == 2 || argc == 3) && argv[1][1] == 'f'))) {
		resetme();
		printmail(argc, argv);
		delexit();
	}
	if (signal(SIGINT,1) == 0)
		signal(SIGINT, delexit);
	if ((mfil = fopen(lettmp, "w")) == NULL) {
		fprintf(stderr, "Cannot create temporary\n");
		delexit();
	}
	chmod (lettmp, 0600);
	if ((argv[1][0] == '-') && (argv[1][1] == 'Z') && (argv[1][2] == 0)) {
		frdfil = NULL;
		argv++;
		argc--;
		resetme();
	} else {
		frdfil = fopen("/etc/forwardings", "r");
		if (frdfil == NULL)
			fprintf(stderr,"Warning: no forwardings file.\n");
		cat(ufdfile, logdir(), "/.forwardings");
		ufrdfil = fopen(ufdfile, "r");
	}
	if ((argv[1][0] == '-') && (argv[1][1] == 's') && (argv[1][2] == 0)) {

		argv++;
		argc--;
		nomeflg = 0;
	}
	if (argc <= 1) {
		fprintf(stderr,"No recipients specified.\n");
		delexit();
	}
	bulkmail( argc, argv, whoami() );
	cat(plugh, logdir(), "/.mail");
	if((stat(plugh, &toline) < 0) && isatty(0)){
		fprintf(stderr,"You have no mailbox. Create one? ");
		fflush(stderr);
		y = getchar();
		if (y != '\n')
			while (getchar() != '\n');
		if (y == 'y') {
			resetme();
			close(creat(plugh,0600));
		}
	}
	delexit();
}

char *
whoami(){
	return(logname());
}

printmail(argc, argv)
char **argv;
{
	register c;
	register char *my_ldir;
	char mail[100], mbox[100];

	if( argc==3 ){
		cat( mail, argv[2], "" );
		cat( mbox, "", "" );
		if ((mfil=fopen(mail,"r")) == NULL) {
			fprintf(stderr, "Can't open %s\n", mail);
			return;
			}
		}
	else {
		cat( mail, ".mail", "" );
		cat( mbox, "mbox", "" );
		if( (mfil=fopen(mail, "r")) == NULL ){
			my_ldir = logdir();
			cat( mail, my_ldir, "/.mail" );
			cat( mbox, my_ldir, "/mbox" );
			mfil = fopen( mail, "r" );
			}
		}
	if (mfil!=NULL && getc(mfil)>=0) {
		fseek( mfil, 0L, 0 );
		prlet();
		c = 'y';
		if (argc<2) {
			if(isatty(0)){
				fprintf(stderr, "Save? ");
				fflush(stderr);
				c = getchar();
			}
		} else
			c = argv[1][1];
		if ((c != 'n') && (c != 'f')) {
			if( *mbox == '\0' || !append(mbox,0) ){
				fprintf( stderr, "cannot append; didn't destroy\n" );
				return;
				}
			}
		fseek(mfil,0L,2);
		if(ftell(mfil) > msiz) {
			fprintf( stderr, "More mail has arrived: nothing done\n" );
			return;
		}
		if(argc<=2)
			fclose(fopen(mail, "w"));
	} else
		fprintf(stderr, "No mail\n");
}

long
prlet()
{
	long beg, end;
	register flag;

	flag = 1;
	beg = ftell( mfil );
	for(;;) {
		switch(getc(mfil)) {
		case EOF:
			msiz = beg+1;
			return( msiz+1 );
		case '\n':
			if(flag==8) {
				end = prlet();
				goto brk1;
			}
			flag = 1;
			beg = ftell(mfil);
			continue;
		case 'F':
			if(flag!=1)
				goto dflt;
			break;
		case 'r':
			if(flag!=2)
				goto dflt;
			break;
		case 'o':
			if(flag!=3)
				goto dflt;
			break;
		case 'm':
			if(flag!=4)
				goto dflt;
			break;
		case ' ':
			if(flag!=5)
				goto dflt;
			break;
		case ':':
			if(flag>5)
				break;
		default:
		dflt:
			if(flag<=5)
				flag = 0;
			continue;
		}
		flag++;
	}

/*      plausible postmark found
 *      (line beginning with "From " and containig 2 :'s
*/
brk1:
	fseek(mfil, beg, 0);
	while( beg<end-- && (flag=getc(mfil))>=0 ) putchar(flag);
	return( beg );
}

bulkmail(argc, argv, from)
char **argv, *from;
{
	long tbuf;
	register c;
	register char *a, *b;

	time(&tbuf);
	sprintf(hdline,"From %s %s",from,ctime(&tbuf));
	line[0] = '>';
	while (fgets(line+1, 128, stdin) != NULL) {
		if (line[1]=='.' && line[2]=='\n')
			break;
		if(strncmp(line+1, "From", 4) == 0)
			fputs(line, mfil);
		else
			fputs(line+1, mfil);
	}
	putc('\n', mfil);
	fclose(mfil);
	if( (mfil=fopen(lettmp, "r")) == NULL ){
		fprintf( stderr, "horrible mail problem: goodbye\n" );
		delexit();
		}
	while (--argc > 0) {
		argv++;
		if ((argv[0][0] == '-') && (argv[0][1] == 'c') && (argv[0][2] == 0)) {
			if (xargv)
				continue;
			xargv = ++argv;
			xargc = argc;
			argc--;
			if (argc < 1) {
				fprintf(stderr,"No recipients specified for cc-list.\n");
				delexit();
			}
			b = line;
			while (--xargc > 0) {
				if (xargv == argv)
					a = "cc: ";
				else
					a = "    ";
				while (*b++ = *a++);
				b--;
				a = *xargv++;
				while (*b++ = *a++);
				b--;
				*b++ = '\n';
			}
			*b++ = '\n';
			*b = 0;
		}
		sendto(*argv);
	}
}

sendto(person)
char *person;
{
	register char *a;
	register char *b;
	whereto = toline;
	hy3 = 0;
	switch(doent(person, 0, ufrdfil)){
	case 0:
		switch(doent(person, 0, frdfil)){
		case 0:
			add(person);
			break;
		case 1:
			return;
		case 2:
			break;
		}
		break;
	case 1:
		return;
	case 2:
		break;
	}
	{ int test;
		test = open("/dev/tty",0);
		if ((test == -1) && (hy3 > 2)) {
			dead++;
			return;
		}
		close(test);
	}
	*whereto++ = ')';
	*whereto = 0;
	b = a = toline;
	while (*a) {
		if ((*a != ')') && (*a != '(') && (*a != ',')) {
			a++;
			continue;
		}
		if (*a != '(')
			realout(b,a);
		while ((*a == ')') || (*a == '(') || (*a == ','))
			a++;
		b = a;
	}
}

realout(from,to)
char *from;
char *to;
{
	register struct passwd *p;
	char target[100];
	char x;
	struct stat statb;
	int y;
	int z;

	x = *to;
	*to = 0;
	if ((nomeflg) && (hy3 > 1))
		if (equal(from,whoami())) {
			*to = x;
			return;
		}
	if(strchr(from, '!')){
		sendrmt(from);
		return;
	}
	while(p = getpent(from)){
		*to = x;
		cat(target,p->pw_dir,"/.mail");
		if (stat(target,&statb) < 0) {
			if ((z = creat(target, 0600)) < 0) {
				*to = 0;
				break;
			}
			/* hope for no interrupt RIGHT HERE */
			chown(target, p->pw_uid, p->pw_gid);
			close(z);
		} else
			if (priv)
				if ((statb.st_uid != p->pw_uid) ||
				    ((statb.st_mode&0200) == 0)) {
					*to = 0;
					break;
				}
			if (append(target,1)==0) {
				*to = 0;
			break;
		}
		*to = 0;
		*to = x;
		return;
	}
	dead++;
	if (hy3 <= 1)
		fprintf(stderr, "Can't send to %s\n", from);
	else
		fprintf(stderr,"Invalid forwarding reference: %s\n",from);
	*to = x;
}


deadsv()
{
	char v[100];
	char c;
	if(isatty(0) && saved == 0){
		saved++;
		if(dead == 1)
			fprintf(stderr,"1 error -- save letter? ");
		else
			fprintf(stderr,"%d errors -- save letter? ",dead);
		fflush(stderr);
		c = getchar();
		if (c != '\n')
			while (getchar() != '\n');
		if (c != 'n'){
			cat(toline,"????????)","");
			cat(v,logdir(),"/dead.letters");
			resetme();
			if (append(v,2))
				fprintf(stderr, "Letter appended to %s\n",v);
			else
				fprintf(stderr,"Can't\n");
			}

		}
}
append(to,flag) /* flag is on if headline/toline is to be written */
char *to;
int flag;
{
	register FILE *pf;
	register c;
	register char *a;

	if ((pf = fopen(to, "a")) == NULL)
		return(0);
	fseek( mfil, 0L, 0 );
	if (flag)
		fprintf(pf,"%s(To: %s\n",hdline,toline);
	while ((c = getc(mfil)) >= 0)
		putc(c, pf);
	if ((xargv) && (flag == 1)) {
		a = line;
		while (*a)
			putc(*a++, pf);
	}
	fclose(pf);
	return(1);
}

getpent(n)
char *n;
{
	register char *p;
	register c;
	static struct passwd passwd;
	static char xline[200];

	if(getent(HFILE, n, xline) < 0)
		return(0);
	p = xline;
	passwd.pw_name = p;
	p = pwskip(p);
	passwd.pw_passwd = p;
	p = pwskip(p);
	passwd.pw_uid = atoi(p);
	p = pwskip(p);
	passwd.pw_gid = atoi(p);
	p = pwskip(p);
	passwd.pw_gecos = p;
	p = pwskip(p);
	passwd.pw_dir = p;
	p = pwskip(p);
	passwd.pw_shell = p;
	return(&passwd);
}

pwskip(ap)
char *ap;
{
	register char *p;

	p = ap;
	while(*p != ':') {
		if(*p == 0)
			return(p);
		p++;
	}
	*p++ = 0;
	return(p);
}

delexit()
{
	if (dead)
		deadsv();
	unlink(lettmp);
	exit(dead);
}

equal(as1, as2)
{
	register char *s1, *s2;

	s1 = as1;
	s2 = as2;
	while (*s1++ == *s2)
		if (*s2++ == 0)
			return(1);
	return(0);
}

char *
cat( target, ap1, ap2)
char *target, *ap1, *ap2;
{
	register char *p1, *p2;
	p1 = ap1;
	p2 = target;
	while (*p2++ = *p1++);
	p2--;
	p1 = ap2;
	while (*p2++ = *p1++);
	return(target);
}

doent(c, n, fp)

FILE *fp;
char *c;
int n;
{
	char fbuf[512];
	char *fmax;
	register char *cp;
	register char *cp1;
	register char *cp2;
	if (n == 0) {
		if (setjmp(recsave)) {
			fprintf(stderr,"Recursive forwarding entry: %s\n",c);
			dead++;
			return(1);
		}
	}
	if ( n > RECUR ) {
		longjmp(recsave);
		abort(); /* should never get here..... */
	}
	if (fp == NULL)
		return(0);
	rewind(fp);
	fmax = &fbuf[511];
next:   cp = fbuf;
	do {
		if ((*cp = getc(fp)) <= 0)
			return(0);
	} while (*cp++ != '\n' && cp < fmax);
	if(cp >= fmax){
		fprintf(stderr, "mail: Forwardings entry too long: %s\n", fbuf);
		return(0);
	}
	*cp = 0;
	cp2 = fbuf;
	cp1 = c;
	do {
		if (*cp1++ != *cp2++)
			goto next;
	} while (*cp2 != ':');
	if (*cp1)
		goto next;
	do {
		cp2++;
	} while(*cp2 != ':' && *cp2 != '\n');
	if(*cp2 == '\n'){
		fprintf(stderr, "mail: Invalid forwardings entry: %s", fbuf);
		return(0);
	}
	if(fp == frdfil && cp2[1] == '/')
		if(getlist(cp2+1, 510 - (cp2 - fbuf)) == 0)
			return(0);
	add(c);
	*whereto++ = '(';
again:  cp2++;
	cp1 = cp2;
	while ((*cp2 != ',') && (*cp2 != '\n'))
		cp2++;
	if (*cp2 == '\n') {
		*cp2 = 0;
		cp2 = 0;
	} else
		*cp2 = 0;
	if (*cp1 == '!')
		add(++cp1);
	else {
		switch(doent(cp1, n+1, ufrdfil)){
		case 0:
			if(doent(cp1, n+1, frdfil) != 2)
				add(cp1);
			break;

		case 1:
			add(cp1);
			break;

		case 2:
			break;
		}
	}
	if (cp2) {
		*whereto++ = ',';
		goto again;
	}
	*whereto++ = ')';
	return(2);
}

add(c)
register char *c;
{
	hy3++;
	while (*c)
		*whereto++ = *c++;
}

resetme()
{
	setgid(getgid());
	setuid(getuid());
	priv = 0;
}


getlist(f, l)
char *f;
{
	register FILE *fp;
	register char *s;

	s = f;
	while(*s && *s != '\n')s++;
	if(*s == '\n')*s = 0;
	if((fp = fopen(f, "r")) == NULL){
		fprintf(stderr, "mail: Invalid forwarding file: %s\n", f);
		return(NULL);
	}
	s = f;
	*s = '\n';
	s[1] = 0;
	if(fgets(s, l, fp) != NULL){
		while(*s)s++;
		if(s[-1] != '\n'){
			*s++ = '\n';
			*s = 0;
		}
	}
	fclose(fp);
	return(1);
}

sendrmt(name)
char *name;
{
	register char *p;
	char rsys[64], cmd[64];
	register local, pid;
	int sts;
	int w;
	int	pv[2];

	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')) {
		printf("Null name in remote mail address\n");
		return(0);
	}
	if ((pid = fork()) == -1) {
		printf("mail: can not create proc for remote\n");
		return(0);
	}
	if (pid) {
		while (wait(&sts) != pid) {
			if (wait(&sts)==-1)
				return(0);
		}
		return(!sts);
	}
	setgid(getgid());
	if (local){
		printf("mail: local mail not permitted through these channels\n");
		return(0);
	}
	if (strchr(name+1, '!'))
		sprintf(cmd, "uux - %s!rmail \\(%s\\)", rsys, name+1);
	else	{
		sprintf(cmd, "uux - %s!rmail %s", rsys, name+1);
		uucpname(myname);
		sprintf(rmtmsg, " remote from %s\n", myname);
	}
	if(pipe(pv) < 0){
		printf("Cant open pipe for remote\n");
		exit(1);
	}
	if((pid = fork()) == -1){
		printf("mail: cant fork for uux execution\n");
		exit(2);
	}
	if(pid){
		w = dup(1);
		close(1);
		dup(pv[1]);
		close(pv[0]);
		close(pv[1]);
		copylet(name); /* closes 1 for us */
		dup(w);
		while((w = wait(&sts)) != pid && w != -1);
		exit(0);
	}
	close(0);
	dup(pv[0]);
	close(pv[0]);
	close(pv[1]);
	execl("/bin/sh", "sh", "-c", cmd, 0);
	printf("mail: can not execute '%s'\n", cmd);
	exit(1);
}



copylet(n)
char *n;
{
	register int mfd, r;
	register char *s;
	static char cbuf[512];
	char flag;
	if((mfd = open(lettmp, 0)) == -1){
		printf("mail: %s (the letter) has gone away.\n", lettmp);
		exit(5);
	}

	for(s = hdline; *s && *s != '\n'; s++);
	r = *s;
	*s = 0;
	sprintf(cbuf, ">%s%sTo: %s\n", hdline, rmtmsg, n);
	*s = r;
	write(1, cbuf, strlen(cbuf));
	while((r = read(mfd, cbuf, 512)) > 0){
		write(1, cbuf, r);
	}
	close(1);
	close(mfd);
	return;
}

