/*
 *
 * This program is not related to David Wall, whose Stanford Ph.D. thesis
 * is entitled "Mechanisms for Broadcast and Selective Broadcast".
 */

#include <stdio.h>
#include <utmp.h>
#include <time.h>
#include <utsname.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>

char	*strcpy(), *strncpy();
char	*strcat(), *strncat();
long	time();
struct tm *localtime();

main()
{
	register int c;
	register char *p;
	struct utmp utmp;
	struct tm *tm;
	long clock;
	FILE *f;
	char *who, *mytty;
	struct utsname node;
	char mesg[3000];
	char *getlogin(), *ttyname();
	long time();
	struct tm *localtime();

	if((f = fopen("/etc/utmp", "r")) == NULL) {
		fprintf(stderr, "Cannot open /etc/utmp\n");
		exit(1);
	}
	if ((who = getlogin()) == NULL)
		who = "greg";
	if ((mytty = ttyname(2)) == NULL)
		mytty = "???";
	else if (strncmp(mytty, "/dev/", 5) == 0)
		mytty += 5;		/* for prettiness */
	uname(&node);
	clock = time((long *)0);
	tm = localtime(&clock);
	sprintf(mesg,  "\nBroadcast Message from %s!%s (%s) at %d:%02d ...\r\n",
		node.nodename, who, mytty, tm->tm_hour, tm->tm_min);
	p = &mesg[strlen(mesg)];
	while((c = getchar()) != EOF) {
		if (p >= &mesg[sizeof(mesg)]) {
			fprintf(stderr, "Message too long\n");
			exit(1);
		}
		if (c == '\n')
			*p++ = '\r';
		*p++ = c;
	}
	while (fread((char *)&utmp, sizeof(utmp), 1, f) == 1) {
		if (utmp.ut_name[0] == 0)
			continue;
		/* reject people not really logged in */
		for (c = 0; c < sizeof(utmp.ut_name); c++)
			if (utmp.ut_name[c] == '*')
				break;
		if (c < sizeof(utmp.ut_name))
			continue;
		sendmes(utmp.ut_line, sizeof(utmp.ut_line), mesg, p - mesg);
	}
	exit(0);
}

sendmes(tty, len, mesg, mlen)
char *tty, *mesg;
int len, mlen;
{
	int i;
	char t[50];
	int fd;

	while ((i = fork()) == -1)
		if (wait((int *)0) == -1) {
			fprintf(stderr, "Try again\n");
			return;
		}
	if(i)
		return;
	sprintf(t, "/dev/%.*s", len, tty);
	if (ckmode(t) == 0)
		exit(0);
	signal(SIGALRM, SIG_DFL);	/* blow away if open hangs */
	alarm(10);
	if((fd = open(t, 1)) < 0) {
		fprintf(stderr,"cannot open %s\n", t);
		exit(1);
	}
	write(fd, mesg, mlen);
	close(fd);

	/*
	 * Bitchin'.
	 */

	exit(0);
}

/*
 * don't write on ttys whose mode is 0
 * hack to prevent hanging ndcon
 */

ckmode(tty)
char *tty;
{
	struct stat sb;

	if (stat(tty, &sb) < 0)
		return (1);	/* eh? */
	if (sb.st_mode & ~S_IFMT)
		return (1);
	return (0);
}
