[alt.sources] watch.c - Trash the last copy...this one passed lint...Ooops.

cs00chs@unccvax.uncc.edu (charles spell) (10/17/90)

This seems to satisfy lint and the more picky compliers...ignore any warnings.
Trash last version....to compile: cc -o watch watch.c -lcurses.
--cut here--
/******************************************************************************
*  This program is freely distributable as long as there has been no changes
*  applied to this file. Bugs, comments, suggestions:uunet!mcnc!unccvax!cs00chs
*     If you find this program useful in part or in whole, please send a
*     contribution to John J. Ribera, Jr. If there is enough monetary interest,
*     fixes and upgrades will be available (see address below).
*/
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <utmp.h>
#include <time.h>
/******************************************************************************
* NAME
*     watch(1-att) - watch for mail, time, and users logging in (SystemV)
*
* SYNOPSIS
*     att watch [users...] [ttylines...] [&]
*
* DESCRIPTION
*     watch will notify the you if there is mail, when new mail arrives,
*     display the current time, and notify you of any user logging on or off
*     the system. On dual universe machines this program must be compiled and
*     run in the att universe. The terminal this is run on must have the tsl=
*     and fsl= capabilities to work properly. It helps if ws# is in terminfo
*     also. tsl= is the sequence to go to the status line, fsl= is the
*     sequence to return from status line (cursor position should be restored
*     by this sequence). ws# should be the maximum number of characters that
*     can be displayed on the status line. See your terminal reference manual
*     for these values (and TERMINFO(5) on how to apply them).
*
*     If there are users and/or ttylines specified on the command line, only
*     those users and/or lines will be checked for logins/logouts, otherwise
*     ANY login/logout will be displayed.
*     To disable watch and clear the status line, use:
*            kill <pid>
*     where <pid> is the process id of the watch program. Do not kill
*     watch(1-att) with a -9 value, i.e., the status line will not be cleared.
*
* EXAMPLES
*     watch &
*        - this watches for all users logging in or out of the system.
*
*     watch jjr smith tty01 tty03 &
*        - this will watch for users with 'jjr' and 'smith' as well as those
*          logging in tty01 and tty03.
*
* WARNINGS
*     Be sure to run watch(1) with an att preceeding the watch command on dual
*     universe systems. Be careful not to run watch in the backround more than
*     once.  To compile type: cc watch.c -o watch -ltermlib (the att universe
*     on dual universe machines).
*
* BUGS
*     Most of the time you will want to execute watch in the backround. The
*     logout seems to be closing the tty faster than the clear status line
*     sequence can be sent in some cases.
*     Try putting this in your .logout: sleep 2
*
* AUTHOR
*
*     clt2!jjr
*     John J. Ribera Jr.
*     9505-J University Terrace Drive
*     Charlotte, NC 28262
*     Voice: (704) 549-5571
*
*     If you find this program useful in part or in whole, please send a
*     contribution to John J. Ribera, Jr. If there is enough monetary interest,
*     fixes and upgrades will be available.
*/

#define MAX_PORT    512
#define UTMP        "/etc/utmp"
#define ST_MAIL     0
#define ST_DATE     9
#define ST_LOGIN    26
#define ST_WIDTH    37
#define MAIL_DIR    "/usr/spool/mail"

#define MAIL        "    MAIL"
#define NEW_MAIL    "NEW MAIL"
#define CLR_MAIL    "        "

char    watchfor[2048];
char    St_line[256];
char    Termb[1024];
char    Ts[80];
char    Fs[80];
short   Ws;
char    *tgetstr();
int     tgetent();
int     tgetnum();
int     tputs();

