/*
 * Copyright (c) 1987 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1987 Regents of the University of California.\n\
 All rights reserved.\n";
#endif /* not lint */

static char *sccsid = "@(#)mesg.c	4.2 (Berkeley) 10/18/80";
/*
 * mesg -- set current tty to accept or
 *	forbid write permission.
 *
 *	mesg [yn] "answerback message"
 *		y allow messages
 *		n forbid messages
 *		answerback is what the other guy gets told (Waterloo)
 *		needs to be setuid root to get rid of other people's
 *		old answerback message files
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <utmp.h>
#include <pwd.h>

#define ANSWERBACK_FMT	"/usr/tmp/mesg.%s"

main(argc, argv)
	char **argv;
{
	int uid, mode, r=0;
	char *tty, *p, *rindex(), *ttyname();
	FILE *fp;
	int i_own_answerback = 0;
	struct stat sbuf;
	struct passwd *pw;
	char answerback[200];

	(void) umask(022);	/* so we can read answerback file */
	tty = ttyname(2);
	if (tty == 0)
		error("Cannot determine name of current terminal", (char *)0);
	if ( (p=rindex(tty,'/')) != NULL )
		p++;
	else
		p = tty;
	/*
	 * If this isn't a login session, use of mesg is meaningless.
	 */
	uid = getuid();
	pw = getpwuid(uid);
	if (pw == NULL) {
		fprintf(stderr, "mesg: Can't find your uid (%d) in the password file\n", uid);
		exit(2);
	}
	if (!in_utmp(pw->pw_name, p)) {
		fprintf(stderr, "mesg: Current terminal session on %s is not a login session\n", tty);
		exit(2);
	}
	/* find name of answerback file */
	(void) sprintf( answerback, ANSWERBACK_FMT, p );
	/* Now make sure that if the answerback file exists, it belongs to
	   the current user */
	if ( lstat( answerback, &sbuf ) == 0 ) {
		if (sbuf.st_uid == uid)
			i_own_answerback = 1;
		else
			(void) unlink(answerback);
	}
	if(stat(tty, &sbuf) < 0) error("cannot stat", tty);
	/*
	 * must be root before here so we can get rid of other persons
	 * answerback file since sticky bit is on tmp directory.
	 * must be real user after here so he cant read/write *any* file
	 * by creating a link in the tmp directory.
	 */
	setuid(uid);
	if(argc < 2) {
		if(sbuf.st_mode & 020)
			printf( "is y\n" );
		else {	r=1;
			printf( "is n\n" );
		}
		if (i_own_answerback) {
			if ( (fp=fopen(answerback,"r")) != NULL ) {
				int c;
				while ( (c=getc(fp)) != EOF )
					putc( c, stdout );
				(void) fclose( fp );
			} else
				error("Can't read answerback file", answerback);
		}
	} else {
		if (i_own_answerback)
			(void) unlink(answerback);
		if ( argv[1][0] == 'y' ) {
			mode = sbuf.st_mode | 020;
		} else if ( argv[1][0] == 'n' ) {
			mode = sbuf.st_mode & ~022;
			r = 1;
		} else
			error("usage: mesg [yn] [answerback message]", (char *)0);
		if (chmod(tty, mode) < 0)
			error("cannot change modes", tty);
		if ( argc > 2 ) {	/* write answerback message */
			int i;
			if ( (fp=fopen(answerback,"w")) == (FILE *)NULL )
				error("Couldn't write answerback file", answerback);
			for ( i=2; i<argc; i++ ) {
				if ( i>2 )
					putc( ' ', fp );
				fputs( argv[i], fp );
			}
			putc( '\n', fp );
			(void) fclose( fp );
		}
	}
	exit(r);
}

error(s, arg)
char *s, *arg;
{
	fprintf(stderr,"mesg: %s", s);
	if (arg)
		perror(arg);
	else
		putc('\n', stderr);
	exit(2);
}

/*
 * Does the given (user,tty) pair appear in the utmp file?
 */
in_utmp(user, tty)
	char *user, *tty;
{
	FILE *fp;
	struct utmp utmp;

	if ((fp = fopen("/etc/utmp", "r")) == NULL)
		return 0;
	while (fread((char *)&utmp, sizeof utmp, 1, fp) == 1) {
		if (strncmp(user, utmp.ut_name, sizeof utmp.ut_name) == 0 &&
		    strncmp(tty, utmp.ut_line, sizeof utmp.ut_line) == 0) {
#ifdef USER_PROCESS
			if ( utmp.ut_type != USER_PROCESS )
				continue;
#endif
			fclose(fp);
			return 1;
		}
	}
	fclose(fp);
	return 0;
}
