/*
 *  Copyright (c) 2000 David Parsons. All rights reserved.
 *
 *  This software is released under a berkeley-style copyright; the
 *  details can be found in the file COPYRIGHT.
 */

/*
 * (5 lines -- the code that picks out active users from utmp --
 *  is from the OpenBSD who program.  So it falls under this copyright):
 *
 * Copyright (c) 1989, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Michael Fischbein.
 *
 * 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.
 */

/*
 * wall() writes messages to every user
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <pwd.h>
#include <utmp.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <malloc.h>
#include <stdarg.h>

wall(char *mesg)
{
    int utmpf, mesgf;
    struct utmp usr;
    char line[80];
#define HSIZ	200
    char hdr[HSIZ];
    int used, s;
    char *p, *q;
    struct iovec message[4];
    struct passwd *pwd;
    time_t now;
    int hasnl = 0;
    int len;


    if ( (utmpf = open(_PATH_UTMP, O_RDONLY)) == -1) {
	error("can't open " _PATH_UTMP ": %s", strerror(errno));
	return;
    }

    /* assert that |this fixed string| < HSIZ */
    used = snprintf(hdr, HSIZ, "\007\r\nBroadcast message "); 

    if ( (pwd = getpwuid(getuid())) != 0) {
	s = snprintf(hdr+used, HSIZ-used, "from %s", pwd->pw_name);

	if (s != -1) {
	    used += s;
	    if ( (p = ttyname(0)) != 0)
		if ( (s = snprintf(hdr+used, HSIZ-used, " (%s)", p)) != -1)
		    used += s;
	    time(&now);
	    p = ctime(&now);
	    strtok(p, "\n");
	    if ( (s = snprintf(hdr+used, HSIZ-used, " %s", p)) != -1)
		used += s;
	}
    }

    len = strlen(mesg);
    hasnl = (len > 0 && mesg[len-1] == '\n');

    message[0].iov_base = hdr;
    message[0].iov_len  = used;
    message[1].iov_base = "\r\n";
    message[1].iov_len  = 2;
    message[2].iov_base = mesg;
    message[2].iov_len  = len;
    message[3].iov_base = "\r\n\r\n";
    message[3].iov_len  = hasnl ? 2 : 4;

    while (read(utmpf, &usr, sizeof usr) == sizeof usr) {
	/* OpenBSD code begins here */
	if (*usr.ut_name
# ifdef USER_PROCESS
		&& usr.ut_type == USER_PROCESS
# endif
		&& *usr.ut_line) {
	/* OpenBSD code ends here */

	    if (snprintf(line, sizeof line, "/dev/%s", usr.ut_line) == -1)
		continue;

	    if ( (mesgf = open(line, O_WRONLY|O_NDELAY)) >= 0) {
		writev(mesgf, message, sizeof message/sizeof message[0]);
		close(mesgf);
	    }
	}
    }
    close(utmpf);
} /* wall */
