tc.who.c revision 232633
11590Srgrimes/* $Header: /p/tcsh/cvsroot/tcsh/tc.who.c,v 3.57 2012/01/17 20:53:38 christos Exp $ */
21590Srgrimes/*
31590Srgrimes * tc.who.c: Watch logins and logouts...
41590Srgrimes */
51590Srgrimes/*-
61590Srgrimes * Copyright (c) 1980, 1991 The Regents of the University of California.
71590Srgrimes * All rights reserved.
81590Srgrimes *
91590Srgrimes * Redistribution and use in source and binary forms, with or without
101590Srgrimes * modification, are permitted provided that the following conditions
111590Srgrimes * are met:
121590Srgrimes * 1. Redistributions of source code must retain the above copyright
131590Srgrimes *    notice, this list of conditions and the following disclaimer.
141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151590Srgrimes *    notice, this list of conditions and the following disclaimer in the
161590Srgrimes *    documentation and/or other materials provided with the distribution.
171590Srgrimes * 3. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes#include "sh.h"
341590Srgrimes
3574769SmikehRCSID("$tcsh: tc.who.c,v 3.57 2012/01/17 20:53:38 christos Exp $")
361590Srgrimes
3774769Smikeh#include "tc.h"
3874769Smikeh
3974769Smikeh#ifndef HAVENOUTMP
401590Srgrimes/*
411590Srgrimes * kfk 26 Jan 1984 - for login watch functions.
421590Srgrimes */
431590Srgrimes#include <ctype.h>
441590Srgrimes
451590Srgrimes#ifdef HAVE_UTMPX_H
461590Srgrimes# include <utmpx.h>
471590Srgrimes# define UTNAMLEN	sizeof(((struct utmpx *) 0)->ut_name)
481590Srgrimes# define UTLINLEN	sizeof(((struct utmpx *) 0)->ut_line)
491590Srgrimes# ifdef HAVE_STRUCT_UTMPX_UT_HOST
5088428Smikeh#  define UTHOSTLEN	sizeof(((struct utmpx *) 0)->ut_host)
511590Srgrimes# endif
521590Srgrimes/* I just redefine a few words here.  Changing every occurrence below
531590Srgrimes * seems like too much of work.  All UTMP functions have equivalent
541590Srgrimes * UTMPX counterparts, so they can be added all here when needed.
551590Srgrimes * Kimmo Suominen, Oct 14 1991
561590Srgrimes */
571590Srgrimes# if defined(__UTMPX_FILE) && !defined(UTMPX_FILE)
581590Srgrimes#  define TCSH_PATH_UTMP __UTMPX_FILE
591590Srgrimes# elif defined(_PATH_UTMPX)
601590Srgrimes#  define TCSH_PATH_UTMP _PATH_UTMPX
611590Srgrimes# elif defined(UTMPX_FILE)
621590Srgrimes#  define TCSH_PATH_UTMP UTMPX_FILE
631590Srgrimes# elif __FreeBSD_version >= 900000
641590Srgrimes#  /* Why isn't this defined somewhere? */
651590Srgrimes#  define TCSH_PATH_UTMP "/var/run/utx.active"
661590Srgrimes# elif defined(__hpux)
671590Srgrimes#  define TCSH_PATH_UTMP "/etc/utmpx"
681590Srgrimes# endif
691590Srgrimes# if defined(TCSH_PATH_UTMP) || !defined(HAVE_UTMP_H)
701590Srgrimes#  define utmp utmpx
711590Srgrimes#  define TCSH_USE_UTMPX
721590Srgrimes#  if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
731590Srgrimes#   define getutent getutxent
741590Srgrimes#   define setutent setutxent
751590Srgrimes#   define endutent endutxent
761590Srgrimes#  endif /* HAVE_GETUTENT || HAVE_GETUTXENT */
771590Srgrimes#  if defined(HAVE_STRUCT_UTMPX_UT_TV)
781590Srgrimes#   define ut_time ut_tv.tv_sec
791590Srgrimes#  elif defined(HAVE_STRUCT_UTMPX_UT_XTIME)
801590Srgrimes#   define ut_time ut_xtime
811590Srgrimes#  endif
8277274Smikeh#  if defined(HAVE_STRUCT_UTMPX_UT_USER)
8377274Smikeh#   define ut_name ut_user
8488150Smikeh#  endif
8588150Smikeh# endif /* TCSH_PATH_UTMP || !HAVE_UTMP_H */
8688150Smikeh#endif /* HAVE_UTMPX_H */
871590Srgrimes
881590Srgrimes#if !defined(TCSH_USE_UTMPX) && defined(HAVE_UTMP_H)
891590Srgrimes# include <utmp.h>
901590Srgrimes# if defined(HAVE_STRUCT_UTMP_UT_TV)
911590Srgrimes#  define ut_time ut_tv.tv_sec
921590Srgrimes# elif defined(HAVE_STRUCT_UTMP_UT_XTIME)
9388150Smikeh#  define ut_time ut_xtime
9488150Smikeh# endif
9588150Smikeh# if defined(HAVE_STRUCT_UTMP_UT_USER)
9688150Smikeh#  define ut_name ut_user
971590Srgrimes# endif
9877274Smikeh# ifndef BROKEN_CC
991590Srgrimes#  define UTNAMLEN	sizeof(((struct utmp *) 0)->ut_name)
10077274Smikeh#  define UTLINLEN	sizeof(((struct utmp *) 0)->ut_line)
1011590Srgrimes#  ifdef HAVE_STRUCT_UTMP_UT_HOST
1021590Srgrimes#   ifdef _SEQUENT_
1031590Srgrimes#    define UTHOSTLEN	100
1041590Srgrimes#   else
10577274Smikeh#    define UTHOSTLEN	sizeof(((struct utmp *) 0)->ut_host)
1061590Srgrimes#   endif
1071590Srgrimes#  endif	/* HAVE_STRUCT_UTMP_UT_HOST */
10888150Smikeh# else
1091590Srgrimes/* give poor cc a little help if it needs it */
1101590Srgrimesstruct utmp __ut;
11177274Smikeh#  define UTNAMLEN	sizeof(__ut.ut_name)
11277274Smikeh#  define UTLINLEN	sizeof(__ut.ut_line)
11374769Smikeh#  ifdef HAVE_STRUCT_UTMP_UT_HOST
11474769Smikeh#   ifdef _SEQUENT_
11574769Smikeh#    define UTHOSTLEN	100
1161590Srgrimes#   else
1171590Srgrimes#    define UTHOSTLEN	sizeof(__ut.ut_host)
11877274Smikeh#   endif
1191590Srgrimes#  endif /* HAVE_STRUCT_UTMP_UT_HOST */
1201590Srgrimes# endif /* BROKEN_CC */
1211590Srgrimes# ifndef TCSH_PATH_UTMP
1221590Srgrimes#  ifdef UTMP_FILE
1231590Srgrimes#   define TCSH_PATH_UTMP UTMP_FILE
1241590Srgrimes#  elif defined(_PATH_UTMP)
1251590Srgrimes#   define TCSH_PATH_UTMP _PATH_UTMP
1261590Srgrimes#  else
12777274Smikeh#   define TCSH_PATH_UTMP "/etc/utmp"
12877274Smikeh#  endif /* UTMP_FILE */
1291590Srgrimes# endif /* TCSH_PATH_UTMP */
1301590Srgrimes#endif /* !TCSH_USE_UTMPX && HAVE_UTMP_H */
1311590Srgrimes
13277274Smikeh#ifndef UTNAMLEN
1331590Srgrimes#define UTNAMLEN 64
13477274Smikeh#endif
1351590Srgrimes#ifndef UTLINLEN
1361590Srgrimes#define UTLINLEN 64
1371590Srgrimes#endif
1381590Srgrimes
1391590Srgrimesstruct who {
14088150Smikeh    struct who *who_next;
14188150Smikeh    struct who *who_prev;
1421590Srgrimes    char    who_name[UTNAMLEN + 1];
1431590Srgrimes    char    who_new[UTNAMLEN + 1];
1441590Srgrimes    char    who_tty[UTLINLEN + 1];
1451590Srgrimes#ifdef UTHOSTLEN
1461590Srgrimes    char    who_host[UTHOSTLEN + 1];
1471590Srgrimes#endif /* UTHOSTLEN */
1481590Srgrimes    time_t  who_time;
1491590Srgrimes    int     who_status;
1501590Srgrimes};
1511590Srgrimes
1521590Srgrimesstatic struct who whohead, whotail;
1531590Srgrimesstatic time_t watch_period = 0;
15477274Smikehstatic time_t stlast = 0;
1551590Srgrimes#ifdef WHODEBUG
1561590Srgrimesstatic	void	debugwholist	(struct who *, struct who *);
1571590Srgrimes#endif
1581590Srgrimesstatic	void	print_who	(struct who *);
15977274Smikeh
1601590Srgrimes
1611590Srgrimes#define ONLINE		01
1621590Srgrimes#define OFFLINE		02
1631590Srgrimes#define CHANGED		04
1641590Srgrimes#define STMASK		07
1651590Srgrimes#define ANNOUNCE	010
1661590Srgrimes#define CLEARED		020
16777274Smikeh
16877274Smikeh/*
1691590Srgrimes * Karl Kleinpaste, 26 Jan 1984.
1701590Srgrimes * Initialize the dummy tty list for login watch.
1711590Srgrimes * This dummy list eliminates boundary conditions
1721590Srgrimes * when doing pointer-chase searches.
1731590Srgrimes */
17488150Smikehvoid
17588150Smikehinitwatch(void)
1761590Srgrimes{
1771590Srgrimes    whohead.who_next = &whotail;
1781590Srgrimes    whotail.who_prev = &whohead;
17988150Smikeh    stlast = 1;
18077274Smikeh#ifdef WHODEBUG
1811590Srgrimes    debugwholist(NULL, NULL);
18288150Smikeh#endif /* WHODEBUG */
18388150Smikeh}
18488150Smikeh
1851590Srgrimesvoid
1861590Srgrimesresetwatch(void)
1871590Srgrimes{
1881590Srgrimes    watch_period = 0;
1891590Srgrimes    stlast = 0;
1901590Srgrimes}
1911590Srgrimes
1921590Srgrimes/*
1931590Srgrimes * Karl Kleinpaste, 26 Jan 1984.
1941590Srgrimes * Watch /etc/utmp for login/logout changes.
1951590Srgrimes */
19688150Smikehvoid
1971590Srgrimeswatch_login(int force)
1981590Srgrimes{
1991590Srgrimes    int     comp = -1, alldone;
2001590Srgrimes    int	    firsttime = stlast == 1;
2011590Srgrimes#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
2021590Srgrimes    struct utmp *uptr;
2031590Srgrimes#else
2041590Srgrimes    int utmpfd;
2051590Srgrimes#endif
2061590Srgrimes    struct utmp utmp;
2071590Srgrimes    struct who *wp, *wpnew;
2081590Srgrimes    struct varent *v;
2091590Srgrimes    Char  **vp = NULL;
2101590Srgrimes    time_t  t, interval = MAILINTVL;
2111590Srgrimes    struct stat sta;
2121590Srgrimes#if defined(HAVE_STRUCT_UTMP_UT_HOST) && defined(_SEQUENT_)
2131590Srgrimes    char   *host, *ut_find_host();
2141590Srgrimes#endif
2151590Srgrimes#ifdef WINNT_NATIVE
2161590Srgrimes    static int ncbs_posted = 0;
21788428Smikeh    USE(utmp);
2181590Srgrimes    USE(utmpfd);
2191590Srgrimes    USE(sta);
2201590Srgrimes    USE(wpnew);
2211590Srgrimes#endif /* WINNT_NATIVE */
2221590Srgrimes
2231590Srgrimes    /* stop SIGINT, lest our login list get trashed. */
2241590Srgrimes    pintr_disabled++;
2251590Srgrimes    cleanup_push(&pintr_disabled, disabled_cleanup);
2261590Srgrimes
2271590Srgrimes    v = adrof(STRwatch);
2281590Srgrimes    if ((v == NULL || v->vec == NULL) && !force) {
2291590Srgrimes	cleanup_until(&pintr_disabled);
2301590Srgrimes	return;			/* no names to watch */
2311590Srgrimes    }
2321590Srgrimes    if (!force) {
2331590Srgrimes	trim(vp = v->vec);
2341590Srgrimes	if (blklen(vp) % 2)		/* odd # args: 1st == # minutes. */
2351590Srgrimes	    interval = (number(*vp)) ? (getn(*vp++) * 60) : MAILINTVL;
23688428Smikeh    }
23788428Smikeh    else
23888428Smikeh	interval = 0;
23988428Smikeh
24088428Smikeh    (void) time(&t);
2411590Srgrimes#ifdef WINNT_NATIVE
2421590Srgrimes	/*
2431590Srgrimes	 * Since NCB_ASTATs take time, start em async at least 90 secs
2441590Srgrimes	 * before we are due -amol 6/5/97
2451590Srgrimes	 */
2461590Srgrimes	if (!ncbs_posted) {
2471590Srgrimes	    time_t tdiff = t - watch_period;
2481590Srgrimes	    if (!watch_period || ((tdiff  > 0) && (tdiff > (interval - 90)))) {
2491590Srgrimes		start_ncbs(vp);
2501590Srgrimes 		ncbs_posted = 1;
2511590Srgrimes	    }
2521590Srgrimes	}
2531590Srgrimes#endif /* WINNT_NATIVE */
2541590Srgrimes    if (t - watch_period < interval) {
25532189Sjoerg	cleanup_until(&pintr_disabled);
2561590Srgrimes	return;			/* not long enough yet... */
2571590Srgrimes    }
25888227Sache    watch_period = t;
2591590Srgrimes#ifdef WINNT_NATIVE
2601590Srgrimes    ncbs_posted = 0;
2611590Srgrimes#else /* !WINNT_NATIVE */
26232189Sjoerg
26332189Sjoerg    /*
26432189Sjoerg     * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
26532189Sjoerg     * Don't open utmp all the time, stat it first...
26632189Sjoerg     */
26788227Sache    if (stat(TCSH_PATH_UTMP, &sta)) {
26832189Sjoerg	if (!force)
26932189Sjoerg	    xprintf(CGETS(26, 1,
27032189Sjoerg			  "cannot stat %s.  Please \"unset watch\".\n"),
2711590Srgrimes		    TCSH_PATH_UTMP);
2721590Srgrimes	cleanup_until(&pintr_disabled);
2731590Srgrimes	return;
2741590Srgrimes    }
2751590Srgrimes    if (stlast == sta.st_mtime) {
2761590Srgrimes	cleanup_until(&pintr_disabled);
2771590Srgrimes	return;
2781590Srgrimes    }
27988428Smikeh    stlast = sta.st_mtime;
2801590Srgrimes#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
2811590Srgrimes    setutent();
2821590Srgrimes#else
28388428Smikeh    if ((utmpfd = xopen(TCSH_PATH_UTMP, O_RDONLY|O_LARGEFILE)) < 0) {
28488428Smikeh	if (!force)
28588428Smikeh	    xprintf(CGETS(26, 2,
28688428Smikeh			  "%s cannot be opened.  Please \"unset watch\".\n"),
28788428Smikeh		    TCSH_PATH_UTMP);
28888428Smikeh	cleanup_until(&pintr_disabled);
28988428Smikeh	return;
29088428Smikeh    }
29188428Smikeh    cleanup_push(&utmpfd, open_cleanup);
29288428Smikeh#endif
29388428Smikeh
29488428Smikeh    /*
29588428Smikeh     * xterm clears the entire utmp entry - mark everyone on the status list
29688428Smikeh     * OFFLINE or we won't notice X "logouts"
29788428Smikeh     */
29888428Smikeh    for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next)
29988428Smikeh	wp->who_status = OFFLINE | CLEARED;
30088428Smikeh
30188428Smikeh    /*
30288428Smikeh     * Read in the utmp file, sort the entries, and update existing entries or
30388428Smikeh     * add new entries to the status list.
30488428Smikeh     */
30588428Smikeh#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
30688428Smikeh    while ((uptr = getutent()) != NULL) {
30788428Smikeh        memcpy(&utmp, uptr, sizeof (utmp));
30888428Smikeh#else
30988428Smikeh    while (xread(utmpfd, &utmp, sizeof utmp) == sizeof utmp) {
31088428Smikeh#endif
31188428Smikeh
3121590Srgrimes# ifdef DEAD_PROCESS
31388428Smikeh#  ifndef IRIS4D
31488428Smikeh	if (utmp.ut_type != USER_PROCESS)
31588428Smikeh	    continue;
31688428Smikeh#  else
31788428Smikeh	/* Why is that? Cause the utmp file is always corrupted??? */
31874769Smikeh	if (utmp.ut_type != USER_PROCESS && utmp.ut_type != DEAD_PROCESS)
31974769Smikeh	    continue;
32074769Smikeh#  endif /* IRIS4D */
32174769Smikeh# endif /* DEAD_PROCESS */
32288428Smikeh
3231590Srgrimes	if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0')
32488428Smikeh	    continue;	/* completely void entry */
3251590Srgrimes# ifdef DEAD_PROCESS
3261590Srgrimes	if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0')
3271590Srgrimes	    continue;
3281590Srgrimes# endif /* DEAD_PROCESS */
3291590Srgrimes	wp = whohead.who_next;
3301590Srgrimes	while (wp->who_next && (comp = strncmp(wp->who_tty, utmp.ut_line, UTLINLEN)) < 0)
33188227Sache	    wp = wp->who_next;/* find that tty! */
3321590Srgrimes
3331590Srgrimes	if (wp->who_next && comp == 0) {	/* found the tty... */
3341590Srgrimes	    if (utmp.ut_time < wp->who_time)
3351590Srgrimes	        continue;
3361590Srgrimes# ifdef DEAD_PROCESS
3371590Srgrimes	    if (utmp.ut_type == DEAD_PROCESS) {
33877274Smikeh		wp->who_time = utmp.ut_time;
3391590Srgrimes		wp->who_status = OFFLINE;
34088428Smikeh	    }
34188428Smikeh	    else
34288428Smikeh# endif /* DEAD_PROCESS */
34388428Smikeh	    if (utmp.ut_name[0] == '\0') {
34488428Smikeh		wp->who_time = utmp.ut_time;
34588428Smikeh		wp->who_status = OFFLINE;
34688428Smikeh	    }
34788428Smikeh	    else if (strncmp(utmp.ut_name, wp->who_name, UTNAMLEN) == 0) {
34888428Smikeh		/* someone is logged in */
34988428Smikeh		wp->who_time = utmp.ut_time;
35088428Smikeh		wp->who_status = ONLINE | ANNOUNCE;	/* same guy */
35188428Smikeh	    }
35288428Smikeh	    else {
35388428Smikeh		(void) strncpy(wp->who_new, utmp.ut_name, UTNAMLEN);
35488428Smikeh# ifdef UTHOSTLEN
35588428Smikeh#  ifdef _SEQUENT_
35688428Smikeh		host = ut_find_host(wp->who_tty);
35788428Smikeh		if (host)
35888428Smikeh		    (void) strncpy(wp->who_host, host, UTHOSTLEN);
35988428Smikeh		else
36088428Smikeh		    wp->who_host[0] = 0;
36188428Smikeh#  else
36288428Smikeh		(void) strncpy(wp->who_host, utmp.ut_host, UTHOSTLEN);
36388428Smikeh#  endif
36488428Smikeh# endif /* UTHOSTLEN */
36588428Smikeh		wp->who_time = utmp.ut_time;
36688428Smikeh		if (wp->who_name[0] == '\0')
36788428Smikeh		    wp->who_status = ONLINE;
36888428Smikeh		else
36988428Smikeh		    wp->who_status = CHANGED;
37088428Smikeh	    }
37188428Smikeh	}
37288428Smikeh	else {		/* new tty in utmp */
37388428Smikeh	    wpnew = xcalloc(1, sizeof *wpnew);
37488428Smikeh	    (void) strncpy(wpnew->who_tty, utmp.ut_line, UTLINLEN);
37588428Smikeh# ifdef UTHOSTLEN
37688428Smikeh#  ifdef _SEQUENT_
37788428Smikeh	    host = ut_find_host(wpnew->who_tty);
37888428Smikeh	    if (host)
37988428Smikeh		(void) strncpy(wpnew->who_host, host, UTHOSTLEN);
38088428Smikeh	    else
38188428Smikeh		wpnew->who_host[0] = 0;
38288428Smikeh#  else
38388428Smikeh	    (void) strncpy(wpnew->who_host, utmp.ut_host, UTHOSTLEN);
38488428Smikeh#  endif
38588428Smikeh# endif /* UTHOSTLEN */
3861590Srgrimes	    wpnew->who_time = utmp.ut_time;
3871590Srgrimes# ifdef DEAD_PROCESS
38888428Smikeh	    if (utmp.ut_type == DEAD_PROCESS)
38974769Smikeh		wpnew->who_status = OFFLINE;
3901590Srgrimes	    else
3911590Srgrimes# endif /* DEAD_PROCESS */
3921590Srgrimes	    if (utmp.ut_name[0] == '\0')
39377274Smikeh		wpnew->who_status = OFFLINE;
3941590Srgrimes	    else {
3951590Srgrimes		(void) strncpy(wpnew->who_new, utmp.ut_name, UTNAMLEN);
39688150Smikeh		wpnew->who_status = ONLINE;
39788150Smikeh	    }
39888150Smikeh# ifdef WHODEBUG
39988150Smikeh	    debugwholist(wpnew, wp);
40088150Smikeh# endif /* WHODEBUG */
40177274Smikeh
4021590Srgrimes	    wpnew->who_next = wp;	/* link in a new 'who' */
4031590Srgrimes	    wpnew->who_prev = wp->who_prev;
4041590Srgrimes	    wpnew->who_prev->who_next = wpnew;
4051590Srgrimes	    wp->who_prev = wpnew;	/* linked in now */
40677274Smikeh	}
4071590Srgrimes    }
4081590Srgrimes#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT)
4091590Srgrimes    endutent();
4101590Srgrimes#else
4111590Srgrimes    cleanup_until(&utmpfd);
4121590Srgrimes#endif
4131590Srgrimes#endif /* !WINNT_NATIVE */
4141590Srgrimes
4151590Srgrimes    if (force || vp == NULL) {
4161590Srgrimes	cleanup_until(&pintr_disabled);
4171590Srgrimes	return;
4181590Srgrimes    }
4191590Srgrimes
42077274Smikeh    /*
4211590Srgrimes     * The state of all logins is now known, so we can search the user's list
4221590Srgrimes     * of watchables to print the interesting ones.
4231590Srgrimes     */
4241590Srgrimes    for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' &&
4251590Srgrimes	 *(vp + 1) != NULL && **(vp + 1) != '\0';
4261590Srgrimes	 vp += 2) {		/* args used in pairs... */
4271590Srgrimes
4281590Srgrimes	if (eq(*vp, STRany) && eq(*(vp + 1), STRany))
4291590Srgrimes	    alldone = 1;
4301590Srgrimes
4311590Srgrimes	for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
4321590Srgrimes	    if (wp->who_status & ANNOUNCE ||
4331590Srgrimes		(!eq(STRany, vp[0]) &&
4341590Srgrimes		 !Gmatch(str2short(wp->who_name), vp[0]) &&
43574769Smikeh		 !Gmatch(str2short(wp->who_new),  vp[0])) ||
4361590Srgrimes		(!Gmatch(str2short(wp->who_tty),  vp[1]) &&
4371590Srgrimes		 !eq(STRany, vp[1])))
4381590Srgrimes		continue;	/* entry doesn't qualify */
4391590Srgrimes	    /* already printed or not right one to print */
44074769Smikeh
4411590Srgrimes
4421590Srgrimes	    if (wp->who_status & CLEARED) {/* utmp entry was cleared */
4431590Srgrimes		wp->who_time = watch_period;
44477274Smikeh		wp->who_status &= ~CLEARED;
44577274Smikeh	    }
4461590Srgrimes
4471590Srgrimes	    if ((wp->who_status & OFFLINE) &&
4481590Srgrimes		(wp->who_name[0] != '\0')) {
4491590Srgrimes		if (!firsttime)
4501590Srgrimes		    print_who(wp);
4511590Srgrimes		wp->who_name[0] = '\0';
4521590Srgrimes		wp->who_status |= ANNOUNCE;
4531590Srgrimes		continue;
4541590Srgrimes	    }
4551590Srgrimes	    if (wp->who_status & ONLINE) {
45677274Smikeh		if (!firsttime)
4571590Srgrimes		    print_who(wp);
4581590Srgrimes		(void) strcpy(wp->who_name, wp->who_new);
4591590Srgrimes		wp->who_status |= ANNOUNCE;
4601590Srgrimes		continue;
4611590Srgrimes	    }
4621590Srgrimes	    if (wp->who_status & CHANGED) {
4631590Srgrimes		if (!firsttime)
4641590Srgrimes		    print_who(wp);
4651590Srgrimes		(void) strcpy(wp->who_name, wp->who_new);
4661590Srgrimes		wp->who_status |= ANNOUNCE;
4671590Srgrimes		continue;
4681590Srgrimes	    }
4691590Srgrimes	}
4701590Srgrimes    }
4711590Srgrimes    cleanup_until(&pintr_disabled);
4721590Srgrimes}
4731590Srgrimes
4741590Srgrimes#ifdef WHODEBUG
4751590Srgrimesstatic void
4761590Srgrimesdebugwholist(struct who *new, struct who *wp)
4771590Srgrimes{
4781590Srgrimes    struct who *a;
4791590Srgrimes
4801590Srgrimes    a = whohead.who_next;
48177274Smikeh    while (a->who_next != NULL) {
4821590Srgrimes	xprintf("%s/%s -> ", a->who_name, a->who_tty);
4831590Srgrimes	a = a->who_next;
4841590Srgrimes    }
4851590Srgrimes    xprintf("TAIL\n");
4861590Srgrimes    if (a != &whotail) {
4871590Srgrimes	xprintf(CGETS(26, 3, "BUG! last element is not whotail!\n"));
48888150Smikeh	abort();
48977274Smikeh    }
49077274Smikeh    a = whotail.who_prev;
49177274Smikeh    xprintf(CGETS(26, 4, "backward: "));
49277274Smikeh    while (a->who_prev != NULL) {
49377274Smikeh	xprintf("%s/%s -> ", a->who_name, a->who_tty);
49488150Smikeh	a = a->who_prev;
49577274Smikeh    }
4961590Srgrimes    xprintf("HEAD\n");
4971590Srgrimes    if (a != &whohead) {
4981590Srgrimes	xprintf(CGETS(26, 5, "BUG! first element is not whohead!\n"));
4991590Srgrimes	abort();
5001590Srgrimes    }
5011590Srgrimes    if (new)
5021590Srgrimes	xprintf(CGETS(26, 6, "new: %s/%s\n"), new->who_name, new->who_tty);
5031590Srgrimes    if (wp)
5041590Srgrimes	xprintf("wp: %s/%s\n", wp->who_name, wp->who_tty);
5051590Srgrimes}
5061590Srgrimes#endif /* WHODEBUG */
50777274Smikeh
50877274Smikeh
5091590Srgrimesstatic void
5101590Srgrimesprint_who(struct who *wp)
5111590Srgrimes{
5121590Srgrimes#ifdef UTHOSTLEN
5131590Srgrimes    Char   *cp = str2short(CGETS(26, 7, "%n has %a %l from %m."));
51477274Smikeh#else
5151590Srgrimes    Char   *cp = str2short(CGETS(26, 8, "%n has %a %l."));
51674769Smikeh#endif /* UTHOSTLEN */
5171590Srgrimes    struct varent *vp = adrof(STRwho);
5181590Srgrimes    Char *str;
5191590Srgrimes
52077274Smikeh    if (vp && vp->vec && vp->vec[0])
5211590Srgrimes	cp = vp->vec[0];
5221590Srgrimes
52377274Smikeh    str = tprintf(FMT_WHO, cp, NULL, wp->who_time, wp);
52477274Smikeh    cleanup_push(str, xfree);
5251590Srgrimes    for (cp = str; *cp;)
5261590Srgrimes	xputwchar(*cp++);
5271590Srgrimes    cleanup_until(str);
5281590Srgrimes    xputchar('\n');
5291590Srgrimes} /* end print_who */
5301590Srgrimes
5311590Srgrimes
53277274Smikehchar *
5331590Srgrimeswho_info(ptr_t ptr, int c)
53474769Smikeh{
53577274Smikeh    struct who *wp = ptr;
53677274Smikeh    char *wbuf;
5371590Srgrimes#ifdef UTHOSTLEN
5381590Srgrimes    char *wb;
53977274Smikeh    int flg;
5401590Srgrimes    char *pb;
54177274Smikeh#endif /* UTHOSTLEN */
54277274Smikeh
5431590Srgrimes    switch (c) {
5441590Srgrimes    case 'n':		/* user name */
5451590Srgrimes	switch (wp->who_status & STMASK) {
5461590Srgrimes	case ONLINE:
5471590Srgrimes	case CHANGED:
5481590Srgrimes	    return strsave(wp->who_new);
5491590Srgrimes	case OFFLINE:
5501590Srgrimes	    return strsave(wp->who_name);
5511590Srgrimes	default:
5521590Srgrimes	    break;
5531590Srgrimes	}
5541590Srgrimes	break;
5551590Srgrimes
5561590Srgrimes    case 'a':
5571590Srgrimes	switch (wp->who_status & STMASK) {
55882793Sache	case ONLINE:
5591590Srgrimes	    return strsave(CGETS(26, 9, "logged on"));
56077274Smikeh	case OFFLINE:
5611590Srgrimes	    return strsave(CGETS(26, 10, "logged off"));
56277274Smikeh	case CHANGED:
5631590Srgrimes	    return xasprintf(CGETS(26, 11, "replaced %s on"), wp->who_name);
5641590Srgrimes	default:
5651590Srgrimes	    break;
5661590Srgrimes	}
5671590Srgrimes	break;
5681590Srgrimes
5691590Srgrimes#ifdef UTHOSTLEN
5701590Srgrimes    case 'm':
5711590Srgrimes	if (wp->who_host[0] == '\0')
5721590Srgrimes	    return strsave(CGETS(26, 12, "local"));
5731590Srgrimes	else {
5741590Srgrimes	    pb = wp->who_host;
5751590Srgrimes	    wbuf = xmalloc(strlen(pb) + 1);
5761590Srgrimes	    wb = wbuf;
57774769Smikeh	    /* the ':' stuff is for <host>:<display>.<screen> */
5781590Srgrimes	    for (flg = isdigit((unsigned char)*pb) ? '\0' : '.';
57977274Smikeh		 *pb != '\0' && (*pb != flg || ((pb = strchr(pb, ':')) != 0));
5801590Srgrimes		 pb++) {
58177274Smikeh		if (*pb == ':')
58277274Smikeh		    flg = '\0';
58374769Smikeh		*wb++ = isupper((unsigned char)*pb) ?
58474769Smikeh		    tolower((unsigned char)*pb) : *pb;
58574769Smikeh	    }
5861590Srgrimes	    *wb = '\0';
5871590Srgrimes	    return wbuf;
58877274Smikeh	}
5891590Srgrimes
5901590Srgrimes    case 'M':
5911590Srgrimes	if (wp->who_host[0] == '\0')
5921590Srgrimes	    return strsave(CGETS(26, 12, "local"));
59377274Smikeh	else {
59477274Smikeh	    pb = wp->who_host;
59577274Smikeh	    wbuf = xmalloc(strlen(pb) + 1);
59677274Smikeh	    wb = wbuf;
59777274Smikeh	    for (; *pb != '\0'; pb++)
5981590Srgrimes		*wb++ = isupper((unsigned char)*pb) ?
5991590Srgrimes		    tolower((unsigned char)*pb) : *pb;
6001590Srgrimes	    *wb = '\0';
6011590Srgrimes	    return wbuf;
60277274Smikeh	}
6031590Srgrimes#endif /* UTHOSTLEN */
6041590Srgrimes
6051590Srgrimes    case 'l':
6061590Srgrimes	return strsave(wp->who_tty);
6071590Srgrimes
60882793Sache    default:
6091590Srgrimes	wbuf = xmalloc(3);
61077274Smikeh	wbuf[0] = '%';
6111590Srgrimes	wbuf[1] = (char) c;
61277274Smikeh	wbuf[2] = '\0';
6131590Srgrimes	return wbuf;
6141590Srgrimes    }
6151590Srgrimes    return NULL;
6161590Srgrimes}
6171590Srgrimes
6181590Srgrimesvoid
6191590Srgrimes/*ARGSUSED*/
6201590Srgrimesdolog(Char **v, struct command *c)
6211590Srgrimes{
6221590Srgrimes    struct who *wp;
6231590Srgrimes    struct varent *vp;
62474769Smikeh
6251590Srgrimes    USE(v);
6261590Srgrimes    USE(c);
62774769Smikeh    vp = adrof(STRwatch);	/* lint insists vp isn't used unless we */
6281590Srgrimes    if (vp == NULL)		/* unless we assign it outside the if */
6291590Srgrimes	stderror(ERR_NOWATCH);
63077274Smikeh    resetwatch();
6311590Srgrimes    wp = whohead.who_next;
6321590Srgrimes    while (wp->who_next != NULL) {
6331590Srgrimes	wp->who_name[0] = '\0';
63477274Smikeh	wp = wp->who_next;
63577274Smikeh    }
63677274Smikeh}
6371590Srgrimes
63877274Smikeh# ifdef UTHOSTLEN
6391590Srgrimessize_t
6401590Srgrimesutmphostsize(void)
64129574Sphk{
6421590Srgrimes    return UTHOSTLEN;
64377274Smikeh}
6441590Srgrimes
64529574Sphkchar *
6461590Srgrimesutmphost(void)
6471590Srgrimes{
64877274Smikeh    char *tty = short2str(varval(STRtty));
64977274Smikeh    struct who *wp;
6501590Srgrimes    char *host = NULL;
65188227Sache
6521590Srgrimes    watch_login(1);
6531590Srgrimes
6541590Srgrimes    for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
6551590Srgrimes	if (strcmp(tty, wp->who_tty) == 0)
6561590Srgrimes	    host = wp->who_host;
6571590Srgrimes	wp->who_name[0] = '\0';
65874769Smikeh    }
65974769Smikeh    resetwatch();
66077274Smikeh    return host;
6611590Srgrimes}
6621590Srgrimes# endif /* UTHOSTLEN */
6631590Srgrimes
66477274Smikeh#ifdef WINNT_NATIVE
6651590Srgrimesvoid
6661590Srgrimesadd_to_who_list(char *name, char *mach_nm)
6671590Srgrimes{
6681590Srgrimes
6691590Srgrimes    struct who *wp, *wpnew;
6701590Srgrimes    int comp = -1;
6711590Srgrimes
6721590Srgrimes    wp = whohead.who_next;
6731590Srgrimes    while (wp->who_next && (comp = strncmp(wp->who_tty,mach_nm,UTLINLEN)) < 0)
6741590Srgrimes	wp = wp->who_next;/* find that tty! */
6751590Srgrimes
67688150Smikeh    if (wp->who_next && comp == 0) {	/* found the tty... */
6771590Srgrimes
67888150Smikeh	if (*name == '\0') {
67988150Smikeh	    wp->who_time = 0;
68088150Smikeh	    wp->who_status = OFFLINE;
68177274Smikeh	}
68288150Smikeh	else if (strncmp(name, wp->who_name, UTNAMLEN) == 0) {
68377274Smikeh	    /* someone is logged in */
6841590Srgrimes	    wp->who_time = 0;
6851590Srgrimes	    wp->who_status = 0;	/* same guy */
6861590Srgrimes	}
6871590Srgrimes	else {
6881590Srgrimes	    (void) strncpy(wp->who_new, name, UTNAMLEN);
6891590Srgrimes	    wp->who_time = 0;
6901590Srgrimes	    if (wp->who_name[0] == '\0')
6911590Srgrimes		wp->who_status = ONLINE;
6921590Srgrimes	    else
6931590Srgrimes		wp->who_status = CHANGED;
6941590Srgrimes	}
6951590Srgrimes    }
6961590Srgrimes    else {
6971590Srgrimes	wpnew = xcalloc(1, sizeof *wpnew);
6981590Srgrimes	(void) strncpy(wpnew->who_tty, mach_nm, UTLINLEN);
6991590Srgrimes	wpnew->who_time = 0;
7001590Srgrimes	if (*name == '\0')
7011590Srgrimes	    wpnew->who_status = OFFLINE;
7021590Srgrimes	else {
7031590Srgrimes	    (void) strncpy(wpnew->who_new, name, UTNAMLEN);
70477274Smikeh	    wpnew->who_status = ONLINE;
70577274Smikeh	}
70677274Smikeh#ifdef WHODEBUG
7071590Srgrimes	debugwholist(wpnew, wp);
7081590Srgrimes#endif /* WHODEBUG */
7091590Srgrimes
7101590Srgrimes	wpnew->who_next = wp;	/* link in a new 'who' */
7111590Srgrimes	wpnew->who_prev = wp->who_prev;
7121590Srgrimes	wpnew->who_prev->who_next = wpnew;
7131590Srgrimes	wp->who_prev = wpnew;	/* linked in now */
71477274Smikeh    }
7151590Srgrimes}
7161590Srgrimes#endif /* WINNT_NATIVE */
7171590Srgrimes#endif /* HAVENOUTMP */
7181590Srgrimes