/*
 * Generic OS_Idle () implementation, to be included in os-*.c modules.
 */
#ifndef lint
static char *rcsid2 =
"$Id: os-idle.c,v 1.1 1994/10/22 02:33:44 stolcke Exp $ ICSI (Berkeley)";
#endif /* not lint */

/***********************************************************************
 *				OS_Idle
 ***********************************************************************
 * SYNOPSIS:	    Find the idle time of the machine
 * CALLED BY:	    Avail_Local
 * RETURN:	    The number of seconds for which the machine has been
 *	    	    idle.
 * SIDE EFFECTS:    None
 *
 * STRATEGY:
 *	Locate the access time for various relevant devices and subtract it
 *	from the current time to obtain the number of seconds the
 *	machine has been idle.  The devices (terminal lines) used are
 *	selected based on the criteria argument, which is an OR of the
 *	IDLECRIT_* flags defined in customs.h.
 *
 *
 * REVISION HISTORY:
 *	Name	Date		Description
 *	----	----		-----------
 *	ardeb	9/10/89		Initial Revision
 *	stolcke	9/24/91		Rewritten in terms of kmem_read()
 *	stolcke	2/19/92		Allow for two input devices (HP-UX)
 *	stolcke	4/02/93		Support for devices listed in /etc/utmp
 *	stolcke	10/21/94	Parameterized idle criteria
 *
 ***********************************************************************/
int
OS_Idle(criteria)
    int criteria;
{
    struct stat	    statb;
    int		    consUid;	/* console user id */
    struct utmp     uEntry;
    char	    tty[sizeof("/dev/") + sizeof(uEntry.ut_line)];
    struct timeval  now;
    time_t          atime;

    atime = 0;

    /*
     * Check keyboard and mouse access times
     */
    if (criteria & IDLECRIT_KBD) {
#ifdef DEV_KEYBOARD
	if (stat (DEV_KEYBOARD, &statb) == 0) {
	    atime = statb.st_atime;
	}
#endif /* DEV_KEYBOARD */
#ifdef DEV_MOUSE
	if (stat (DEV_MOUSE, &statb) == 0 && statb.st_atime > atime) {
	    atime = statb.st_atime;
	}
#endif /* DEV_MOUSE */
    }

    /*
     * Find console user, if any
     */
    if (criteria & IDLECRIT_USER) {
	if (stat (DEV_CONSOLE, &statb) == 0 && statb.st_uid != 0) {
	    consUid = statb.st_uid;
	} else {
	    consUid = -1;
	}
    }

    /*
     * Scan utmp for logins and check associated terminal lines
     */
    if (criteria & (IDLECRIT_USER|IDLECRIT_LOCAL|IDLECRIT_REMOTE)) {
	while (read(utmpf, (char *)&uEntry, sizeof(uEntry)) == sizeof(uEntry)) {
	    if (*uEntry.ut_name &&
		*uEntry.ut_line &&
#ifdef USER_PROCESS
		uEntry.ut_type == USER_PROCESS &&
#endif
		(sprintf(tty, "/dev/%.*s", sizeof(uEntry.ut_line),
			 uEntry.ut_line), 
		 stat(tty, &statb) == 0) &&
		statb.st_atime > atime &&
		((criteria & IDLECRIT_USER) && (statb.st_uid == consUid)
		 || (criteria & IDLECRIT_LOCAL)
#ifndef NO_UTHOST
		 /*
		  * 'Remote' logins are characterized by an empty ut_host
		  * field, or one that contains a local X display number.
		  */
		    && (uEntry.ut_host[0] == '\0' || uEntry.ut_host[0] == ':')
		 || (criteria & IDLECRIT_REMOTE)
		    && (uEntry.ut_host[0] != '\0' && uEntry.ut_host[0] != ':')
#endif /* NO_UTHOST */
	        ))
	    {
		atime = statb.st_atime;
	    }
	}
	lseek (utmpf, 0L, L_SET);
    }

    gettimeofday (&now, (struct timezone *)0);
	
    if (verbose) {
	xlog (XLOG_DEBUG, "OS_Idle: last access = %.8s, idle = %ld:%02ld",
	        ctime(&atime) + 11,
		(now.tv_sec - atime)/60, (now.tv_sec - atime)%60);
    }

    return (now.tv_sec - atime);
}
