1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/tc.who.c,v 3.57 2012/01/17 20:53:38 christos Exp $ */ 259243Sobrien/* 359243Sobrien * tc.who.c: Watch logins and logouts... 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35232633SmpRCSID("$tcsh: tc.who.c,v 3.57 2012/01/17 20:53:38 christos Exp $") 3659243Sobrien 3759243Sobrien#include "tc.h" 3859243Sobrien 3959243Sobrien#ifndef HAVENOUTMP 4059243Sobrien/* 4159243Sobrien * kfk 26 Jan 1984 - for login watch functions. 4259243Sobrien */ 4359243Sobrien#include <ctype.h> 4459243Sobrien 45145479Smp#ifdef HAVE_UTMPX_H 4659243Sobrien# include <utmpx.h> 47232633Smp# define UTNAMLEN sizeof(((struct utmpx *) 0)->ut_name) 48232633Smp# define UTLINLEN sizeof(((struct utmpx *) 0)->ut_line) 49232633Smp# ifdef HAVE_STRUCT_UTMPX_UT_HOST 50232633Smp# define UTHOSTLEN sizeof(((struct utmpx *) 0)->ut_host) 51232633Smp# endif 5259243Sobrien/* I just redefine a few words here. Changing every occurrence below 5359243Sobrien * seems like too much of work. All UTMP functions have equivalent 5459243Sobrien * UTMPX counterparts, so they can be added all here when needed. 5559243Sobrien * Kimmo Suominen, Oct 14 1991 5659243Sobrien */ 57145479Smp# if defined(__UTMPX_FILE) && !defined(UTMPX_FILE) 58145479Smp# define TCSH_PATH_UTMP __UTMPX_FILE 59145479Smp# elif defined(_PATH_UTMPX) 60145479Smp# define TCSH_PATH_UTMP _PATH_UTMPX 61145479Smp# elif defined(UTMPX_FILE) 62145479Smp# define TCSH_PATH_UTMP UTMPX_FILE 63232633Smp# elif __FreeBSD_version >= 900000 64232633Smp# /* Why isn't this defined somewhere? */ 65232633Smp# define TCSH_PATH_UTMP "/var/run/utx.active" 66232633Smp# elif defined(__hpux) 67232633Smp# define TCSH_PATH_UTMP "/etc/utmpx" 68232633Smp# endif 69232633Smp# if defined(TCSH_PATH_UTMP) || !defined(HAVE_UTMP_H) 70145479Smp# define utmp utmpx 71232633Smp# define TCSH_USE_UTMPX 72232633Smp# if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 73232633Smp# define getutent getutxent 74232633Smp# define setutent setutxent 75232633Smp# define endutent endutxent 76232633Smp# endif /* HAVE_GETUTENT || HAVE_GETUTXENT */ 77232633Smp# if defined(HAVE_STRUCT_UTMPX_UT_TV) 78145479Smp# define ut_time ut_tv.tv_sec 79232633Smp# elif defined(HAVE_STRUCT_UTMPX_UT_XTIME) 80145479Smp# define ut_time ut_xtime 81145479Smp# endif 82232633Smp# if defined(HAVE_STRUCT_UTMPX_UT_USER) 83145479Smp# define ut_name ut_user 84145479Smp# endif 85232633Smp# endif /* TCSH_PATH_UTMP || !HAVE_UTMP_H */ 86145479Smp#endif /* HAVE_UTMPX_H */ 8759243Sobrien 88232633Smp#if !defined(TCSH_USE_UTMPX) && defined(HAVE_UTMP_H) 89232633Smp# include <utmp.h> 90232633Smp# if defined(HAVE_STRUCT_UTMP_UT_TV) 91232633Smp# define ut_time ut_tv.tv_sec 92232633Smp# elif defined(HAVE_STRUCT_UTMP_UT_XTIME) 93232633Smp# define ut_time ut_xtime 94232633Smp# endif 95232633Smp# if defined(HAVE_STRUCT_UTMP_UT_USER) 96232633Smp# define ut_name ut_user 97232633Smp# endif 98232633Smp# ifndef BROKEN_CC 99232633Smp# define UTNAMLEN sizeof(((struct utmp *) 0)->ut_name) 100232633Smp# define UTLINLEN sizeof(((struct utmp *) 0)->ut_line) 101232633Smp# ifdef HAVE_STRUCT_UTMP_UT_HOST 102232633Smp# ifdef _SEQUENT_ 103232633Smp# define UTHOSTLEN 100 104232633Smp# else 105232633Smp# define UTHOSTLEN sizeof(((struct utmp *) 0)->ut_host) 106232633Smp# endif 107232633Smp# endif /* HAVE_STRUCT_UTMP_UT_HOST */ 108232633Smp# else 10959243Sobrien/* give poor cc a little help if it needs it */ 11059243Sobrienstruct utmp __ut; 111232633Smp# define UTNAMLEN sizeof(__ut.ut_name) 112232633Smp# define UTLINLEN sizeof(__ut.ut_line) 113232633Smp# ifdef HAVE_STRUCT_UTMP_UT_HOST 114232633Smp# ifdef _SEQUENT_ 115232633Smp# define UTHOSTLEN 100 116232633Smp# else 117232633Smp# define UTHOSTLEN sizeof(__ut.ut_host) 118232633Smp# endif 119232633Smp# endif /* HAVE_STRUCT_UTMP_UT_HOST */ 120232633Smp# endif /* BROKEN_CC */ 121232633Smp# ifndef TCSH_PATH_UTMP 122232633Smp# ifdef UTMP_FILE 123232633Smp# define TCSH_PATH_UTMP UTMP_FILE 124232633Smp# elif defined(_PATH_UTMP) 125232633Smp# define TCSH_PATH_UTMP _PATH_UTMP 12659243Sobrien# else 127232633Smp# define TCSH_PATH_UTMP "/etc/utmp" 128232633Smp# endif /* UTMP_FILE */ 129232633Smp# endif /* TCSH_PATH_UTMP */ 130232633Smp#endif /* !TCSH_USE_UTMPX && HAVE_UTMP_H */ 13159243Sobrien 132232633Smp#ifndef UTNAMLEN 133232633Smp#define UTNAMLEN 64 134232633Smp#endif 135232633Smp#ifndef UTLINLEN 136232633Smp#define UTLINLEN 64 137232633Smp#endif 13859243Sobrien 13959243Sobrienstruct who { 14059243Sobrien struct who *who_next; 14159243Sobrien struct who *who_prev; 14259243Sobrien char who_name[UTNAMLEN + 1]; 14359243Sobrien char who_new[UTNAMLEN + 1]; 14459243Sobrien char who_tty[UTLINLEN + 1]; 145232633Smp#ifdef UTHOSTLEN 14659243Sobrien char who_host[UTHOSTLEN + 1]; 147232633Smp#endif /* UTHOSTLEN */ 14859243Sobrien time_t who_time; 14959243Sobrien int who_status; 15059243Sobrien}; 15159243Sobrien 15259243Sobrienstatic struct who whohead, whotail; 15359243Sobrienstatic time_t watch_period = 0; 15459243Sobrienstatic time_t stlast = 0; 15559243Sobrien#ifdef WHODEBUG 156167465Smpstatic void debugwholist (struct who *, struct who *); 15759243Sobrien#endif 158167465Smpstatic void print_who (struct who *); 15959243Sobrien 16059243Sobrien 16159243Sobrien#define ONLINE 01 16259243Sobrien#define OFFLINE 02 16359243Sobrien#define CHANGED 04 16459243Sobrien#define STMASK 07 16559243Sobrien#define ANNOUNCE 010 166167465Smp#define CLEARED 020 16759243Sobrien 16859243Sobrien/* 16959243Sobrien * Karl Kleinpaste, 26 Jan 1984. 17059243Sobrien * Initialize the dummy tty list for login watch. 17159243Sobrien * This dummy list eliminates boundary conditions 17259243Sobrien * when doing pointer-chase searches. 17359243Sobrien */ 17459243Sobrienvoid 175167465Smpinitwatch(void) 17659243Sobrien{ 17759243Sobrien whohead.who_next = &whotail; 17859243Sobrien whotail.who_prev = &whohead; 17959243Sobrien stlast = 1; 18059243Sobrien#ifdef WHODEBUG 18159243Sobrien debugwholist(NULL, NULL); 18259243Sobrien#endif /* WHODEBUG */ 18359243Sobrien} 18459243Sobrien 18559243Sobrienvoid 186167465Smpresetwatch(void) 18759243Sobrien{ 18859243Sobrien watch_period = 0; 18959243Sobrien stlast = 0; 19059243Sobrien} 19159243Sobrien 19259243Sobrien/* 19359243Sobrien * Karl Kleinpaste, 26 Jan 1984. 19459243Sobrien * Watch /etc/utmp for login/logout changes. 19559243Sobrien */ 19659243Sobrienvoid 197167465Smpwatch_login(int force) 19859243Sobrien{ 199145479Smp int comp = -1, alldone; 20059243Sobrien int firsttime = stlast == 1; 201232633Smp#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 202145479Smp struct utmp *uptr; 203145479Smp#else 204145479Smp int utmpfd; 205145479Smp#endif 20659243Sobrien struct utmp utmp; 20759243Sobrien struct who *wp, *wpnew; 20859243Sobrien struct varent *v; 20959243Sobrien Char **vp = NULL; 21059243Sobrien time_t t, interval = MAILINTVL; 21159243Sobrien struct stat sta; 212145479Smp#if defined(HAVE_STRUCT_UTMP_UT_HOST) && defined(_SEQUENT_) 21359243Sobrien char *host, *ut_find_host(); 21459243Sobrien#endif 21569408Sache#ifdef WINNT_NATIVE 21659243Sobrien static int ncbs_posted = 0; 21759243Sobrien USE(utmp); 21859243Sobrien USE(utmpfd); 21959243Sobrien USE(sta); 22059243Sobrien USE(wpnew); 22169408Sache#endif /* WINNT_NATIVE */ 22259243Sobrien 22359243Sobrien /* stop SIGINT, lest our login list get trashed. */ 224167465Smp pintr_disabled++; 225167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 22659243Sobrien 22759243Sobrien v = adrof(STRwatch); 228100616Smp if ((v == NULL || v->vec == NULL) && !force) { 229167465Smp cleanup_until(&pintr_disabled); 23059243Sobrien return; /* no names to watch */ 23159243Sobrien } 23259243Sobrien if (!force) { 23359243Sobrien trim(vp = v->vec); 23459243Sobrien if (blklen(vp) % 2) /* odd # args: 1st == # minutes. */ 23559243Sobrien interval = (number(*vp)) ? (getn(*vp++) * 60) : MAILINTVL; 23659243Sobrien } 23759243Sobrien else 23859243Sobrien interval = 0; 23959243Sobrien 24059243Sobrien (void) time(&t); 24169408Sache#ifdef WINNT_NATIVE 24259243Sobrien /* 24359243Sobrien * Since NCB_ASTATs take time, start em async at least 90 secs 24459243Sobrien * before we are due -amol 6/5/97 24559243Sobrien */ 24659243Sobrien if (!ncbs_posted) { 247167465Smp time_t tdiff = t - watch_period; 24859243Sobrien if (!watch_period || ((tdiff > 0) && (tdiff > (interval - 90)))) { 24959243Sobrien start_ncbs(vp); 25059243Sobrien ncbs_posted = 1; 25159243Sobrien } 25259243Sobrien } 25369408Sache#endif /* WINNT_NATIVE */ 25459243Sobrien if (t - watch_period < interval) { 255167465Smp cleanup_until(&pintr_disabled); 25659243Sobrien return; /* not long enough yet... */ 25759243Sobrien } 25859243Sobrien watch_period = t; 25969408Sache#ifdef WINNT_NATIVE 26059243Sobrien ncbs_posted = 0; 26169408Sache#else /* !WINNT_NATIVE */ 26259243Sobrien 26359243Sobrien /* 26459243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 26559243Sobrien * Don't open utmp all the time, stat it first... 26659243Sobrien */ 267145479Smp if (stat(TCSH_PATH_UTMP, &sta)) { 26861515Sobrien if (!force) 26961515Sobrien xprintf(CGETS(26, 1, 27061515Sobrien "cannot stat %s. Please \"unset watch\".\n"), 271145479Smp TCSH_PATH_UTMP); 272167465Smp cleanup_until(&pintr_disabled); 27359243Sobrien return; 27459243Sobrien } 27559243Sobrien if (stlast == sta.st_mtime) { 276167465Smp cleanup_until(&pintr_disabled); 27759243Sobrien return; 27859243Sobrien } 27959243Sobrien stlast = sta.st_mtime; 280232633Smp#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 281145479Smp setutent(); 282145479Smp#else 283167465Smp if ((utmpfd = xopen(TCSH_PATH_UTMP, O_RDONLY|O_LARGEFILE)) < 0) { 28461515Sobrien if (!force) 28561515Sobrien xprintf(CGETS(26, 2, 28661515Sobrien "%s cannot be opened. Please \"unset watch\".\n"), 287145479Smp TCSH_PATH_UTMP); 288167465Smp cleanup_until(&pintr_disabled); 28959243Sobrien return; 29059243Sobrien } 291167465Smp cleanup_push(&utmpfd, open_cleanup); 292145479Smp#endif 29359243Sobrien 29459243Sobrien /* 29559243Sobrien * xterm clears the entire utmp entry - mark everyone on the status list 29659243Sobrien * OFFLINE or we won't notice X "logouts" 29759243Sobrien */ 298167465Smp for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) 299167465Smp wp->who_status = OFFLINE | CLEARED; 30059243Sobrien 30159243Sobrien /* 30259243Sobrien * Read in the utmp file, sort the entries, and update existing entries or 30359243Sobrien * add new entries to the status list. 30459243Sobrien */ 305232633Smp#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 306145479Smp while ((uptr = getutent()) != NULL) { 307145479Smp memcpy(&utmp, uptr, sizeof (utmp)); 308145479Smp#else 309167465Smp while (xread(utmpfd, &utmp, sizeof utmp) == sizeof utmp) { 310145479Smp#endif 31159243Sobrien 31259243Sobrien# ifdef DEAD_PROCESS 31359243Sobrien# ifndef IRIS4D 31459243Sobrien if (utmp.ut_type != USER_PROCESS) 31559243Sobrien continue; 31659243Sobrien# else 31759243Sobrien /* Why is that? Cause the utmp file is always corrupted??? */ 31859243Sobrien if (utmp.ut_type != USER_PROCESS && utmp.ut_type != DEAD_PROCESS) 31959243Sobrien continue; 32059243Sobrien# endif /* IRIS4D */ 32159243Sobrien# endif /* DEAD_PROCESS */ 32259243Sobrien 32359243Sobrien if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0') 32459243Sobrien continue; /* completely void entry */ 32559243Sobrien# ifdef DEAD_PROCESS 32659243Sobrien if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0') 32759243Sobrien continue; 32859243Sobrien# endif /* DEAD_PROCESS */ 32959243Sobrien wp = whohead.who_next; 33059243Sobrien while (wp->who_next && (comp = strncmp(wp->who_tty, utmp.ut_line, UTLINLEN)) < 0) 33159243Sobrien wp = wp->who_next;/* find that tty! */ 33259243Sobrien 33359243Sobrien if (wp->who_next && comp == 0) { /* found the tty... */ 334167465Smp if (utmp.ut_time < wp->who_time) 335167465Smp continue; 33659243Sobrien# ifdef DEAD_PROCESS 33759243Sobrien if (utmp.ut_type == DEAD_PROCESS) { 33859243Sobrien wp->who_time = utmp.ut_time; 33959243Sobrien wp->who_status = OFFLINE; 34059243Sobrien } 34159243Sobrien else 34259243Sobrien# endif /* DEAD_PROCESS */ 34359243Sobrien if (utmp.ut_name[0] == '\0') { 34459243Sobrien wp->who_time = utmp.ut_time; 34559243Sobrien wp->who_status = OFFLINE; 34659243Sobrien } 34759243Sobrien else if (strncmp(utmp.ut_name, wp->who_name, UTNAMLEN) == 0) { 34859243Sobrien /* someone is logged in */ 34959243Sobrien wp->who_time = utmp.ut_time; 350167465Smp wp->who_status = ONLINE | ANNOUNCE; /* same guy */ 35159243Sobrien } 35259243Sobrien else { 35359243Sobrien (void) strncpy(wp->who_new, utmp.ut_name, UTNAMLEN); 354232633Smp# ifdef UTHOSTLEN 35559243Sobrien# ifdef _SEQUENT_ 35659243Sobrien host = ut_find_host(wp->who_tty); 35759243Sobrien if (host) 35859243Sobrien (void) strncpy(wp->who_host, host, UTHOSTLEN); 35959243Sobrien else 36059243Sobrien wp->who_host[0] = 0; 36159243Sobrien# else 36259243Sobrien (void) strncpy(wp->who_host, utmp.ut_host, UTHOSTLEN); 36359243Sobrien# endif 364232633Smp# endif /* UTHOSTLEN */ 36559243Sobrien wp->who_time = utmp.ut_time; 36659243Sobrien if (wp->who_name[0] == '\0') 36759243Sobrien wp->who_status = ONLINE; 36859243Sobrien else 36959243Sobrien wp->who_status = CHANGED; 37059243Sobrien } 37159243Sobrien } 37259243Sobrien else { /* new tty in utmp */ 373167465Smp wpnew = xcalloc(1, sizeof *wpnew); 37459243Sobrien (void) strncpy(wpnew->who_tty, utmp.ut_line, UTLINLEN); 375232633Smp# ifdef UTHOSTLEN 37659243Sobrien# ifdef _SEQUENT_ 37759243Sobrien host = ut_find_host(wpnew->who_tty); 37859243Sobrien if (host) 37959243Sobrien (void) strncpy(wpnew->who_host, host, UTHOSTLEN); 38059243Sobrien else 38159243Sobrien wpnew->who_host[0] = 0; 38259243Sobrien# else 38359243Sobrien (void) strncpy(wpnew->who_host, utmp.ut_host, UTHOSTLEN); 38459243Sobrien# endif 385232633Smp# endif /* UTHOSTLEN */ 38659243Sobrien wpnew->who_time = utmp.ut_time; 38759243Sobrien# ifdef DEAD_PROCESS 38859243Sobrien if (utmp.ut_type == DEAD_PROCESS) 38959243Sobrien wpnew->who_status = OFFLINE; 39059243Sobrien else 39159243Sobrien# endif /* DEAD_PROCESS */ 39259243Sobrien if (utmp.ut_name[0] == '\0') 39359243Sobrien wpnew->who_status = OFFLINE; 39459243Sobrien else { 39559243Sobrien (void) strncpy(wpnew->who_new, utmp.ut_name, UTNAMLEN); 39659243Sobrien wpnew->who_status = ONLINE; 39759243Sobrien } 39859243Sobrien# ifdef WHODEBUG 39959243Sobrien debugwholist(wpnew, wp); 40059243Sobrien# endif /* WHODEBUG */ 40159243Sobrien 40259243Sobrien wpnew->who_next = wp; /* link in a new 'who' */ 40359243Sobrien wpnew->who_prev = wp->who_prev; 40459243Sobrien wpnew->who_prev->who_next = wpnew; 40559243Sobrien wp->who_prev = wpnew; /* linked in now */ 40659243Sobrien } 40759243Sobrien } 408232633Smp#if defined(HAVE_GETUTENT) || defined(HAVE_GETUTXENT) 409145479Smp endutent(); 410145479Smp#else 411167465Smp cleanup_until(&utmpfd); 412145479Smp#endif 41369408Sache#endif /* !WINNT_NATIVE */ 41459243Sobrien 415167465Smp if (force || vp == NULL) { 416167465Smp cleanup_until(&pintr_disabled); 41759243Sobrien return; 418167465Smp } 41959243Sobrien 42059243Sobrien /* 42159243Sobrien * The state of all logins is now known, so we can search the user's list 42259243Sobrien * of watchables to print the interesting ones. 42359243Sobrien */ 42459243Sobrien for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' && 42559243Sobrien *(vp + 1) != NULL && **(vp + 1) != '\0'; 42659243Sobrien vp += 2) { /* args used in pairs... */ 42759243Sobrien 42859243Sobrien if (eq(*vp, STRany) && eq(*(vp + 1), STRany)) 42959243Sobrien alldone = 1; 43059243Sobrien 43159243Sobrien for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) { 43259243Sobrien if (wp->who_status & ANNOUNCE || 43359243Sobrien (!eq(STRany, vp[0]) && 43459243Sobrien !Gmatch(str2short(wp->who_name), vp[0]) && 43559243Sobrien !Gmatch(str2short(wp->who_new), vp[0])) || 43659243Sobrien (!Gmatch(str2short(wp->who_tty), vp[1]) && 43759243Sobrien !eq(STRany, vp[1]))) 43859243Sobrien continue; /* entry doesn't qualify */ 43959243Sobrien /* already printed or not right one to print */ 44059243Sobrien 44159243Sobrien 442167465Smp if (wp->who_status & CLEARED) {/* utmp entry was cleared */ 44359243Sobrien wp->who_time = watch_period; 444167465Smp wp->who_status &= ~CLEARED; 445167465Smp } 44659243Sobrien 44759243Sobrien if ((wp->who_status & OFFLINE) && 44859243Sobrien (wp->who_name[0] != '\0')) { 44959243Sobrien if (!firsttime) 45059243Sobrien print_who(wp); 45159243Sobrien wp->who_name[0] = '\0'; 45259243Sobrien wp->who_status |= ANNOUNCE; 45359243Sobrien continue; 45459243Sobrien } 45559243Sobrien if (wp->who_status & ONLINE) { 45659243Sobrien if (!firsttime) 45759243Sobrien print_who(wp); 45859243Sobrien (void) strcpy(wp->who_name, wp->who_new); 45959243Sobrien wp->who_status |= ANNOUNCE; 46059243Sobrien continue; 46159243Sobrien } 46259243Sobrien if (wp->who_status & CHANGED) { 46359243Sobrien if (!firsttime) 46459243Sobrien print_who(wp); 46559243Sobrien (void) strcpy(wp->who_name, wp->who_new); 46659243Sobrien wp->who_status |= ANNOUNCE; 46759243Sobrien continue; 46859243Sobrien } 46959243Sobrien } 47059243Sobrien } 471167465Smp cleanup_until(&pintr_disabled); 47259243Sobrien} 47359243Sobrien 47459243Sobrien#ifdef WHODEBUG 47559243Sobrienstatic void 476167465Smpdebugwholist(struct who *new, struct who *wp) 47759243Sobrien{ 478145479Smp struct who *a; 47959243Sobrien 48059243Sobrien a = whohead.who_next; 48159243Sobrien while (a->who_next != NULL) { 48259243Sobrien xprintf("%s/%s -> ", a->who_name, a->who_tty); 48359243Sobrien a = a->who_next; 48459243Sobrien } 48559243Sobrien xprintf("TAIL\n"); 48659243Sobrien if (a != &whotail) { 48759243Sobrien xprintf(CGETS(26, 3, "BUG! last element is not whotail!\n")); 48859243Sobrien abort(); 48959243Sobrien } 49059243Sobrien a = whotail.who_prev; 49159243Sobrien xprintf(CGETS(26, 4, "backward: ")); 49259243Sobrien while (a->who_prev != NULL) { 49359243Sobrien xprintf("%s/%s -> ", a->who_name, a->who_tty); 49459243Sobrien a = a->who_prev; 49559243Sobrien } 49659243Sobrien xprintf("HEAD\n"); 49759243Sobrien if (a != &whohead) { 49859243Sobrien xprintf(CGETS(26, 5, "BUG! first element is not whohead!\n")); 49959243Sobrien abort(); 50059243Sobrien } 50159243Sobrien if (new) 50259243Sobrien xprintf(CGETS(26, 6, "new: %s/%s\n"), new->who_name, new->who_tty); 50359243Sobrien if (wp) 50459243Sobrien xprintf("wp: %s/%s\n", wp->who_name, wp->who_tty); 50559243Sobrien} 50659243Sobrien#endif /* WHODEBUG */ 50759243Sobrien 50859243Sobrien 50959243Sobrienstatic void 510167465Smpprint_who(struct who *wp) 51159243Sobrien{ 512232633Smp#ifdef UTHOSTLEN 51359243Sobrien Char *cp = str2short(CGETS(26, 7, "%n has %a %l from %m.")); 51459243Sobrien#else 51559243Sobrien Char *cp = str2short(CGETS(26, 8, "%n has %a %l.")); 516232633Smp#endif /* UTHOSTLEN */ 51759243Sobrien struct varent *vp = adrof(STRwho); 518167465Smp Char *str; 51959243Sobrien 520100616Smp if (vp && vp->vec && vp->vec[0]) 52159243Sobrien cp = vp->vec[0]; 52259243Sobrien 523167465Smp str = tprintf(FMT_WHO, cp, NULL, wp->who_time, wp); 524167465Smp cleanup_push(str, xfree); 525167465Smp for (cp = str; *cp;) 526145479Smp xputwchar(*cp++); 527167465Smp cleanup_until(str); 52859243Sobrien xputchar('\n'); 52959243Sobrien} /* end print_who */ 53059243Sobrien 53159243Sobrien 532167465Smpchar * 533167465Smpwho_info(ptr_t ptr, int c) 534167465Smp{ 535167465Smp struct who *wp = ptr; 53659243Sobrien char *wbuf; 537232633Smp#ifdef UTHOSTLEN 538167465Smp char *wb; 53959243Sobrien int flg; 54059243Sobrien char *pb; 541232633Smp#endif /* UTHOSTLEN */ 54259243Sobrien 54359243Sobrien switch (c) { 54459243Sobrien case 'n': /* user name */ 54559243Sobrien switch (wp->who_status & STMASK) { 54659243Sobrien case ONLINE: 54759243Sobrien case CHANGED: 548167465Smp return strsave(wp->who_new); 54959243Sobrien case OFFLINE: 550167465Smp return strsave(wp->who_name); 55159243Sobrien default: 55259243Sobrien break; 55359243Sobrien } 55459243Sobrien break; 55559243Sobrien 55659243Sobrien case 'a': 55759243Sobrien switch (wp->who_status & STMASK) { 55859243Sobrien case ONLINE: 559167465Smp return strsave(CGETS(26, 9, "logged on")); 56059243Sobrien case OFFLINE: 561167465Smp return strsave(CGETS(26, 10, "logged off")); 56259243Sobrien case CHANGED: 563167465Smp return xasprintf(CGETS(26, 11, "replaced %s on"), wp->who_name); 56459243Sobrien default: 56559243Sobrien break; 56659243Sobrien } 56759243Sobrien break; 56859243Sobrien 569232633Smp#ifdef UTHOSTLEN 57059243Sobrien case 'm': 57159243Sobrien if (wp->who_host[0] == '\0') 572167465Smp return strsave(CGETS(26, 12, "local")); 57359243Sobrien else { 574167465Smp pb = wp->who_host; 575167465Smp wbuf = xmalloc(strlen(pb) + 1); 576167465Smp wb = wbuf; 57759243Sobrien /* the ':' stuff is for <host>:<display>.<screen> */ 578167465Smp for (flg = isdigit((unsigned char)*pb) ? '\0' : '.'; 579167465Smp *pb != '\0' && (*pb != flg || ((pb = strchr(pb, ':')) != 0)); 58059243Sobrien pb++) { 58159243Sobrien if (*pb == ':') 58259243Sobrien flg = '\0'; 583145479Smp *wb++ = isupper((unsigned char)*pb) ? 584145479Smp tolower((unsigned char)*pb) : *pb; 58559243Sobrien } 58659243Sobrien *wb = '\0'; 58759243Sobrien return wbuf; 58859243Sobrien } 58959243Sobrien 59059243Sobrien case 'M': 59159243Sobrien if (wp->who_host[0] == '\0') 592167465Smp return strsave(CGETS(26, 12, "local")); 59359243Sobrien else { 594167465Smp pb = wp->who_host; 595167465Smp wbuf = xmalloc(strlen(pb) + 1); 596167465Smp wb = wbuf; 597167465Smp for (; *pb != '\0'; pb++) 598145479Smp *wb++ = isupper((unsigned char)*pb) ? 599145479Smp tolower((unsigned char)*pb) : *pb; 60059243Sobrien *wb = '\0'; 60159243Sobrien return wbuf; 60259243Sobrien } 603232633Smp#endif /* UTHOSTLEN */ 60459243Sobrien 60559243Sobrien case 'l': 606167465Smp return strsave(wp->who_tty); 60759243Sobrien 60859243Sobrien default: 609167465Smp wbuf = xmalloc(3); 61059243Sobrien wbuf[0] = '%'; 61159243Sobrien wbuf[1] = (char) c; 61259243Sobrien wbuf[2] = '\0'; 61359243Sobrien return wbuf; 61459243Sobrien } 61559243Sobrien return NULL; 61659243Sobrien} 61759243Sobrien 61859243Sobrienvoid 61959243Sobrien/*ARGSUSED*/ 620167465Smpdolog(Char **v, struct command *c) 62159243Sobrien{ 62259243Sobrien struct who *wp; 62359243Sobrien struct varent *vp; 62459243Sobrien 62559243Sobrien USE(v); 62659243Sobrien USE(c); 62759243Sobrien vp = adrof(STRwatch); /* lint insists vp isn't used unless we */ 62859243Sobrien if (vp == NULL) /* unless we assign it outside the if */ 62959243Sobrien stderror(ERR_NOWATCH); 63059243Sobrien resetwatch(); 63159243Sobrien wp = whohead.who_next; 63259243Sobrien while (wp->who_next != NULL) { 63359243Sobrien wp->who_name[0] = '\0'; 63459243Sobrien wp = wp->who_next; 63559243Sobrien } 63659243Sobrien} 63759243Sobrien 638232633Smp# ifdef UTHOSTLEN 63969408Sachesize_t 640167465Smputmphostsize(void) 64169408Sache{ 64269408Sache return UTHOSTLEN; 64369408Sache} 64469408Sache 64559243Sobrienchar * 646167465Smputmphost(void) 64759243Sobrien{ 64859243Sobrien char *tty = short2str(varval(STRtty)); 64959243Sobrien struct who *wp; 65059243Sobrien char *host = NULL; 65159243Sobrien 65259243Sobrien watch_login(1); 65359243Sobrien 65459243Sobrien for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) { 65559243Sobrien if (strcmp(tty, wp->who_tty) == 0) 65659243Sobrien host = wp->who_host; 65759243Sobrien wp->who_name[0] = '\0'; 65859243Sobrien } 65959243Sobrien resetwatch(); 66059243Sobrien return host; 66159243Sobrien} 662232633Smp# endif /* UTHOSTLEN */ 66359243Sobrien 66469408Sache#ifdef WINNT_NATIVE 665232633Smpvoid 666232633Smpadd_to_who_list(char *name, char *mach_nm) 66759243Sobrien{ 66859243Sobrien 66959243Sobrien struct who *wp, *wpnew; 67059243Sobrien int comp = -1; 67159243Sobrien 67259243Sobrien wp = whohead.who_next; 67359243Sobrien while (wp->who_next && (comp = strncmp(wp->who_tty,mach_nm,UTLINLEN)) < 0) 67459243Sobrien wp = wp->who_next;/* find that tty! */ 67559243Sobrien 67659243Sobrien if (wp->who_next && comp == 0) { /* found the tty... */ 67759243Sobrien 67859243Sobrien if (*name == '\0') { 67959243Sobrien wp->who_time = 0; 68059243Sobrien wp->who_status = OFFLINE; 68159243Sobrien } 68259243Sobrien else if (strncmp(name, wp->who_name, UTNAMLEN) == 0) { 68359243Sobrien /* someone is logged in */ 68459243Sobrien wp->who_time = 0; 68559243Sobrien wp->who_status = 0; /* same guy */ 68659243Sobrien } 68759243Sobrien else { 68859243Sobrien (void) strncpy(wp->who_new, name, UTNAMLEN); 68959243Sobrien wp->who_time = 0; 69059243Sobrien if (wp->who_name[0] == '\0') 69159243Sobrien wp->who_status = ONLINE; 69259243Sobrien else 69359243Sobrien wp->who_status = CHANGED; 69459243Sobrien } 69559243Sobrien } 69659243Sobrien else { 697167465Smp wpnew = xcalloc(1, sizeof *wpnew); 69859243Sobrien (void) strncpy(wpnew->who_tty, mach_nm, UTLINLEN); 69959243Sobrien wpnew->who_time = 0; 70059243Sobrien if (*name == '\0') 70159243Sobrien wpnew->who_status = OFFLINE; 70259243Sobrien else { 70359243Sobrien (void) strncpy(wpnew->who_new, name, UTNAMLEN); 70459243Sobrien wpnew->who_status = ONLINE; 70559243Sobrien } 70659243Sobrien#ifdef WHODEBUG 70759243Sobrien debugwholist(wpnew, wp); 70859243Sobrien#endif /* WHODEBUG */ 70959243Sobrien 71059243Sobrien wpnew->who_next = wp; /* link in a new 'who' */ 71159243Sobrien wpnew->who_prev = wp->who_prev; 71259243Sobrien wpnew->who_prev->who_next = wpnew; 71359243Sobrien wp->who_prev = wpnew; /* linked in now */ 71459243Sobrien } 71559243Sobrien} 71669408Sache#endif /* WINNT_NATIVE */ 71759243Sobrien#endif /* HAVENOUTMP */ 718