main(argc, argv)
int     argc;
char    **argv;
{
struct  utmp    curr[MAX_PORT + 1];
struct  utmp    last[MAX_PORT + 1];
struct  stat    statb, save_mail;
        long    last_mtime;
        long    last_time;
        char    mailfile[256];
        char    *login;
        char    *strcpy();
        char    *getenv();
        char    *getlogin();
        char    *ctime();
        char    *memcpy();
        char    *strstr();
        char    *strcat();
        char    *gettstr();
        char    **getpwuid();
        short   i, j, k, l;
        short   watchcnt;
        short   read_utmp();
        int     memcmp();
        void    disp_utmp();
        void    disp_chng();
        void    disp_stat();
        void    done();

signal(SIGINT, done);
signal(SIGQUIT, done);
signal(SIGTERM, done);
signal(SIGHUP, done);
for (watchfor[0] = '\0', watchcnt = --argc; argc; --argc)
    strcat(strcat(watchfor, *++argv), " ");
/* Initialize termcaps for going to/from status line and intensity  */
if (tgetent(Termb, getenv("TERM")) != 1)
    fprintf(stderr, "\nUnable to find terminfo data"), exit(1);
if (!*strcpy(Ts, gettstr("tsl")) || !*strcpy(Fs, gettstr("fsl")))
    fprintf(stderr, "\nNeed status line caps - tsl=, and fsl=."), exit(1);
if ((Ws = tgetnum("ws")) == -1 && (Ws = tgetnum("co")) == -1)
    Ws = 80;
/* Initialize everything for loop below...get current utmp entries  */
sprintf(St_line, "%-*.*s", Ws, Ws, "");
last_time = time((long *) 0);
memcpy(&St_line[ST_DATE], ctime(&last_time), 16);
disp_stat(St_line);
if ((login = getenv("LOGNAME")) == NULL && (login = getenv("USER")) == NULL &&
    (login = getlogin()) == NULL && !*(login = *getpwuid(getuid())))
    fprintf(stderr, "\nUnable to find you"), exit(1);
sprintf(mailfile, "%s/%s", MAIL_DIR, login);
l = read_utmp(last);
if (stat(UTMP, &statb) < 0)
    fprintf(stderr, "\nUnable to stat utmp file."), exit(1);

for (last_mtime = statb.st_mtime; stat(UTMP, &statb) == 0; sleep(1))
    {
    if (statb.st_mtime > last_mtime)
        {
        last_mtime = statb.st_mtime;
        for (i = k = read_utmp(curr); i; i--)
            for (j = l; j; j--)
                if (!watchcnt ||
                    (strstr(watchfor, curr[i-1].ut_line) ||
                     strstr(watchfor, curr[i-1].ut_user) ||
                     strstr(watchfor, last[j-1].ut_line) ||
                     strstr(watchfor, last[j-1].ut_user)))
                     if (!strcmp(curr[i-1].ut_line, last[j-1].ut_line))
                        if (last[j-1].ut_type != curr[i-1].ut_type)
                            disp_chng(&last[j-1], &curr[j-1]);
        memcpy(last, curr, sizeof(curr));
        l = k;
        }
    if ((last_time / 60) != (time((long *) 0) / 60))
        {
        if (!((last_time = time((long *) 0)) % 3600))
            putchar('\007');
        memcpy(&St_line[ST_DATE], ctime(&last_time), 16);
        disp_stat(St_line);
        }
    if (stat(mailfile, &statb) != 0)
        fprintf(stderr, "Unable to stat %s", mailfile), exit(1);
    if (memcmp(&save_mail, &statb, sizeof(statb)))
        {
        memcpy(&St_line[ST_MAIL], CLR_MAIL, strlen(CLR_MAIL));
        disp_stat(St_line);
        if (statb.st_mtime >= statb.st_atime && statb.st_size > 1)
            {
            memcpy(&St_line[ST_MAIL], NEW_MAIL, strlen(NEW_MAIL));
            putchar('\007');
            }
        else if (statb.st_size > 1)
            memcpy(&St_line[ST_MAIL], MAIL, strlen(MAIL));
        disp_stat(St_line);
        memcpy(&save_mail, &statb, sizeof(statb));
        }
    if (getppid() == 1)
        done();
    }
return(0);
}

void
disp_chng(last, curr)
struct  utmp    *last;
struct  utmp    *curr;
{
if (last->ut_type != USER_PROCESS && curr->ut_type == USER_PROCESS)
    sprintf(&St_line[ST_LOGIN], "%-8.8s on %s", curr->ut_user, curr->ut_line);
if (last->ut_type == USER_PROCESS && curr->ut_type != USER_PROCESS)
    sprintf(&St_line[ST_LOGIN], "%-8.8s off %s", last->ut_user, last->ut_line);
memcpy(last, curr, sizeof(*last));
disp_stat(St_line);
}

void
disp_stat(stat_line)
char    *stat_line;
{
    int     outc();
    char    hold[256];

tputs(Ts, 1, outc);
strcpy(hold, stat_line);
sprintf(stat_line, "%-*.*s", Ws-1, Ws-1, hold);
fwrite(stat_line, strlen(stat_line), 1, stdout);
tputs(Fs, 1, outc);
fflush(stdout);
}

short
read_utmp(utmps)
struct  utmp    *utmps;
{
        FILE    *fp;
        short   i;

if ((fp = fopen(UTMP, "r")) == (FILE *) NULL)
    fprintf(stderr, "\nUnable to read utmp file."), (void)exit(1);
i = (short) fread(utmps, sizeof(*utmps), MAX_PORT, fp);
fclose(fp);
return(i);
}

void
done()
{
disp_stat("");
exit(0);
}

char    *
gettstr(id)
char    *id;
{
static  char    tstr[256];
        char    *ptr;

ptr = tstr;
strcpy(tstr, tgetstr(id, &ptr));
if (ptr == tstr)
    *tstr = '\0';
return(tstr);
}

int
outc(c)
char    c;
{
fwrite(&c, 1, 1, stdout);
}
--cut here--
-- 
 .--------------------------.  ...  |On the border of your mind lies a place
 |uunet!mcnc!unccvax!cs00chs|  (")  |where dreams and reality are one...I will 
 `--------------------------'-w-U-w-|take you there, for I am the subject...
 \%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\%\|the subject of your imagination. -Aldo Nova